Support PATA drive configuration option (ide:N[N...]).
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.
This commit is contained in:
parent
8fdb017001
commit
b3662b7bde
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue