root/sys/arch/hpcmips/stand/pbsdboot/tx39xx.c
/* $NetBSD: tx39xx.c,v 1.8 2009/03/14 21:04:09 dsl Exp $ */

/*-
 * Copyright (c) 1999 Shin Takemura, UCHIYAMA Yasushi
 * All rights reserved.
 *
 * This software is part of the PocketBSD.
 *
 * 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 the PocketBSD project
 *      and its contributors.
 * 4. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 <pbsdboot.h>

extern void tx39xx_asm_code();
extern void tx39xx_asm_code_end();
void tx39xx_asm_code_holder(void);

#define TX39_SYSADDR_CONFIG_REG         0x10C00000
#define TX39_SYSADDR_CONFIG_REG_LEN     0x00200000
typedef int tx_chipset_tag_t;
u_int32_t __tx39conf_addr;

u_int32_t
tx_conf_read(tx_chipset_tag_t t, int reg)
{
        return *((u_int32_t*)(__tx39conf_addr + reg));
}

void
tx_conf_write(tx_chipset_tag_t t, int reg, u_int32_t val)
{
        u_int32_t addr = (u_int32_t)t;
        *((u_int32_t*)(__tx39conf_addr +reg)) = val;
}

void
tx39xx_init(SYSTEM_INFO *info)
{
        /* 4KByte page */
        system_info.si_pagesize = info->dwPageSize;
        /* DRAM Bank 0/1 physical addr range */
        system_info.si_dramstart = 0x04000000;
        system_info.si_drammaxsize = 0x04000000;
        /* Pointer for bootstrap code */
        system_info.si_asmcode = (unsigned char*)tx39xx_asm_code;
        system_info.si_asmcodelen = (unsigned char*)tx39xx_asm_code_end
                - system_info.si_asmcode;
        system_info.si_boot = mips_boot;
        system_info.si_intrvec = 0x80;

        __tx39conf_addr = (int)VirtualAlloc(0, TX39_SYSADDR_CONFIG_REG_LEN, MEM_RESERVE, 
                            PAGE_NOACCESS);
        if (!VirtualCopy((LPVOID)__tx39conf_addr, 
                         (LPVOID)(TX39_SYSADDR_CONFIG_REG >> 8), 
                         TX39_SYSADDR_CONFIG_REG_LEN,
                         PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL)) {
                msg_printf(MSG_ERROR, whoami, 
                           TEXT("Mapping TX39 configuration register failed.\n"));
        }
}

void
tx39xx_asm_code_holder()
{
        /*
         * void
         * startprog(register struct map_s *map)
         * {
         *   register unsigned char *addr;
         *   register unsigned char *p;
         *   register int i;
         * 
         *   addr = map->base;
         *   i = 0;
         *   while (p = map->leaf[i / map->leafsize][i % map->leafsize]) {
         *     register unsigned char *pe = p + map->pagesize;
         *     while (p < pe) {
         *       *addr++ = *p++;
         *     }
         *     i++;
         *   }
         * }
         *
         *  register assignment:
         *    struct map_s *map         a0
         *    unsigned char *addr       a1
         *    unsigned char *p          a2
         *    unsigned char *pe         a3
         *    int i                     t0
         *
         * struct map_s {
         *   void *entry;       +0
         *   void *base;        +4
         *   int pagesize;      +8
         *   int leafsize;      +12
         *   int nleaves;       +16
         *   void *arg0;        +20
         *   void *arg1;  +24
         *   void *arg2;        +28
         *   void *arg3;        +32
         *   void **leaf[32];   +36
         *
         */
        __asm(
                ".set noreorder;"
                ".globl tx39xx_asm_code;"
                "tx39xx_asm_code:"
                "lui    a0, 0x0000;"
                "ori    a0, 0x0000;"

                /* Disable interrupt */
                "nop;"
                "mtc0   zero, $12;"
                "nop;"

                /*
                 * Copy kernel to bootaddr
                 */
                /* addr = map->base;    */
                "lw     a1, 4(a0);"

                /*   i = 0;             */
                "ori    t0, zero, 0;"

        " loop_start:"

                /*   while (p = map->leaf[i / map->leafsize][i % map->leafsize]) { */
                /*   t1 = map->leafsize */
                "lw     t1, 12(a0);"

                /*   lo = i / map->leafsize, hi = i % map->leafsize */
                "addu   t3, zero, t0;"
                "div    t3, t1;"
                /*   t2 = map->leaf */
                "addiu  t2, a0, 36;"
                /*   t3 = i / map->leafsize */
                "nop;"
                "mflo   t3;"
                /*   t2 = map->leaf[i / map->leafsize] */
                "sll    t3, t3, 2;"
                "addu   t2, t2, t3;"
                "lw     t2, 0(t2);"
                /*   t3 = i % map->leafsize */
                "mfhi   t3;"

                /*   p = map->leaf[i / map->leafsize][i % map->leafsize] */
                "sll    t3, t3, 2;"
                "addu   t2, t2, t3;"
                "lw     a2, 0(t2);"

                /*              if (p == NULL) {        */
                /*                      break;                  */
                /*              }                                       */
                "beq    a2, zero, loop_end;"
                "nop;"

                /*     register unsigned char *pe = p + map->pagesize; */
                "lw     t1, 8(a0);"
                "add    a3, a2, t1;"

                /*              while (p < pe) {                */
        "loop_start2:"
                "sltu        t1, a2, a3;"
                "beq         zero,t1,loop_end2;"
                "nop;"

                /*                      *addr++ = *p++; */
                "lw     t1, 0(a2);"
                "sw     t1, 0(a1);"
                "addi   a2, a2, 4;"
                "addi   a1, a1, 4;"

                /*              }       */
                "beq    zero, zero, loop_start2;"
                "nop;"

                /*     i++;     */
        "loop_end2:"
                "addi   t0, t0, 1;"
                "beq    zero, zero, loop_start;"
                "nop;"

        "loop_end:"
                "move t3, a0;"
        );

        /* 
         * Flush cache
         */
        __asm(
                "li     t1, 16384;"
                "li     t2, 8192;"

                /* Disable I-cache */
                "li     t5, ~0x00000020;"
                "mfc0   t6, $3;"
                "and    t5, t5, t6;"
                "nop;"
                "mtc0   t5, $3;"
                /* Stop streaming */
                "beq    zero, zero, 1f;"
                "nop;"
        "1:"
                /* Flush I-cache */
                "li     t0, 0x80000000;"
                "addu   t1, t0, t1;"
                "subu   t1, t1, 128;"
        "2:"
                ".word 0xbd000000;"
                ".word 0xbd000010;"
                ".word 0xbd000020;"
                ".word 0xbd000030;"
                ".word 0xbd000040;"
                ".word 0xbd000050;"
                ".word 0xbd000060;"
                ".word 0xbd000070;"
                "bne    t0, t1, 2b;"
                "addu   t0, t0, 128;"

                /* Flush D-cache */
                "li     t0, 0x80000000;"
                "addu   t1, t0, t2;"

        "3:"
                "lw     t2, 0(t0);"
                "bne    t1, t0, 3b;"
                "addiu  t0, t0, 4;"

                /* Enable I-cache */
                "nop;"
                "mtc0   t6, $3;"
                "nop;"
        );
        /* 
         *  Jump to kernel entry 
         */
        __asm(

                "lw     t0, 0(t3);"     /* entry addr */
                "lw     a1, 24(t3);"    /* arg1 */
                "lw     a2, 28(t3);"    /* arg2 */
                "lw     a3, 32(t3);"    /* arg3 */
                "lw     a0, 20(t3);"    /* arg0 */
                "jr     t0;"
                "nop;"

                ".globl tx39xx_asm_code_end;"
                "tx39xx_asm_code_end: nop;"
                ".set reorder;  "
        );
}