From 563db8c39c71ccdbdf68cbbcbffbd905fdb3ce4f Mon Sep 17 00:00:00 2001 From: John Hay Date: Mon, 6 Oct 2008 19:38:10 +0000 Subject: [PATCH] Add a boot loader for ixp425 based boards like the Gateworks Avila and ADI Pronghorn Metro with Redboot on them. --- sys/boot/arm/ixp425/Makefile.inc | 42 ++ sys/boot/arm/ixp425/boot2/Makefile | 75 +++ sys/boot/arm/ixp425/boot2/arm_init.S | 50 ++ sys/boot/arm/ixp425/boot2/boot2.c | 483 ++++++++++++++++ sys/boot/arm/ixp425/boot2/cf_ata.h | 62 ++ sys/boot/arm/ixp425/boot2/ixp425_board.c | 697 +++++++++++++++++++++++ sys/boot/arm/ixp425/boot2/lib.h | 64 +++ 7 files changed, 1473 insertions(+) create mode 100644 sys/boot/arm/ixp425/Makefile.inc create mode 100644 sys/boot/arm/ixp425/boot2/Makefile create mode 100644 sys/boot/arm/ixp425/boot2/arm_init.S create mode 100644 sys/boot/arm/ixp425/boot2/boot2.c create mode 100644 sys/boot/arm/ixp425/boot2/cf_ata.h create mode 100644 sys/boot/arm/ixp425/boot2/ixp425_board.c create mode 100644 sys/boot/arm/ixp425/boot2/lib.h diff --git a/sys/boot/arm/ixp425/Makefile.inc b/sys/boot/arm/ixp425/Makefile.inc new file mode 100644 index 000000000000..37af9c7b3747 --- /dev/null +++ b/sys/boot/arm/ixp425/Makefile.inc @@ -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 diff --git a/sys/boot/arm/ixp425/boot2/Makefile b/sys/boot/arm/ixp425/boot2/Makefile new file mode 100644 index 000000000000..944794341039 --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/Makefile @@ -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 + diff --git a/sys/boot/arm/ixp425/boot2/arm_init.S b/sys/boot/arm/ixp425/boot2/arm_init.S new file mode 100644 index 000000000000..088f23dbb123 --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/arm_init.S @@ -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 */ diff --git a/sys/boot/arm/ixp425/boot2/boot2.c b/sys/boot/arm/ixp425/boot2/boot2.c new file mode 100644 index 000000000000..d46c4ae31f3a --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/boot2.c @@ -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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include + +#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 diff --git a/sys/boot/arm/ixp425/boot2/cf_ata.h b/sys/boot/arm/ixp425/boot2/cf_ata.h new file mode 100644 index 000000000000..3c9e9e5facae --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/cf_ata.h @@ -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 */ diff --git a/sys/boot/arm/ixp425/boot2/ixp425_board.c b/sys/boot/arm/ixp425/boot2/ixp425_board.c new file mode 100644 index 000000000000..985c0a52c82d --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/ixp425_board.c @@ -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 +__FBSDID("$FreeBSD$"); +#include +#include + +#include + +#include "lib.h" +#include "cf_ata.h" + +#include +#include + +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; +} + diff --git a/sys/boot/arm/ixp425/boot2/lib.h b/sys/boot/arm/ixp425/boot2/lib.h new file mode 100644 index 000000000000..7b39028556a5 --- /dev/null +++ b/sys/boot/arm/ixp425/boot2/lib.h @@ -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 +#include + +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 */