root/sys/arch/shark/stand/ofwboot/Locore.c
/*      $NetBSD: Locore.c,v 1.4 2009/03/14 15:36:14 dsl Exp $   */

/*
 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
 * Copyright (C) 1995, 1996 TooLs GmbH.
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <lib/libsa/stand.h>

#include <machine/cpu.h>

#include <arm/armreg.h>

#include "cache.h"
#include "extern.h"
#include "openfirm.h"

static int (*openfirmware_entry)(void *);
static int openfirmware(void *);

void startup(int (*)(void *), char *, int);
static void setup(void);

void (*cache_syncI)(void);

void abort(void);
void abort(void)
{

        /* Stupid compiler (__dead). */
        for (;;)
                continue;
}

static int
openfirmware(void *arg)
{

        (*openfirmware_entry)(arg);
        return 0;
}

static vaddr_t
ofw_getcleaninfo(void)
{
        int cpu, vclean;

        if ((cpu = OF_finddevice("/cpu")) == -1)
                panic("no /cpu from OFW");

        if (OF_getprop(cpu, "d-cache-flush-address", &vclean,
                       sizeof(vclean)) != sizeof(vclean)) {
                printf("WARNING: no OFW d-cache-flush-address property\n");
                return (RELOC);
        }

        return (of_decode_int((unsigned char *)&vclean));
}

void
startup(int (*openfirm)(void *), char *arg, int argl)
{
        u_int cputype = cpufunc_id() & CPU_ID_CPU_MASK;

        openfirmware_entry = openfirm;
        setup();

        /*
         * Determine the CPU type, and set up the appropriate
         * I$ sync routine.
         */
        if (cputype == CPU_ID_SA110 || cputype == CPU_ID_SA1100 ||
            cputype == CPU_ID_SA1110) {
                extern vaddr_t sa110_cache_clean_addr;
                cache_syncI = sa110_cache_syncI;
                sa110_cache_clean_addr = ofw_getcleaninfo();
        } else {
                printf("WARNING: no I$ sync routine for CPU 0x%x\n",
                    cputype);
        }

        main();
        OF_exit();
}

int
of_decode_int(const u_char *p)
{
        unsigned int i = *p++ << 8;
        i = (i + *p++) << 8;
        i = (i + *p++) << 8;
        return (i + *p);
}

__dead void
OF_exit(void)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
        } args = {
                "exit",
                0,
                0
        };

        openfirmware(&args);
        for (;;);                       /* just in case */
}

int
OF_finddevice(const char *name)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                const char *device;
                int phandle;
        } args = {
                "finddevice",
                1,
                1,
        };      
        
        args.device = name;
        if (openfirmware(&args) == -1)
                return -1;
        return args.phandle;
}

int
OF_instance_to_package(int ihandle)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int ihandle;
                int phandle;
        } args = {
                "instance-to-package",
                1,
                1,
        };
        
        args.ihandle = ihandle;
        if (openfirmware(&args) == -1)
                return -1;
        return args.phandle;
}

int
OF_getprop(int handle, const char *prop, void *buf, int buflen)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int phandle;
                const char *prop;
                void *buf;
                int buflen;
                int size;
        } args = {
                "getprop",
                4,
                1,
        };
        
        args.phandle = handle;
        args.prop = prop;
        args.buf = buf;
        args.buflen = buflen;
        if (openfirmware(&args) == -1)
                return -1;
        return args.size;
}

#ifdef  __notyet__      /* Has a bug on FirePower */
int
OF_setprop(int handle, const char *prop, void *buf, int len)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int phandle;
                const char *prop;
                void *buf;
                int len;
                int size;
        } args = {
                "setprop",
                4,
                1,
        };
        
        args.phandle = handle;
        args.prop = prop;
        args.buf = buf;
        args.len = len;
        if (openfirmware(&args) == -1)
                return -1;
        return args.size;
}
#endif

int
OF_open(char *dname)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                char *dname;
                int handle;
        } args = {
                "open",
                1,
                1,
        };
        
#ifdef OFW_DEBUG
        printf("OF_open(%s) -> ", dname);
#endif
        args.dname = dname;
        if (openfirmware(&args) == -1 ||
            args.handle == 0) {
#ifdef OFW_DEBUG
                printf("lose\n");
#endif
                return -1;
        }
#ifdef OFW_DEBUG
        printf("%d\n", args.handle);
#endif
        return args.handle;
}

void
OF_close(int handle)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int handle;
        } args = {
                "close",
                1,
                0,
        };
        
#ifdef OFW_DEBUG
        printf("OF_close(%d)\n", handle);
#endif
        args.handle = handle;
        openfirmware(&args);
}

int
OF_write(int handle, void *addr, int len)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int ihandle;
                void *addr;
                int len;
                int actual;
        } args = {
                "write",
                3,
                1,
        };

#ifdef OFW_DEBUG
        if (len != 1)
                printf("OF_write(%d, %x, %x) -> ", handle, addr, len);
#endif
        args.ihandle = handle;
        args.addr = addr;
        args.len = len;
        if (openfirmware(&args) == -1) {
#ifdef OFW_DEBUG
                printf("lose\n");
#endif
                return -1;
        }
#ifdef OFW_DEBUG
        if (len != 1)
                printf("%x\n", args.actual);
#endif
        return args.actual;
}

int
OF_read(int handle, void *addr, int len)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int ihandle;
                void *addr;
                int len;
                int actual;
        } args = {
                "read",
                3,
                1,
        };

#ifdef OFW_DEBUG
        if (len != 1)
                printf("OF_read(%d, %x, %x) -> ", handle, addr, len);
#endif
        args.ihandle = handle;
        args.addr = addr;
        args.len = len;
        if (openfirmware(&args) == -1) {
#ifdef OFW_DEBUG
                printf("lose\n");
#endif
                return -1;
        }
#ifdef OFW_DEBUG
        if (len != 1)
                printf("%x\n", args.actual);
#endif
        return args.actual;
}

int
OF_seek(int handle, u_quad_t pos)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int handle;
                int poshi;
                int poslo;
                int status;
        } args = {
                "seek",
                3,
                1,
        };
        
#ifdef OFW_DEBUG
        printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos);
#endif
        args.handle = handle;
        args.poshi = (int)(pos >> 32);
        args.poslo = (int)pos;
        if (openfirmware(&args) == -1) {
#ifdef OFW_DEBUG
                printf("lose\n");
#endif
                return -1;
        }
#ifdef OFW_DEBUG
        printf("%d\n", args.status);
#endif
        return args.status;
}

void *
OF_claim(void *virt, u_int size, u_int align)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                void *virt;
                u_int size;
                u_int align;
                void *baseaddr;
        } args = {
                "claim",
                3,
                1,
        };

#ifdef OFW_DEBUG
        printf("OF_claim(%x, %x, %x) -> ", virt, size, align);
#endif
        args.virt = virt;
        args.size = size;
        args.align = align;
        if (openfirmware(&args) == -1) {
#ifdef OFW_DEBUG
                printf("lose\n");
#endif
                return (void *)-1;
        }
#ifdef OFW_DEBUG
        printf("%x\n", args.baseaddr);
#endif
        return args.baseaddr;
}

void
OF_release(void *virt, u_int size)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                void *virt;
                u_int size;
        } args = {
                "release",
                2,
                0,
        };
        
#ifdef OFW_DEBUG
        printf("OF_release(%x, %x)\n", virt, size);
#endif
        args.virt = virt;
        args.size = size;
        openfirmware(&args);
}

int
OF_milliseconds(void)
{
        static struct {
                const char *name;
                int nargs;
                int nreturns;
                int ms;
        } args = {
                "milliseconds",
                0,
                1,
        };
        
        openfirmware(&args);
        return args.ms;
}

void
OF_chain(void *virt, u_int size, void (*entry)(int (*)(void *), void *, u_int),
    void *arg, u_int len)
{
        struct {
                const char *name;
                int nargs;
                int nreturns;
                void *virt;
                u_int size;
                void (*entry)(int (*)(void *), void *, u_int);
                void *arg;
                u_int len;
        } args;

        args.name = "chain";
        args.nargs = 5;
        args.nreturns = 0;
        args.virt = virt;
        args.size = size;
        args.entry = entry;
        args.arg = arg;
        args.len = len;
#if 1
        openfirmware(&args);
#else
        entry(openfirmware_entry, arg, len);
#endif
}

static int stdin;
static int stdout;

static void
setup(void)
{
        u_char buf[sizeof(int)];
        int chosen;

        if ((chosen = OF_finddevice("/chosen")) == -1)
                OF_exit();

        if (OF_getprop(chosen, "stdin", buf, sizeof(buf)) != sizeof(buf))
                OF_exit();
        stdin = of_decode_int(buf);

        if (OF_getprop(chosen, "stdout", buf, sizeof(buf)) != sizeof(buf))
                OF_exit();
        stdout = of_decode_int(buf);
}

void
putchar(int c)
{
        char ch = c;

        if (c == '\n')
                putchar('\r');
        OF_write(stdout, &ch, 1);
}

int
getchar(void)
{
        unsigned char ch = '\0';
        int l;

        while ((l = OF_read(stdin, &ch, 1)) != 1)
                if (l != -2 && l != 0)
                        return -1;
        return ch;
}