mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-20 23:35:02 +00:00
Add a boot loader for ixp425 based boards like the Gateworks Avila
and ADI Pronghorn Metro with Redboot on them.
This commit is contained in:
parent
2c8995842c
commit
563db8c39c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=183651
42
sys/boot/arm/ixp425/Makefile.inc
Normal file
42
sys/boot/arm/ixp425/Makefile.inc
Normal file
|
@ -0,0 +1,42 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.if !target(__ixp425_boot_Makefile.inc__)
|
||||
.PATH: ${.CURDIR}/../../../../libkern ${.CURDIR}/../../../../libkern/arm
|
||||
|
||||
__ixp425_boot_Makefile.inc__:
|
||||
|
||||
# Both Avila and Pronghorn Metro are supported by ixp425
|
||||
BOOT_FLAVOR=ixp425
|
||||
|
||||
CFLAGS+=-Os -ffreestanding \
|
||||
-I${.CURDIR}/../../../.. \
|
||||
-I${.CURDIR}/../../../../arm \
|
||||
-DCPU_XSCALE_IXP425 \
|
||||
-Wall -Waggregate-return \
|
||||
-Werror \
|
||||
-Wnested-externs \
|
||||
-Wpointer-arith -Wshadow -Wwrite-strings \
|
||||
-Wmissing-prototypes \
|
||||
-Wmissing-declarations
|
||||
|
||||
# -Wstrict-prototypes
|
||||
|
||||
CFLAGS+=-DBOOT_${BOOT_FLAVOR:U}
|
||||
|
||||
LD ?= ld
|
||||
OBJCOPY ?= objcopy
|
||||
|
||||
.if defined(P)
|
||||
${P}: ${OBJS}
|
||||
${LD} ${LDFLAGS} -o ${.TARGET} ${OBJS}
|
||||
|
||||
CLEANFILES+= ${P}
|
||||
.endif
|
||||
|
||||
.if defined(WITH_TAG_LIST)
|
||||
MK_TAG_LIST:=yes
|
||||
.else
|
||||
MK_TAG_LIST:=no
|
||||
.endif
|
||||
|
||||
.endif
|
75
sys/boot/arm/ixp425/boot2/Makefile
Normal file
75
sys/boot/arm/ixp425/boot2/Makefile
Normal file
|
@ -0,0 +1,75 @@
|
|||
# $FreeBSD$
|
||||
|
||||
# We get a lot of the std lib functions from here.
|
||||
.PATH: ${.CURDIR}/../../at91/libat91
|
||||
|
||||
# Enable to get debug msgs
|
||||
#DEBUG=yes
|
||||
|
||||
# Hack to search through the kernel for ufs:ad0s1a and replace it with
|
||||
# the correct one for the active slice/partition.
|
||||
FIXUP_BOOT_DRV=yes
|
||||
|
||||
P=boot2
|
||||
FILES=${P}
|
||||
SRCS=arm_init.S boot2.c ${BOOT_FLAVOR:L}_board.c
|
||||
SRCS+=memchr.c memcmp.c memcpy.c memmem.c memset.c printf.c strcmp.c strcpy.c
|
||||
SRCS+=strlen.c ashldi3.c divsi3.S muldi3.c
|
||||
NO_MAN=
|
||||
|
||||
KERNPHYSADDR=0x180000
|
||||
KERNVIRTADDR=${KERNPHYSADDR}
|
||||
BOOT_STACK=0x200000-4
|
||||
M=${MACHINE_ARCH}
|
||||
LDFLAGS=-e ${KERNPHYSADDR} -EB -T ldscript.${M}
|
||||
OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
|
||||
S=${.CURDIR}/../../../..
|
||||
|
||||
CFLAGS+= \
|
||||
-DBOOT_STACK=${BOOT_STACK} \
|
||||
-I${.CURDIR}/../../../common \
|
||||
-I${.CURDIR}
|
||||
|
||||
.if defined(FIXUP_BOOT_DRV)
|
||||
CFLAGS+=-DFIXUP_BOOT_DRV
|
||||
.endif
|
||||
.if defined(DEBUG)
|
||||
CFLAGS+=-DDEBUG
|
||||
.endif
|
||||
|
||||
ldscript.$M: $S/conf/ldscript.$M
|
||||
cat $S/conf/ldscript.$M|sed s/KERNPHYSADDR/${KERNPHYSADDR}/g| \
|
||||
sed s/KERNVIRTADDR/${KERNVIRTADDR}/g | \
|
||||
sed s/" + SIZEOF_HEADERS"// > ldscript.$M
|
||||
|
||||
${P}: ldscript.$M
|
||||
|
||||
CLEANFILES+=ldscript.$M
|
||||
|
||||
memchr.c: $S/../lib/libc/string/memchr.c
|
||||
sed -e 's/string\.h/lib.h/' < $S/../lib/libc/string/memchr.c > \
|
||||
${.TARGET}
|
||||
|
||||
memmem.c: $S/../lib/libc/string/memmem.c
|
||||
sed -e 's/string\.h/lib.h/' < $S/../lib/libc/string/memmem.c > \
|
||||
${.TARGET}
|
||||
|
||||
CLEANFILES+=memchr.c memmem.c
|
||||
|
||||
ashldi3.o: $S/libkern/ashldi3.c
|
||||
cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
|
||||
|
||||
divsi3.o: $S/libkern/${M}/divsi3.S
|
||||
cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
|
||||
|
||||
muldi3.o: $S/libkern/${M}/muldi3.c
|
||||
cc -c ${CFLAGS} -D_KERNEL -o ${.TARGET} ${.IMPSRC}
|
||||
|
||||
inflate.c: $S/kern/inflate.c
|
||||
sed -e 's/extern void putstr (char/extern void putstr (const char/' < \
|
||||
$S/kern/inflate.c > ${.TARGET}
|
||||
|
||||
CLEANFILES+=inflate.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
50
sys/boot/arm/ixp425/boot2/arm_init.S
Normal file
50
sys/boot/arm/ixp425/boot2/arm_init.S
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 John Hay. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
start:
|
||||
|
||||
/* Initialise bss and sp */
|
||||
nop
|
||||
adr r1, .Lstart
|
||||
ldmia r1, {r1, r2, sp} /* Set initial stack and */
|
||||
sub r2, r2, r1 /* get zero init data */
|
||||
mov r3, #0
|
||||
.L1:
|
||||
str r3, [r1], #0x0004 /* get zero init data */
|
||||
subs r2, r2, #4
|
||||
bgt .L1
|
||||
|
||||
.extern main
|
||||
bl main
|
||||
/* main should not return. If it does, spin forever */
|
||||
infiniteLoop:
|
||||
b infiniteLoop
|
||||
|
||||
.Lstart:
|
||||
.word _edata
|
||||
.word _end
|
||||
.word BOOT_STACK
|
||||
/* End */
|
483
sys/boot/arm/ixp425/boot2/boot2.c
Normal file
483
sys/boot/arm/ixp425/boot2/boot2.c
Normal file
|
@ -0,0 +1,483 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 John Hay
|
||||
* Copyright (c) 1998 Robert Nordier
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are freely
|
||||
* permitted provided that the above copyright notice and this
|
||||
* paragraph and the following disclaimer are duplicated in all
|
||||
* such forms.
|
||||
*
|
||||
* This software is provided "AS IS" and without any express or
|
||||
* implied warranties, including, without limitation, the implied
|
||||
* warranties of merchantability and fitness for a particular
|
||||
* purpose.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/diskmbr.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/reboot.h>
|
||||
|
||||
#include <machine/elf.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#define RBX_ASKNAME 0x0 /* -a */
|
||||
#define RBX_SINGLE 0x1 /* -s */
|
||||
/* 0x2 is reserved for log2(RB_NOSYNC). */
|
||||
/* 0x3 is reserved for log2(RB_HALT). */
|
||||
/* 0x4 is reserved for log2(RB_INITNAME). */
|
||||
#define RBX_DFLTROOT 0x5 /* -r */
|
||||
/* #define RBX_KDB 0x6 -d */
|
||||
/* 0x7 is reserved for log2(RB_RDONLY). */
|
||||
/* 0x8 is reserved for log2(RB_DUMP). */
|
||||
/* 0x9 is reserved for log2(RB_MINIROOT). */
|
||||
#define RBX_CONFIG 0xa /* -c */
|
||||
#define RBX_VERBOSE 0xb /* -v */
|
||||
/* #define RBX_SERIAL 0xc -h */
|
||||
/* #define RBX_CDROM 0xd -C */
|
||||
/* 0xe is reserved for log2(RB_POWEROFF). */
|
||||
#define RBX_GDB 0xf /* -g */
|
||||
/* #define RBX_MUTE 0x10 -m */
|
||||
/* 0x11 is reserved for log2(RB_SELFTEST). */
|
||||
/* 0x12 is reserved for boot programs. */
|
||||
/* 0x13 is reserved for boot programs. */
|
||||
/* #define RBX_PAUSE 0x14 -p */
|
||||
/* #define RBX_QUIET 0x15 -q */
|
||||
#define RBX_NOINTR 0x1c /* -n */
|
||||
/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */
|
||||
/* #define RBX_DUAL 0x1d -D */
|
||||
/* 0x1f is reserved for log2(RB_BOOTINFO). */
|
||||
|
||||
/* pass: -a, -s, -r, -v, -g */
|
||||
#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \
|
||||
OPT_SET(RBX_DFLTROOT) | \
|
||||
OPT_SET(RBX_VERBOSE) | \
|
||||
OPT_SET(RBX_GDB))
|
||||
|
||||
#define PATH_CONFIG "/boot.config"
|
||||
#define PATH_KERNEL "/boot/kernel/kernel"
|
||||
|
||||
extern uint32_t _end;
|
||||
|
||||
#define NOPT 6
|
||||
|
||||
#define OPT_SET(opt) (1 << (opt))
|
||||
#define OPT_CHECK(opt) ((opts) & OPT_SET(opt))
|
||||
|
||||
static const char optstr[NOPT] = "agnrsv";
|
||||
static const unsigned char flags[NOPT] = {
|
||||
RBX_ASKNAME,
|
||||
RBX_GDB,
|
||||
RBX_NOINTR,
|
||||
RBX_DFLTROOT,
|
||||
RBX_SINGLE,
|
||||
RBX_VERBOSE
|
||||
};
|
||||
|
||||
static unsigned dsk_start;
|
||||
static char cmd[512];
|
||||
static char kname[1024];
|
||||
static uint32_t opts;
|
||||
static int dsk_meta;
|
||||
static int bootslice;
|
||||
static int bootpart;
|
||||
static int disk_layout;
|
||||
#define DL_UNKNOWN 0
|
||||
#define DL_RAW 1 /* Dangerously dedicated */
|
||||
#define DL_SLICE 2 /* Use only slices (DOS partitions) */
|
||||
#define DL_SLICEPART 3 /* Use slices and partitions */
|
||||
|
||||
static void load(void);
|
||||
static int parse(void);
|
||||
static int xfsread(ino_t, void *, size_t);
|
||||
static int dskread(void *, unsigned, unsigned);
|
||||
static int drvread(void *, unsigned, unsigned);
|
||||
#ifdef FIXUP_BOOT_DRV
|
||||
static void fixup_boot_drv(caddr_t, int, int, int);
|
||||
#endif
|
||||
|
||||
#include "ufsread.c"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
xfsread(ino_t inode, void *buf, size_t nbyte)
|
||||
{
|
||||
if ((size_t)fsread(inode, buf, nbyte) != nbyte)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
getstr(int c)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = cmd;
|
||||
if (c == 0)
|
||||
c = getc(10000);
|
||||
for (;;) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
break;
|
||||
case '\177':
|
||||
case '\b':
|
||||
if (s > cmd) {
|
||||
s--;
|
||||
printf("\b \b");
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
*s = 0;
|
||||
return;
|
||||
default:
|
||||
if (s - cmd < sizeof(cmd) - 1)
|
||||
*s++ = c;
|
||||
xputchar(c);
|
||||
}
|
||||
c = getc(10000);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const char *bt;
|
||||
int autoboot, c = 0;
|
||||
ino_t ino;
|
||||
|
||||
dmadat = (void *)(0x1c0000);
|
||||
p_memset((char *)dmadat, 0, 32 * 1024);
|
||||
bt = board_init();
|
||||
|
||||
printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 3);
|
||||
|
||||
autoboot = 1;
|
||||
|
||||
/* Process configuration file */
|
||||
if ((ino = lookup(PATH_CONFIG)))
|
||||
fsread(ino, cmd, sizeof(cmd));
|
||||
|
||||
if (*cmd) {
|
||||
if (parse())
|
||||
autoboot = 0;
|
||||
printf("%s: %s\n", PATH_CONFIG, cmd);
|
||||
/* Do not process this command twice */
|
||||
*cmd = 0;
|
||||
}
|
||||
|
||||
if (*kname == '\0')
|
||||
strcpy(kname, PATH_KERNEL);
|
||||
|
||||
/* Present the user with the boot2 prompt. */
|
||||
for (;;) {
|
||||
printf("\nDefault: %s\nboot: ", kname);
|
||||
if (!autoboot ||
|
||||
(OPT_CHECK(RBX_NOINTR) == 0 && (c = getc(2)) != 0))
|
||||
getstr(c);
|
||||
xputchar('\n');
|
||||
autoboot = 0;
|
||||
c = 0;
|
||||
DPRINTF("cmd is '%s'\n", cmd);
|
||||
if (parse())
|
||||
xputchar('\a');
|
||||
else
|
||||
load();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load(void)
|
||||
{
|
||||
Elf32_Ehdr eh;
|
||||
static Elf32_Phdr ep[2];
|
||||
caddr_t p;
|
||||
ino_t ino;
|
||||
uint32_t addr;
|
||||
int i, j;
|
||||
#ifdef FIXUP_BOOT_DRV
|
||||
caddr_t staddr;
|
||||
int klen;
|
||||
|
||||
staddr = (caddr_t)0xffffffff;
|
||||
klen = 0;
|
||||
#endif
|
||||
if (!(ino = lookup(kname))) {
|
||||
if (!ls)
|
||||
printf("No %s\n", kname);
|
||||
return;
|
||||
}
|
||||
DPRINTF("Found %s\n", kname);
|
||||
if (xfsread(ino, &eh, sizeof(eh)))
|
||||
return;
|
||||
if (!IS_ELF(eh)) {
|
||||
printf("Invalid %s\n", "format");
|
||||
return;
|
||||
}
|
||||
fs_off = eh.e_phoff;
|
||||
for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
|
||||
if (xfsread(ino, ep + j, sizeof(ep[0])))
|
||||
return;
|
||||
if (ep[j].p_type == PT_LOAD)
|
||||
j++;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
p = (caddr_t)(ep[i].p_paddr & 0x0fffffff);
|
||||
fs_off = ep[i].p_offset;
|
||||
#ifdef FIXUP_BOOT_DRV
|
||||
if (staddr == (caddr_t)0xffffffff)
|
||||
staddr = p;
|
||||
klen += ep[i].p_filesz;
|
||||
#endif
|
||||
if (xfsread(ino, p, ep[i].p_filesz))
|
||||
return;
|
||||
}
|
||||
addr = eh.e_entry & 0x0fffffff;
|
||||
DPRINTF("Entry point %x for %s\n", addr, kname);
|
||||
clr_board();
|
||||
#ifdef FIXUP_BOOT_DRV
|
||||
fixup_boot_drv(staddr, klen, bootslice, bootpart);
|
||||
#endif
|
||||
((void(*)(int))addr)(RB_BOOTINFO /* XXX | (opts & RBX_MASK) */);
|
||||
}
|
||||
|
||||
static int
|
||||
parse()
|
||||
{
|
||||
char *arg = cmd;
|
||||
char *ep, *p;
|
||||
int c, i;
|
||||
|
||||
while ((c = *arg++)) {
|
||||
if (c == ' ' || c == '\t' || c == '\n')
|
||||
continue;
|
||||
for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
|
||||
ep = p;
|
||||
if (*p)
|
||||
*p++ = 0;
|
||||
if (c == '-') {
|
||||
while ((c = *arg++)) {
|
||||
for (i = 0; c != optstr[i]; i++)
|
||||
if (i == NOPT - 1)
|
||||
return -1;
|
||||
opts ^= OPT_SET(flags[i]);
|
||||
}
|
||||
} else {
|
||||
arg--;
|
||||
/* look for ad0s1a:... | ad0s1:... */
|
||||
if (strlen(arg) > 6 && arg[0] == 'a' &&
|
||||
arg[1] == 'd' && arg[3] == 's' &&
|
||||
(arg[5] == ':' || arg[6] == ':')) {
|
||||
/* XXX Should also handle disk. */
|
||||
bootslice = arg[4] - '0';
|
||||
if (bootslice < 1 || bootslice > 4)
|
||||
return (-1);
|
||||
bootpart = 0;
|
||||
if (arg[5] != ':')
|
||||
bootpart = arg[5] - 'a';
|
||||
if (bootpart < 0 || bootpart > 7)
|
||||
return (-1);
|
||||
dsk_meta = 0;
|
||||
if (arg[5] == ':')
|
||||
arg += 6;
|
||||
else
|
||||
arg += 7;
|
||||
/* look for ad0a:... */
|
||||
} else if (strlen(arg) > 4 && arg[0] == 'a' &&
|
||||
arg[1] == 'd' && arg[2] == '0' && arg[4] == ':') {
|
||||
bootslice = 0;
|
||||
bootpart = arg[3] - 'a';
|
||||
if (bootpart < 0 || bootpart > 7)
|
||||
return (-1);
|
||||
dsk_meta = 0;
|
||||
arg += 5;
|
||||
}
|
||||
if ((i = ep - arg)) {
|
||||
if ((size_t)i >= sizeof(kname))
|
||||
return -1;
|
||||
memcpy(kname, arg, i + 1);
|
||||
}
|
||||
}
|
||||
arg = p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* dskread() will try to handle the disk layouts that are typically
|
||||
* encountered.
|
||||
* - raw or "Dangerously Dedicated" mode. No real slice table, just the
|
||||
* default one that is included with bsdlabel -B. Typically this is
|
||||
* used with ROOTDEVNAME=\"ufs:ad0a\".
|
||||
* - slice only. Only a slice table is installed with no bsd label or
|
||||
* bsd partition table. This is typically used with
|
||||
* ROOTDEVNAME=\"ufs:ad0s1\".
|
||||
* - slice + bsd label + partition table. This is typically done with
|
||||
* with fdisk + bsdlabel and is used with ROOTDEVNAME=\"ufs:ad0s1a\".
|
||||
*/
|
||||
static int
|
||||
dskread(void *buf, unsigned lba, unsigned nblk)
|
||||
{
|
||||
struct dos_partition *dp;
|
||||
struct disklabel *d;
|
||||
char *sec;
|
||||
int i;
|
||||
|
||||
if (!dsk_meta) {
|
||||
sec = dmadat->secbuf;
|
||||
dsk_start = 0;
|
||||
if (drvread(sec, DOSBBSECTOR, 1))
|
||||
return -1;
|
||||
dp = (void *)(sec + DOSPARTOFF);
|
||||
if (bootslice != 0) {
|
||||
i = bootslice - 1;
|
||||
if (dp[i].dp_typ != DOSPTYP_386BSD)
|
||||
return -1;
|
||||
} else {
|
||||
for (i = 0; i < NDOSPART; i++) {
|
||||
if ((dp[i].dp_typ == DOSPTYP_386BSD) &&
|
||||
(dp[i].dp_flag == 0x80))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != NDOSPART) {
|
||||
bootslice = i + 1;
|
||||
DPRINTF("Found an active fbsd slice. (%d)\n", i + 1);
|
||||
/*
|
||||
* Although dp_start is aligned within the disk
|
||||
* partition structure, DOSPARTOFF is 446, which
|
||||
* is only word (2) aligned, not longword (4)
|
||||
* aligned. Cope by using memcpy to fetch the
|
||||
* start of this partition.
|
||||
*/
|
||||
memcpy(&dsk_start, &dp[i].dp_start, 4);
|
||||
dsk_start = swap32(dsk_start);
|
||||
DPRINTF("dsk_start %x\n", dsk_start);
|
||||
if ((bootslice == 4) && (dsk_start == 0)) {
|
||||
disk_layout = DL_RAW;
|
||||
bootslice = 0;
|
||||
}
|
||||
}
|
||||
if (drvread(sec, dsk_start + LABELSECTOR, 1))
|
||||
return -1;
|
||||
d = (void *)(sec + LABELOFFSET);
|
||||
if ((d->d_magic == DISKMAGIC && d->d_magic2 == DISKMAGIC) ||
|
||||
(swap32(d->d_magic) == DISKMAGIC &&
|
||||
swap32(d->d_magic2) == DISKMAGIC)) {
|
||||
DPRINTF("p_size = %x\n",
|
||||
!d->d_partitions[bootpart].p_size);
|
||||
if (!d->d_partitions[bootpart].p_size) {
|
||||
printf("Invalid partition\n");
|
||||
return -1;
|
||||
}
|
||||
DPRINTF("p_offset %x, RAW %x\n",
|
||||
swap32(d->d_partitions[bootpart].p_offset),
|
||||
swap32(d->d_partitions[RAW_PART].p_offset));
|
||||
dsk_start += swap32(d->d_partitions[bootpart].p_offset);
|
||||
dsk_start -= swap32(d->d_partitions[RAW_PART].p_offset);
|
||||
if ((disk_layout == DL_UNKNOWN) && (bootslice == 0))
|
||||
disk_layout = DL_RAW;
|
||||
else if (disk_layout == DL_UNKNOWN)
|
||||
disk_layout = DL_SLICEPART;
|
||||
} else {
|
||||
disk_layout = DL_SLICE;
|
||||
DPRINTF("Invalid %s\n", "label");
|
||||
}
|
||||
DPRINTF("bootslice %d, bootpart %d, dsk_start %u\n", bootslice,
|
||||
bootpart, dsk_start);
|
||||
dsk_meta++;
|
||||
}
|
||||
return drvread(buf, dsk_start + lba, nblk);
|
||||
}
|
||||
|
||||
static int
|
||||
drvread(void *buf, unsigned lba, unsigned nblk)
|
||||
{
|
||||
static unsigned c = 0x2d5c7c2f;
|
||||
|
||||
printf("%c\b", c = c << 8 | c >> 24);
|
||||
return (avila_read((char *)buf, lba, nblk));
|
||||
}
|
||||
|
||||
#ifdef FIXUP_BOOT_DRV
|
||||
/*
|
||||
* fixup_boot_drv() will try to find the ROOTDEVNAME spec in the kernel
|
||||
* and change it to what was specified on the comandline or /boot.conf
|
||||
* file or to what was encountered on the disk. It will try to handle 3
|
||||
* different disk layouts, raw (dangerously dedicated), slice only and
|
||||
* slice + partition. It will look for the following strings in the
|
||||
* kernel, but if it is one of the first three, the string in the kernel
|
||||
* must use the correct form to match the actual disk layout:
|
||||
* - ufs:ad0a
|
||||
* - ufs:ad0s1
|
||||
* - ufs:ad0s1a
|
||||
* - ufs:ROOTDEVNAME
|
||||
* In the case of the first three strings, only the "a" at the end and
|
||||
* the "1" after the "s" will be modified, if they exist. The string
|
||||
* length will not be changed. In the case of the last string, the
|
||||
* whole string will be built up and nul, '\0' terminated.
|
||||
*/
|
||||
static void
|
||||
fixup_boot_drv(caddr_t addr, int klen, int bs, int bp)
|
||||
{
|
||||
const u_int8_t op[] = "ufs:ROOTDEVNAME";
|
||||
const u_int8_t op2[] = "ufs:ad0";
|
||||
u_int8_t *p, *ps;
|
||||
|
||||
DPRINTF("fixup_boot_drv: 0x%x, %d, slice %d, partition %d\n",
|
||||
(int)addr, klen, bs, bp);
|
||||
if (bs > 4)
|
||||
return;
|
||||
if (bp > 7)
|
||||
return;
|
||||
ps = memmem(addr, klen, op, sizeof(op));
|
||||
if (ps != NULL) {
|
||||
p = ps + 4; /* past ufs: */
|
||||
DPRINTF("Found it at 0x%x\n", (int)ps);
|
||||
p[0] = 'a'; p[1] = 'd'; p[2] = '0'; /* ad0 */
|
||||
p += 3;
|
||||
if (bs > 0) {
|
||||
/* append slice */
|
||||
*p++ = 's';
|
||||
*p++ = bs + '0';
|
||||
}
|
||||
if (disk_layout != DL_SLICE) {
|
||||
/* append partition */
|
||||
*p++ = bp + 'a';
|
||||
}
|
||||
*p = '\0';
|
||||
} else {
|
||||
ps = memmem(addr, klen, op2, sizeof(op2) - 1);
|
||||
if (ps != NULL) {
|
||||
p = ps + sizeof(op2) - 1;
|
||||
DPRINTF("Found it at 0x%x\n", (int)ps);
|
||||
if (*p == 's') {
|
||||
/* fix slice */
|
||||
p++;
|
||||
*p++ = bs + '0';
|
||||
}
|
||||
if (*p == 'a')
|
||||
*p = bp + 'a';
|
||||
}
|
||||
}
|
||||
if (ps == NULL) {
|
||||
printf("Could not locate \"%s\" to fix kernel boot device, "
|
||||
"check ROOTDEVNAME is set\n", op);
|
||||
return;
|
||||
}
|
||||
DPRINTF("Changed boot device to %s\n", ps);
|
||||
}
|
||||
#endif
|
62
sys/boot/arm/ixp425/boot2/cf_ata.h
Normal file
62
sys/boot/arm/ixp425/boot2/cf_ata.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 John Hay. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef ARM_BOOT_CF_ATA_H
|
||||
#define ARM_BOOT_CF_ATA_H
|
||||
|
||||
#define CF_DATA 0x00
|
||||
#define CF_ERROR 0x01
|
||||
#define CF_FEATURE 0x01
|
||||
#define CF_SECT_CNT 0x02
|
||||
#define CF_SECT_NUM 0x03
|
||||
#define CF_CYL_L 0x04
|
||||
#define CF_CYL_H 0x05
|
||||
#define CF_DRV_HEAD 0x06
|
||||
#define CF_D_MASTER 0x00
|
||||
#define CF_D_LBA 0x40
|
||||
#define CF_D_IBM 0xa0
|
||||
#define CF_STATUS 0x07
|
||||
#define CF_S_ERROR 0x01
|
||||
#define CF_S_INDEX 0x02
|
||||
#define CF_S_CORR 0x04
|
||||
#define CF_S_DRQ 0x08
|
||||
#define CF_S_DSC 0x10
|
||||
#define CF_S_DWF 0x20
|
||||
#define CF_S_READY 0x40
|
||||
#define CF_S_BUSY 0x80
|
||||
#define CF_COMMAND 0x07
|
||||
|
||||
/* This is according to the appnote, but Sam use 0x1e in avila_ata.c */
|
||||
#define CF_ALT_STATUS 0x16
|
||||
#define CF_ALT_DEV_CTR 0x16
|
||||
#define CF_ALT_DEV_CTR2 0x1e
|
||||
#define CF_A_IDS 0x02
|
||||
#define CF_A_RESET 0x04
|
||||
#define CF_A_4BIT 0x08
|
||||
|
||||
#define AVILA_IDE_GPIN 12
|
||||
|
||||
#endif /* !ARM_BOOT_CF_ATA_H */
|
697
sys/boot/arm/ixp425/boot2/ixp425_board.c
Normal file
697
sys/boot/arm/ixp425/boot2/ixp425_board.c
Normal file
|
@ -0,0 +1,697 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 John Hay. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/ata.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "cf_ata.h"
|
||||
|
||||
#include <arm/xscale/ixp425/ixp425reg.h>
|
||||
#include <dev/ic/ns16550.h>
|
||||
|
||||
static u_int8_t *ubase;
|
||||
|
||||
#define BOARD_AVILA 0
|
||||
#define BOARD_PRONGHORN 1
|
||||
static int board;
|
||||
|
||||
static u_int8_t uart_getreg(u_int8_t *, int);
|
||||
static void uart_setreg(u_int8_t *, int, u_int8_t);
|
||||
|
||||
static void cf_init(void);
|
||||
static void cf_clr(void);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
const char *
|
||||
board_init(void)
|
||||
{
|
||||
volatile u_int32_t *cs;
|
||||
const char *bt = NULL;
|
||||
|
||||
/*
|
||||
* Redboot only configure the chip selects that are needed, so
|
||||
* use that to figure out if it is an Avila or ADI board. The
|
||||
* Avila boards use CS2 and ADI does not.
|
||||
*/
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
|
||||
if (*cs != 0) {
|
||||
board = BOARD_AVILA;
|
||||
bt = "Avila";
|
||||
} else {
|
||||
board = BOARD_PRONGHORN;
|
||||
bt = "Pronghorn Metro";
|
||||
}
|
||||
|
||||
/* Config the serial port. RedBoot should do the rest. */
|
||||
if (board == BOARD_AVILA)
|
||||
ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
|
||||
else
|
||||
ubase = (u_int8_t *)(IXP425_UART1_HWBASE);
|
||||
|
||||
cf_init();
|
||||
|
||||
return bt;
|
||||
}
|
||||
|
||||
/*
|
||||
* This should be called just before starting the kernel. This is so
|
||||
* that one can undo incompatable hardware settings.
|
||||
*/
|
||||
void
|
||||
clr_board(void)
|
||||
{
|
||||
cf_clr();
|
||||
}
|
||||
|
||||
/*
|
||||
* General support functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* DELAY should delay for the number of microseconds.
|
||||
* The idea is that the inner loop should take 1us, so val is the
|
||||
* number of usecs to delay.
|
||||
*/
|
||||
void
|
||||
DELAY(int val)
|
||||
{
|
||||
volatile int sub;
|
||||
volatile int subsub;
|
||||
|
||||
sub = val;
|
||||
while(sub) {
|
||||
subsub = 3;
|
||||
while(subsub)
|
||||
subsub--;
|
||||
sub--;
|
||||
}
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
swap32(u_int32_t a)
|
||||
{
|
||||
return (((a & 0xff) << 24) | ((a & 0xff00) << 8) |
|
||||
((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24));
|
||||
}
|
||||
|
||||
u_int16_t
|
||||
swap16(u_int16_t val)
|
||||
{
|
||||
return (val << 8) | (val >> 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* uart related funcs
|
||||
*/
|
||||
static u_int8_t
|
||||
uart_getreg(u_int8_t *bas, int off)
|
||||
{
|
||||
return *((volatile u_int32_t *)(bas + (off << 2))) & 0xff;
|
||||
}
|
||||
|
||||
static void
|
||||
uart_setreg(u_int8_t *bas, int off, u_int8_t val)
|
||||
{
|
||||
*((volatile u_int32_t *)(bas + (off << 2))) = (u_int32_t)val;
|
||||
}
|
||||
|
||||
int
|
||||
getc(int seconds)
|
||||
{
|
||||
int c, delay, limit;
|
||||
|
||||
c = 0;
|
||||
delay = 10000;
|
||||
limit = seconds * 1000000/10000;
|
||||
while ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == 0 && --limit)
|
||||
DELAY(delay);
|
||||
|
||||
if ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == LSR_RXRDY)
|
||||
c = uart_getreg(ubase, REG_DATA);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
putchar(int ch)
|
||||
{
|
||||
int delay, limit;
|
||||
|
||||
delay = 500;
|
||||
limit = 20;
|
||||
while ((uart_getreg(ubase, REG_LSR) & LSR_THRE) == 0 && --limit)
|
||||
DELAY(delay);
|
||||
uart_setreg(ubase, REG_DATA, ch);
|
||||
|
||||
limit = 40;
|
||||
while ((uart_getreg(ubase, REG_LSR) & LSR_TEMT) == 0 && --limit)
|
||||
DELAY(delay);
|
||||
}
|
||||
|
||||
void
|
||||
xputchar(int ch)
|
||||
{
|
||||
if (ch == '\n')
|
||||
putchar('\r');
|
||||
putchar(ch);
|
||||
}
|
||||
|
||||
void
|
||||
putstr(const char *str)
|
||||
{
|
||||
while(*str)
|
||||
xputchar(*str++);
|
||||
}
|
||||
|
||||
void
|
||||
puthex8(u_int8_t ch)
|
||||
{
|
||||
const char *hex = "0123456789abcdef";
|
||||
|
||||
putchar(hex[ch >> 4]);
|
||||
putchar(hex[ch & 0xf]);
|
||||
}
|
||||
|
||||
void
|
||||
puthexlist(const u_int8_t *str, int length)
|
||||
{
|
||||
while(length) {
|
||||
puthex8(*str);
|
||||
putchar(' ');
|
||||
str++;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* CF/IDE functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct {
|
||||
u_int64_t dsize;
|
||||
u_int64_t total_secs;
|
||||
u_int8_t heads;
|
||||
u_int8_t sectors;
|
||||
u_int32_t cylinders;
|
||||
|
||||
u_int8_t *cs1;
|
||||
u_int8_t *cs2;
|
||||
|
||||
u_int32_t use_lba;
|
||||
u_int32_t use_stream8;
|
||||
u_int32_t debug;
|
||||
|
||||
u_int8_t status;
|
||||
u_int8_t error;
|
||||
} dskinf;
|
||||
|
||||
static void cfenable16(void);
|
||||
static void cfdisable16(void);
|
||||
static u_int8_t cfread8(u_int32_t off);
|
||||
static u_int16_t cfread16(u_int32_t off);
|
||||
static void cfreadstream8(void *buf, int length);
|
||||
static void cfreadstream16(void *buf, int length);
|
||||
static void cfwrite8(u_int32_t off, u_int8_t val);
|
||||
static u_int8_t cfaltread8(u_int32_t off);
|
||||
static void cfaltwrite8(u_int32_t off, u_int8_t val);
|
||||
static int cfwait(u_int8_t mask);
|
||||
static int cfaltwait(u_int8_t mask);
|
||||
static int cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head,
|
||||
u_int32_t sector, u_int32_t count, u_int32_t feature);
|
||||
static void cfreset(void);
|
||||
#ifdef DEBUG
|
||||
static int cfgetparams(void);
|
||||
#endif
|
||||
static void cfprintregs(void);
|
||||
|
||||
static void
|
||||
cf_init(void)
|
||||
{
|
||||
u_int8_t status;
|
||||
#ifdef DEBUG
|
||||
int rval;
|
||||
#endif
|
||||
volatile u_int32_t *cs;
|
||||
|
||||
/* Setup the CF select timeing. Maybe already done by RedBoot? */
|
||||
if (board == BOARD_AVILA) {
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
|
||||
*cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
DPRINTF("t1 %x, ", *cs);
|
||||
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
|
||||
*cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
DPRINTF("t2 %x\n", *cs);
|
||||
|
||||
dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS1_HWBASE;
|
||||
dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS2_HWBASE;
|
||||
} else {
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
|
||||
*cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
DPRINTF("t1 %x, ", *cs);
|
||||
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET);
|
||||
*cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
|
||||
DPRINTF("t2 %x\n", *cs);
|
||||
|
||||
dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS3_HWBASE;
|
||||
dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS4_HWBASE;
|
||||
}
|
||||
DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2);
|
||||
|
||||
dskinf.use_stream8 = 0;
|
||||
dskinf.use_lba = 0;
|
||||
dskinf.debug = 1;
|
||||
|
||||
/* Detect if there is a disk. */
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1000);
|
||||
status = cfread8(CF_STATUS);
|
||||
if (status != 0x50)
|
||||
printf("cf-ata0 %x\n", (u_int32_t)status);
|
||||
if (status == 0xff) {
|
||||
printf("cf_ata0: No disk!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cfreset();
|
||||
|
||||
if (dskinf.use_stream8) {
|
||||
DPRINTF("setting %d bit mode.\n", 8);
|
||||
cfwrite8(CF_FEATURE, 0x01); /* Enable 8 bit transfers */
|
||||
cfwrite8(CF_COMMAND, ATA_SETFEATURES);
|
||||
cfaltwait(CF_S_READY);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
rval = cfgetparams();
|
||||
if (rval)
|
||||
return;
|
||||
#endif
|
||||
dskinf.use_lba = 1;
|
||||
dskinf.debug = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cf_clr(void)
|
||||
{
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
cfaltwait(CF_S_READY);
|
||||
cfwrite8(CF_FEATURE, 0x81); /* Enable 8 bit transfers */
|
||||
cfwrite8(CF_COMMAND, ATA_SETFEATURES);
|
||||
cfaltwait(CF_S_READY);
|
||||
}
|
||||
|
||||
static void
|
||||
cfenable16(void)
|
||||
{
|
||||
u_int32_t val;
|
||||
volatile u_int32_t *cs;
|
||||
|
||||
if (board == BOARD_AVILA)
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
|
||||
else
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
|
||||
val = *cs;
|
||||
*cs = val & (~1);
|
||||
DPRINTF("cfenable16: cs1 timing reg %x\n", *cs);
|
||||
}
|
||||
|
||||
static void
|
||||
cfdisable16(void)
|
||||
{
|
||||
u_int32_t val;
|
||||
volatile u_int32_t *cs;
|
||||
|
||||
if (board == BOARD_AVILA)
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
|
||||
else
|
||||
cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
|
||||
val = *cs;
|
||||
*cs = val | 1;
|
||||
}
|
||||
|
||||
static u_int8_t
|
||||
cfread8(u_int32_t off)
|
||||
{
|
||||
volatile u_int8_t *vp;
|
||||
|
||||
vp = (volatile u_int8_t *)(dskinf.cs1 + off);
|
||||
return *vp;
|
||||
}
|
||||
|
||||
static void
|
||||
cfreadstream8(void *buf, int length)
|
||||
{
|
||||
u_int8_t *lbuf;
|
||||
u_int8_t tmp;
|
||||
|
||||
lbuf = buf;
|
||||
while (length) {
|
||||
tmp = cfread8(CF_DATA);
|
||||
*lbuf = tmp;
|
||||
#ifdef DEBUG
|
||||
if (dskinf.debug && (length > (512 - 32))) {
|
||||
if ((length % 16) == 0)
|
||||
xputchar('\n');
|
||||
puthex8(tmp);
|
||||
putchar(' ');
|
||||
}
|
||||
#endif
|
||||
lbuf++;
|
||||
length--;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (dskinf.debug)
|
||||
xputchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
static u_int16_t
|
||||
cfread16(u_int32_t off)
|
||||
{
|
||||
volatile u_int16_t *vp;
|
||||
|
||||
vp = (volatile u_int16_t *)(dskinf.cs1 + off);
|
||||
return swap16(*vp);
|
||||
}
|
||||
|
||||
static void
|
||||
cfreadstream16(void *buf, int length)
|
||||
{
|
||||
u_int16_t *lbuf;
|
||||
|
||||
length = length / 2;
|
||||
cfenable16();
|
||||
lbuf = buf;
|
||||
while (length--) {
|
||||
*lbuf = cfread16(CF_DATA);
|
||||
lbuf++;
|
||||
}
|
||||
cfdisable16();
|
||||
}
|
||||
|
||||
static void
|
||||
cfwrite8(u_int32_t off, u_int8_t val)
|
||||
{
|
||||
volatile u_int8_t *vp;
|
||||
|
||||
vp = (volatile u_int8_t *)(dskinf.cs1 + off);
|
||||
*vp = val;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
cfwrite16(u_int32_t off, u_int16_t val)
|
||||
{
|
||||
volatile u_int16_t *vp;
|
||||
|
||||
vp = (volatile u_int16_t *)(dskinf.cs1 + off);
|
||||
*vp = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u_int8_t
|
||||
cfaltread8(u_int32_t off)
|
||||
{
|
||||
volatile u_int8_t *vp;
|
||||
|
||||
off &= 0x0f;
|
||||
vp = (volatile u_int8_t *)(dskinf.cs2 + off);
|
||||
return *vp;
|
||||
}
|
||||
|
||||
static void
|
||||
cfaltwrite8(u_int32_t off, u_int8_t val)
|
||||
{
|
||||
volatile u_int8_t *vp;
|
||||
|
||||
/*
|
||||
* This is documented in the Intel appnote 302456.
|
||||
*/
|
||||
off &= 0x0f;
|
||||
vp = (volatile u_int8_t *)(dskinf.cs2 + off);
|
||||
*vp = val;
|
||||
}
|
||||
|
||||
static int
|
||||
cfwait(u_int8_t mask)
|
||||
{
|
||||
u_int8_t status;
|
||||
u_int32_t tout;
|
||||
|
||||
tout = 0;
|
||||
while (tout <= 5000000) {
|
||||
status = cfread8(CF_STATUS);
|
||||
if (status == 0xff) {
|
||||
printf("cfwait: master: no status, reselecting\n");
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1);
|
||||
status = cfread8(CF_STATUS);
|
||||
}
|
||||
if (status == 0xff)
|
||||
return -1;
|
||||
dskinf.status = status;
|
||||
if (!(status & CF_S_BUSY)) {
|
||||
if (status & CF_S_ERROR)
|
||||
dskinf.error = cfread8(CF_ERROR);
|
||||
if ((status & mask) == mask) {
|
||||
DPRINTF("cfwait: tout %u\n", tout);
|
||||
return (status & CF_S_ERROR);
|
||||
}
|
||||
}
|
||||
if (tout > 1000) {
|
||||
tout += 1000;
|
||||
DELAY(1000);
|
||||
} else {
|
||||
tout += 10;
|
||||
DELAY(10);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
cfaltwait(u_int8_t mask)
|
||||
{
|
||||
u_int8_t status;
|
||||
u_int32_t tout;
|
||||
|
||||
tout = 0;
|
||||
while (tout <= 5000000) {
|
||||
status = cfaltread8(CF_ALT_STATUS);
|
||||
if (status == 0xff) {
|
||||
printf("cfaltwait: master: no status, reselectin\n");
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1);
|
||||
status = cfread8(CF_STATUS);
|
||||
}
|
||||
if (status == 0xff)
|
||||
return -1;
|
||||
dskinf.status = status;
|
||||
if (!(status & CF_S_BUSY)) {
|
||||
if (status & CF_S_ERROR)
|
||||
dskinf.error = cfread8(CF_ERROR);
|
||||
if ((status & mask) == mask) {
|
||||
DPRINTF("cfaltwait: tout %u\n", tout);
|
||||
return (status & CF_S_ERROR);
|
||||
}
|
||||
}
|
||||
if (tout > 1000) {
|
||||
tout += 1000;
|
||||
DELAY(1000);
|
||||
} else {
|
||||
tout += 10;
|
||||
DELAY(10);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head, u_int32_t sector,
|
||||
u_int32_t count, u_int32_t feature)
|
||||
{
|
||||
if (cfwait(0) < 0) {
|
||||
printf("cfcmd: timeout\n");
|
||||
return -1;
|
||||
}
|
||||
cfwrite8(CF_FEATURE, feature);
|
||||
cfwrite8(CF_CYL_L, cylinder);
|
||||
cfwrite8(CF_CYL_H, cylinder >> 8);
|
||||
if (dskinf.use_lba)
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM | CF_D_LBA | head);
|
||||
else
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM | head);
|
||||
cfwrite8(CF_SECT_NUM, sector);
|
||||
cfwrite8(CF_SECT_CNT, count);
|
||||
cfwrite8(CF_COMMAND, cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cfreset(void)
|
||||
{
|
||||
u_int8_t status;
|
||||
u_int32_t tout;
|
||||
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1);
|
||||
#ifdef DEBUG
|
||||
cfprintregs();
|
||||
#endif
|
||||
cfread8(CF_STATUS);
|
||||
cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS | CF_A_RESET);
|
||||
DELAY(10000);
|
||||
cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS);
|
||||
DELAY(10000);
|
||||
cfread8(CF_ERROR);
|
||||
DELAY(3000);
|
||||
|
||||
for (tout = 0; tout < 310000; tout++) {
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1);
|
||||
status = cfread8(CF_STATUS);
|
||||
if (!(status & CF_S_BUSY))
|
||||
break;
|
||||
DELAY(100);
|
||||
}
|
||||
DELAY(1);
|
||||
if (status & CF_S_BUSY) {
|
||||
cfprintregs();
|
||||
printf("cfreset: Status stayed busy after reset.\n");
|
||||
}
|
||||
DPRINTF("cfreset: finished, tout %u\n", tout);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int
|
||||
cfgetparams(void)
|
||||
{
|
||||
u_int8_t *buf;
|
||||
|
||||
buf = (u_int8_t *)(0x170000);
|
||||
p_memset((char *)buf, 0, 1024);
|
||||
/* Select the drive. */
|
||||
cfwrite8(CF_DRV_HEAD, CF_D_IBM);
|
||||
DELAY(1);
|
||||
cfcmd(ATA_ATA_IDENTIFY, 0, 0, 0, 0, 0);
|
||||
if (cfaltwait(CF_S_READY | CF_S_DSC | CF_S_DRQ)) {
|
||||
printf("cfgetparams: ATA_IDENTIFY failed.\n");
|
||||
return -1;
|
||||
}
|
||||
if (dskinf.use_stream8)
|
||||
cfreadstream8(buf, 512);
|
||||
else
|
||||
cfreadstream16(buf, 512);
|
||||
if (dskinf.debug)
|
||||
cfprintregs();
|
||||
#if 0
|
||||
memcpy(&dskinf.ata_params, buf, sizeof(struct ata_params));
|
||||
dskinf.cylinders = dskinf.ata_params.cylinders;
|
||||
dskinf.heads = dskinf.ata_params.heads;
|
||||
dskinf.sectors = dskinf.ata_params.sectors;
|
||||
printf("dsk0: sec %x, hd %x, cyl %x, stat %x, err %x\n",
|
||||
(u_int32_t)dskinf.ata_params.sectors,
|
||||
(u_int32_t)dskinf.ata_params.heads,
|
||||
(u_int32_t)dskinf.ata_params.cylinders,
|
||||
(u_int32_t)dskinf.status,
|
||||
(u_int32_t)dskinf.error);
|
||||
#endif
|
||||
dskinf.status = cfread8(CF_STATUS);
|
||||
if (dskinf.debug)
|
||||
printf("cfgetparams: ata_params * %x, stat %x\n",
|
||||
(u_int32_t)buf, (u_int32_t)dskinf.status);
|
||||
return 0;
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
static void
|
||||
cfprintregs(void)
|
||||
{
|
||||
u_int8_t rv;
|
||||
|
||||
putstr("cfprintregs: regs error ");
|
||||
rv = cfread8(CF_ERROR);
|
||||
puthex8(rv);
|
||||
putstr(", count ");
|
||||
rv = cfread8(CF_SECT_CNT);
|
||||
puthex8(rv);
|
||||
putstr(", sect ");
|
||||
rv = cfread8(CF_SECT_NUM);
|
||||
puthex8(rv);
|
||||
putstr(", cyl low ");
|
||||
rv = cfread8(CF_CYL_L);
|
||||
puthex8(rv);
|
||||
putstr(", cyl high ");
|
||||
rv = cfread8(CF_CYL_H);
|
||||
puthex8(rv);
|
||||
putstr(", drv head ");
|
||||
rv = cfread8(CF_DRV_HEAD);
|
||||
puthex8(rv);
|
||||
putstr(", status ");
|
||||
rv = cfread8(CF_STATUS);
|
||||
puthex8(rv);
|
||||
putstr("\n");
|
||||
}
|
||||
|
||||
int
|
||||
avila_read(char *dest, unsigned source, unsigned length)
|
||||
{
|
||||
if (dskinf.use_lba == 0 && source == 0)
|
||||
source++;
|
||||
if (dskinf.debug)
|
||||
printf("avila_read: 0x%x, sect %d num secs %d\n",
|
||||
(u_int32_t)dest, source, length);
|
||||
while (length) {
|
||||
cfwait(CF_S_READY);
|
||||
/* cmd, cyl, head, sect, count, feature */
|
||||
cfcmd(ATA_READ, (source >> 8) & 0xffff, source >> 24,
|
||||
source & 0xff, 1, 0);
|
||||
|
||||
cfwait(CF_S_READY | CF_S_DRQ | CF_S_DSC);
|
||||
if (dskinf.use_stream8)
|
||||
cfreadstream8(dest, 512);
|
||||
else
|
||||
cfreadstream16(dest, 512);
|
||||
length--;
|
||||
source++;
|
||||
dest += 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
64
sys/boot/arm/ixp425/boot2/lib.h
Normal file
64
sys/boot/arm/ixp425/boot2/lib.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 John Hay. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef ARM_BOOT_LIB_H
|
||||
#define ARM_BOOT_LIB_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
void DELAY(int);
|
||||
|
||||
int getc(int);
|
||||
void putchar(int);
|
||||
void xputchar(int);
|
||||
void putstr(const char *);
|
||||
void puthex8(u_int8_t);
|
||||
void puthexlist(const u_int8_t *, int);
|
||||
void printf(const char *fmt,...);
|
||||
|
||||
void bzero(void *, size_t);
|
||||
char *strcpy(char *to, const char *from);
|
||||
int strcmp(const char *to, const char *from);
|
||||
int p_strlen(const char *);
|
||||
int p_memcmp(const char *, const char *, unsigned);
|
||||
void *memchr(const void *, int, size_t);
|
||||
void memcpy(void *to, const void *from, unsigned size);
|
||||
void *memmem(const void *, size_t, const void *, size_t);
|
||||
void p_memset(char *buffer, char value, int size);
|
||||
|
||||
#define strlen p_strlen
|
||||
#define memcmp p_memcmp
|
||||
#define memset p_memset
|
||||
|
||||
u_int16_t swap16(u_int16_t);
|
||||
u_int32_t swap32(u_int32_t);
|
||||
|
||||
const char *board_init(void);
|
||||
void clr_board(void);
|
||||
int avila_read(char*, unsigned, unsigned);
|
||||
|
||||
#endif /* !ARM_BOOT_LIB_H */
|
Loading…
Reference in a new issue