diff --git a/sys/arch/sandpoint/stand/altboot/dsk.c b/sys/arch/sandpoint/stand/altboot/dsk.c index b71046358f28..284b80d9d8e6 100644 --- a/sys/arch/sandpoint/stand/altboot/dsk.c +++ b/sys/arch/sandpoint/stand/altboot/dsk.c @@ -1,4 +1,4 @@ -/* $NetBSD: dsk.c,v 1.12 2012/01/19 07:38:05 nisimura Exp $ */ +/* $NetBSD: dsk.c,v 1.13 2012/01/22 13:08:16 phx Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -179,34 +179,46 @@ int perform_atareset(struct dkdev_ata *l, int n) { struct dvata_chan *chan = &l->chan[n]; +// int retries; - CSR_WRITE_1(chan->ctl, ATA_DREQ); - delay(10); - CSR_WRITE_1(chan->ctl, ATA_SRST|ATA_DREQ); - delay(10); - CSR_WRITE_1(chan->ctl, ATA_DREQ); +// for (retries = 0; retries < 10; retries++) { + CSR_WRITE_1(chan->ctl, ATA_DREQ); + delay(10); + CSR_WRITE_1(chan->ctl, ATA_SRST|ATA_DREQ); + delay(10); + CSR_WRITE_1(chan->ctl, ATA_DREQ); +// if (spinwait_unbusy(l, n, 1000/*250*/, NULL) != 0) +// return 1; +// delay(1000 * 1000); +// } + return spinwait_unbusy(l, n, 1000/*250*/, NULL); +} - return spinwait_unbusy(l, n, 250, NULL); +/* clear idle and standby timers to spin up the drive */ +void +wakeup_drive(struct dkdev_ata *l, int n) +{ + struct dvata_chan *chan = &l->chan[n]; + + CSR_WRITE_1(chan->cmd + _NSECT, 0); + CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_IDLE); + (void)CSR_READ_1(chan->alt); + delay(10 * 1000); + CSR_WRITE_1(chan->cmd + _NSECT, 0); + CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_STANDBY); + (void)CSR_READ_1(chan->alt); + delay(10 * 1000); } int -satapresense(struct dkdev_ata *l, int n) +atachkpwr(struct dkdev_ata *l, int n) { -#define VND_CH(n) (((n&02)<<8)+((n&01)<<7)) -#define VND_SC(n) (0x100+VND_CH(n)) -#define VND_SS(n) (0x104+VND_CH(n)) + struct dvata_chan *chan = &l->chan[n]; - uint32_t sc = l->bar[5] + VND_SC(n); - uint32_t ss = l->bar[5] + VND_SS(n); - unsigned val; - - val = (00 << 4) | (03 << 8); /* any speed, no pwrmgt */ - CSR_WRITE_4(sc, val | 01); /* perform init */ - delay(50 * 1000); - CSR_WRITE_4(sc, val); - delay(50 * 1000); - val = CSR_READ_4(ss); /* has completed */ - return ((val & 03) == 03); /* active drive found */ + CSR_WRITE_1(chan->cmd + _CMD, ATA_CMD_CHKPWR); + (void)CSR_READ_1(chan->alt); + delay(10 * 1000); + return CSR_READ_1(chan->cmd + _NSECT); } static int diff --git a/sys/arch/sandpoint/stand/altboot/globals.h b/sys/arch/sandpoint/stand/altboot/globals.h index dc76683b9e6b..76040f800caa 100644 --- a/sys/arch/sandpoint/stand/altboot/globals.h +++ b/sys/arch/sandpoint/stand/altboot/globals.h @@ -1,4 +1,4 @@ -/* $NetBSD: globals.h,v 1.15 2012/01/07 19:57:49 phx Exp $ */ +/* $NetBSD: globals.h,v 1.16 2012/01/22 13:08:16 phx Exp $ */ #ifdef DEBUG #define DPRINTF(x) printf x @@ -42,6 +42,7 @@ extern uint32_t cpuclock, busclock; /* board specific support code */ struct brdprop *brd_lookup(int); +int get_drive_config(int); int tstchar(void); #ifdef DEBUG void sat_write(char *, int); @@ -177,16 +178,23 @@ DSK_DECL(siisata); #define ATA_STS_DRDY 0x40 #define ATA_STS_ERR 0x01 /* command */ +#define ATA_CMD_CHKPWR 0xe5 #define ATA_CMD_IDENT 0xec +#define ATA_CMD_IDLE 0xe3 #define ATA_CMD_READ 0x20 #define ATA_CMD_READ_EXT 0x24 #define ATA_CMD_SETF 0xef +#define ATA_CMD_STANDBY 0xe2 /* device */ #define ATA_DEV_LBA 0xe0 #define ATA_DEV_OBS 0x90 /* control */ #define ATA_DREQ 0x08 #define ATA_SRST 0x04 +/* power state */ +#define ATA_PWR_ACTIVE 0xff +#define ATA_PWR_IDLE 0x80 +#define ATA_PWR_STANDBY 0x00 #define ATA_XFER 0x03 #define XFER_PIO4 0x0c @@ -229,4 +237,5 @@ struct disk { int spinwait_unbusy(struct dkdev_ata *, int, int, const char **); int perform_atareset(struct dkdev_ata *, int); -int satapresense(struct dkdev_ata *, int); +void wakeup_drive(struct dkdev_ata *, int); +int atachkpwr(struct dkdev_ata *, int); diff --git a/sys/arch/sandpoint/stand/altboot/main.c b/sys/arch/sandpoint/stand/altboot/main.c index 626bd701817e..02a8d0fc546c 100644 --- a/sys/arch/sandpoint/stand/altboot/main.c +++ b/sys/arch/sandpoint/stand/altboot/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.16 2012/01/01 18:25:03 phx Exp $ */ +/* $NetBSD: main.c,v 1.17 2012/01/22 13:08:16 phx Exp $ */ /*- * Copyright (c) 2007 The NetBSD Foundation, Inc. @@ -58,6 +58,9 @@ static const struct bootarg { { "altboot", -1 } }; +/* default PATA drive configuration is "10": single master on first channel */ +static char *drive_config = "10"; + void *bootinfo; /* low memory reserved to pass bootinfo structures */ int bi_size; /* BOOTINFO_MAXSIZE */ char *bi_next; @@ -176,6 +179,44 @@ main(int argc, char *argv[], char *bootargs_start, char *bootargs_end) pcisetup(); pcifixup(); + /* + * When argc is too big then it is probably a pointer, which could + * indicate that we were launched as a Linux kernel module using + * "bootm". + */ + if (argc > MAX_ARGS) { + if (argv != NULL) { + /* + * initrd image was loaded: + * check if it contains a valid altboot command line + */ + char *p = (char *)argv; + + if (strncmp(p, "altboot:", 8) == 0) { + *p = 0; + for (p = p + 8; *p >= ' '; p++); + argc = parse_cmdline(new_argv, MAX_ARGS, + ((char *)argv) + 8, p); + argv = new_argv; + } else + argc = 0; /* boot default */ + } else { + /* parse standard Linux bootargs */ + argc = parse_cmdline(new_argv, MAX_ARGS, + bootargs_start, bootargs_end); + argv = new_argv; + } + } + + /* look for a PATA drive configuration string under the arguments */ + for (n = 1; n < argc; n++) { + if (strncmp(argv[n], "ide:", 4) == 0 && + argv[n][4] >= '0' && argv[n][4] <= '2') { + drive_config = &argv[n][4]; + break; + } + } + /* intialize a disk driver */ for (n = 0; n < nata; n++) if (dskdv_init(&lata[n]) != 0) @@ -190,26 +231,6 @@ main(int argc, char *argv[], char *bootargs_start, char *bootargs_end) if (n >= nnif) printf("no NET device driver was found\n"); - /* - * When argc is too big then it is probably a pointer, which could - * indicate that we were launched as a Linux kernel module using - * "bootm". - */ - if (argc > MAX_ARGS) { - if (argv != NULL) { - /* - * initrd image was loaded: assume extremely - * restricted firmware and boot default - */ - argc = 0; - } else { - /* parse standard Linux bootargs */ - argc = parse_cmdline(new_argv, MAX_ARGS, - bootargs_start, bootargs_end); - argv = new_argv; - } - } - /* wait 2s for user to enter interactive mode */ for (n = 200; n >= 0; n--) { if (n % 100 == 0) @@ -239,6 +260,9 @@ main(int argc, char *argv[], char *bootargs_start, char *bootargs_end) /* get boot options and determine bootname */ for (n = 1; n < argc; n++) { + if (strncmp(argv[n], "ide:", 4) == 0) + continue; /* ignore drive configuration argument */ + for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) { if (strncasecmp(argv[n], bootargs[i].name, strlen(bootargs[i].name)) == 0) { @@ -491,52 +515,24 @@ module_open(struct boot_module *bm) return fd; } -#if 0 -static const char *cmdln[] = { - "console=ttyS0,115200 root=/dev/sda1 rw initrd=0x200000,2M", - "console=ttyS0,115200 root=/dev/nfs ip=dhcp" -}; - -void -mkatagparams(unsigned addr, char *kcmd) +/* + * Return the drive configuration for the requested channel 'ch'. + * Channel 2 is the first channel of the next IDE controller. + * 0: for no drive present on channel + * 1: for master drive present on channel, no slave + * 2: for master and slave drive present + */ +int +get_drive_config(int ch) { - struct tag { - unsigned siz; - unsigned tag; - unsigned val[1]; - }; - struct tag *p; -#define ATAG_CORE 0x54410001 -#define ATAG_MEM 0x54410002 -#define ATAG_INITRD 0x54410005 -#define ATAG_CMDLINE 0x54410009 -#define ATAG_NONE 0x00000000 -#define tagnext(p) (struct tag *)((unsigned *)(p) + (p)->siz) -#define tagsize(n) (2 + (n)) - - p = (struct tag *)addr; - p->tag = ATAG_CORE; - p->siz = tagsize(3); - p->val[0] = 0; /* flags */ - p->val[1] = 0; /* pagesize */ - p->val[2] = 0; /* rootdev */ - p = tagnext(p); - p->tag = ATAG_MEM; - p->siz = tagsize(2); - p->val[0] = 64 * 1024 * 1024; - p->val[1] = 0; /* start */ - p = tagnext(p); - if (kcmd != NULL) { - p = tagnext(p); - p->tag = ATAG_CMDLINE; - p->siz = tagsize((strlen(kcmd) + 1 + 3) >> 2); - strcpy((void *)p->val, kcmd); + if (drive_config != NULL) { + if (strlen(drive_config) <= ch) + return 0; /* an unspecified channel is unused */ + if (drive_config[ch] >= '0' && drive_config[ch] <= '2') + return drive_config[ch] - '0'; } - p = tagnext(p); - p->tag = ATAG_NONE; - p->siz = 0; + return -1; } -#endif void * allocaligned(size_t size, size_t align) diff --git a/sys/arch/sandpoint/stand/altboot/pciide.c b/sys/arch/sandpoint/stand/altboot/pciide.c index 629d0f0e8882..e61e720e4040 100644 --- a/sys/arch/sandpoint/stand/altboot/pciide.c +++ b/sys/arch/sandpoint/stand/altboot/pciide.c @@ -1,4 +1,4 @@ -/* $NetBSD: pciide.c,v 1.11 2011/11/13 00:06:54 phx Exp $ */ +/* $NetBSD: pciide.c,v 1.12 2012/01/22 13:08:16 phx Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -82,7 +82,8 @@ pciide_match(unsigned tag, void *data) void * pciide_init(unsigned tag, void *data) { - int native, n; + static int cntrl = 0; + int native, n, retries; unsigned val; struct dkdev_ata *l; @@ -128,16 +129,37 @@ pciide_init(unsigned tag, void *data) } for (n = 0; n < 2; n++) { - if (myops->presense && (*myops->presense)(l, n) == 0) - l->presense[n] = 0; /* found not exist */ - else + if (myops->presense != NULL && (*myops->presense)(l, n) == 0) { + DPRINTF(("channel %d not present\n", n)); + l->presense[n] = 0; + continue; + } else if (get_drive_config(cntrl * 2 + n) == 0) { + DPRINTF(("channel %d disabled by config\n", n)); + l->presense[n] = 0; + continue; + } + + if (atachkpwr(l, n) != ATA_PWR_ACTIVE) { + /* drive is probably sleeping, wake it up */ + for (retries = 0; retries < 10; retries++) { + wakeup_drive(l, n); + DPRINTF(("channel %d spinning up...\n", n)); + delay(1000 * 1000); + l->presense[n] = perform_atareset(l, n); + if (atachkpwr(l, n) == ATA_PWR_ACTIVE) + break; + } + } else { /* check to see whether soft reset works */ + DPRINTF(("channel %d active\n", n)); l->presense[n] = perform_atareset(l, n); + } if (l->presense[n]) printf("channel %d present\n", n); } + cntrl++; /* increment controller number for next call */ return l; } diff --git a/sys/arch/sandpoint/stand/altboot/siisata.c b/sys/arch/sandpoint/stand/altboot/siisata.c index 160b650844ee..c9f00f3fbe9a 100644 --- a/sys/arch/sandpoint/stand/altboot/siisata.c +++ b/sys/arch/sandpoint/stand/altboot/siisata.c @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.4 2011/05/30 19:48:12 phx Exp $ */ +/* $NetBSD: siisata.c,v 1.5 2012/01/22 13:08:17 phx Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -35,6 +35,14 @@ #include "globals.h" +/* + * - no vtophys() translation, vaddr_t == paddr_t. + */ +#define CSR_READ_4(r) in32rb(r) +#define CSR_WRITE_4(r,v) out32rb(r,v) + +static int satapresense(struct dkdev_ata *, int); + static uint32_t pciiobase = PCI_XIOBASE; int @@ -56,7 +64,7 @@ void * siisata_init(unsigned tag, void *data) { unsigned idreg; - int n, nchan, retries; + int n, nchan, retries/*waitforspinup*/; struct dkdev_ata *l; l = alloc(sizeof(struct dkdev_ata)); @@ -99,22 +107,57 @@ siisata_init(unsigned tag, void *data) pcicfgwrite(tag, 0x80, 0x00); pcicfgwrite(tag, 0x84, 0x00); - for (n = 0, retries = 0; n < nchan; n++) { - l->presense[n] = 0; - - if (satapresense(l, n)) { - /* drive present, now check whether soft reset works */ - while (retries++ < 10) { - if (perform_atareset(l, n)) { - DPRINTF(("port %d device present\n", n)); - l->presense[n] = 1; + for (n = 0; n < nchan; n++) { + l->presense[n] = satapresense(l, n); + if (l->presense[n] == 0) { + DPRINTF(("port %d not present\n", n)); + l->presense[n] = 0; + continue; + } + if (atachkpwr(l, n) != ATA_PWR_ACTIVE) { + /* drive is probably sleeping, wake it up */ + for (retries = 0; retries < 10; retries++) { + wakeup_drive(l, n); + DPRINTF(("port %d spinning up...\n", n)); + delay(1000 * 1000); + l->presense[n] = perform_atareset(l, n); + if (atachkpwr(l, n) == ATA_PWR_ACTIVE) break; - } - /* give the drive another second to spin up */ - if (retries < 10) - delay(1000 * 1000); + } + } else { + /* check to see whether soft reset works */ + DPRINTF(("port %d active\n", n)); + for (retries = 0; retries < 10; retries++) { + l->presense[n] = perform_atareset(l, n); + if (l->presense[n] != 0) + break; + DPRINTF(("port %d cold-starting...\n", n)); + delay(1000 * 1000); } } + + if (l->presense[n]) + printf("port %d present\n", n); } return l; } + +static int +satapresense(struct dkdev_ata *l, int n) +{ +#define VND_CH(n) (((n&02)<<8)+((n&01)<<7)) +#define VND_SC(n) (0x100+VND_CH(n)) +#define VND_SS(n) (0x104+VND_CH(n)) + + uint32_t sc = l->bar[5] + VND_SC(n); + uint32_t ss = l->bar[5] + VND_SS(n); + unsigned val; + + val = (00 << 4) | (03 << 8); /* any speed, no pwrmgt */ + CSR_WRITE_4(sc, val | 01); /* perform init */ + delay(50 * 1000); + CSR_WRITE_4(sc, val); + delay(50 * 1000); + val = CSR_READ_4(ss); /* has completed */ + return ((val & 03) == 03); /* active drive found */ +} diff --git a/sys/arch/sandpoint/stand/altboot/version b/sys/arch/sandpoint/stand/altboot/version index 4330e866bee2..25b48d2c8865 100644 --- a/sys/arch/sandpoint/stand/altboot/version +++ b/sys/arch/sandpoint/stand/altboot/version @@ -11,3 +11,6 @@ mode, default boot path is now wd0:netbsd in multiuser mode 1.8: Iomega support, IT821x & VT6410 IDE support, fixed interrupt issue, exception handler and sat-controller test mode (DEBUG) +1.9: Support PATA drive configuration option. Wait until drives are + ready after cold-start. Wake up drives from standby mode. + A default command line can be saved to flash as initrd image.