root/sys/arch/hpcmips/stand/lcboot/start.S
/* $NetBSD: start.S,v 1.4 2021/08/09 19:57:57 andvar Exp $ */

/*
 * Copyright (c) 2003 Naoto Shimazaki.
 * 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 NAOTO SHIMAZAKI 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 NAOTO 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.
 */

/*
 * NOTE:
 * This code assumes some trick described below:
 *
 *      - Located at 0x80000000 by linker
 *      - Placed at 0xbfc00000 (by ROM writer)
 *      - Executed at 0xbfc00000 by CPU
 *
 * So,
 *
 *      - You cannot use 'j' and 'jal'.  Instead, you must use 'b'.
 *      - If you want to jump to absolute address, you must load
 *        the target address to a register and jump to it with
 *        'jr' or 'jalr'.
 *      - You never be able to write any memory before
 *        the bus configuration completed.
 *
 */

#include <sys/cdefs.h>
#include <sys/errno.h>
#include <sys/syscall.h>

#include <machine/param.h>
#include <mips/asm.h>
#include <mips/cpuregs.h>
#include <mips/trap.h>

#include "extern.h"

        .text
        .set    noreorder
        .align  2

/*
 * macro ROMICE  - support for Kyoto-micro's PARTNER-ETII ROM-ICE
 *
 * PARTNER-ETII by Kyoto-microcomputer is a ROM based emulater.
 * This ICE initializes by itself the very early configurations of
 * the target CPU.  This macro skips that configurations.
 */
#ifndef ROMICE
        /*
         * exception vector table
         */
        .org    0x0000
reset_vector:
        b       start           /* MUST relative jump */
        nop

        .org    0x0200
tlb_vector:
        b       start
        nop

        .org    0x0280
xtlb_vector:
        b       start
        nop
        
        .org    0x0380
exception_vector:
        b       start
        nop
#endif

        .org    0x1000
        .globl  start
start:
#ifndef ROMICE
        /*
         * setup CP0 CONFIG
         * EP = 0, AD = 0, K0 = 2
         */
        li      t1, 0x00125482
        mtc0    t1, $16
        
        /*
         * setup CP0 STATUS
         * CU0 = 0, RE = 0, DS:BEV = 0, IM = 0, KX = SX = UX = 0,
         * KSU = 0, IE = 0, others = untouch
         */
        mfc0    t1, $12
        li      t2, 0x00770006
        and     t1, t1, t2
        li      t2, 0x00400000
        or      t1, t1, t2
        mtc0    t1, $12

        mtc0    zero, $18               /* CP0 Watch Lo */
        mtc0    zero, $11               /* CP0 compare */

        /*
         * setup LED
         */
        li      t0, 0xab000248          /* LEDCNTREG */
        li      t1, 0x0001
        sh      t1, (t0)

        /*
         * reset HALTimer
         */
        li      t0, 0xab0000a2
        li      t1, 0x0004
        sh      t1, (t0)

        /*
         * initialize VR4181 bus controller
         */

        /*
         * setup BCUCNTREG1
         * ROMs = 10 (64Mbit), ROMWEN0 = 1, Rtype = 01 (flash)
         * RSTOUT = 1 (inactive)
         */
        li      t0, 0xaa000000          /* BCUCNTREG1 */
        li      t1, 0x8013
        sh      t1, (t0)

        /*
         * setup BCURFCNTREG
         * BRF = refresh cycle x 1/TClock
         *     = 30.52usec x 32.768MHz
         *     = 0x3e8  (1000 TClock)
         */
        li      t0, 0xaa000010          /* BCURFCNTREG */
        li      t1, 0x03e8
        sh      t1, (t0)

        /*
         * setup BCUSPEEDREG
         * WPROM = 111 = 8.5TClock = 259ns
         * WROMA = 1000 = 9.5TClock = 290ns
         */
        li      t0, 0xaa00000c          /* BCUSPEEDREG */
        li      t1, 0x7008
        sh      t1, (t0)

        /*
         * setup SDTIMINGREG
         * BIT8 = 1 (always 1)
         * TRAS = 01 = 5SDCLK   (forced under 66, 50, 33MHz bus clock)
         * TRC  = 01 = 7SDCLK   (forced under 66, 50, 33MHz bus clock)
         * TRP  = 10 = 3SDCLK   (forced under 66, 50, 33MHz bus clock)
         * TRCP = 01 = 2SDCLK   (forced under 66, 50, 33MHz bus clock)
         */
        li      t0, 0xaa00030c          /* SDTIMINGREG */
        li      t1, 0x0159
        sh      t1, (t0)

        /*
         * To initialize 64Mbit SDRAM properly, we have to take
         * following steps:
         * 
         *      1. set MEMCFG_REG for 16Mbit SDRAM
         *      2. setup MODE_REG
         *      3. init SDRAM (setting MEMCFG_REG:Init to 1)
         *      4. set MEMCFG_REG for 64Mbit SDRAM
         *
         * confirm to VR4181 users manual 6.5.2 MEMCFG_REG (page 142).
         * (the page number is for Japanese edition.  it might be 
         *  at another page number for the English edition.)
         */

        /*
         * first, say MEMCFG_REG that SDRAM is 16Mbit
         * Init = 0
         * B1Config = 01        (16Mbit)
         * Bstreftype = 1       (all raw refresh)
         * BstRefr = 0          (not allow burst refresh)
         * EDOAsym = 0          (asymmetric)
         * B0Config = 01        (16Mbit)
         * EDO/SDRAM = 1        (SDRAM)
         */
        li      t0, 0xaa000304          /* MEMCFG_REG <- 503 (16Mbit) */
        li      t1, 0x0503
        sh      t1, (t0)

        /*
         * second, setup MODE_REG
         * Bit11 = 0            (always 0)
         * Bit10 = 0            (always 0)
         * BR-SW = 0            (always 0)
         * TE-Ven = 00          (always 00)
         * LTMode = 011         (3clock CAS latency)
         * WT = 0               (always 0)
         * BL = 111             (always 111)
         */
        li      t0, 0xaa000308          /* MODE_REG */
        li      t1, 0x0037
        sh      t1, (t0)

        /*
         * third, kick SDRAM initialization
         * Init = 1
         * other = untouched
         */
        li      t0, 0xaa000304          /* MEMCFG_REG:Init <- 1 */
        li      t1, 0x8503
        sh      t1, (t0)

        /*
         * final, say MEMCFG_REG that SDRAM is 16Mbit
         * Init = 0
         * B1Config = 10        (64Mbit)
         * Bstreftype = 1       (all raw refresh)
         * BstRefr = 0          (not allow burst refresh)
         * EDOAsym = 0          (asymmetric)
         * B0Config = 10        (64Mbit)
         * EDO/SDRAM = 1        (SDRAM)
         */
        li      t0, 0xaa000304          /* MEMCFG_REG */
        li      t1, 0x0905
        sh      t1, (t0)

        /*
         * setup XISACTL
         * EXTRESULT = 1        (1 is recommended)
         * INTRESULT = 0        (0 is recommended)
         * EXBUFEN = 0          (use SYSDIR and SYSEN)
         * MEMWS = 00           (1.5 SYSCLK)
         * IOWS = 10            (2.5 SYSCLK)
         * SCLKDIV = 10         (PCLK/6)
         */
        li      t0, 0xab0002c4          /* XISACTL */
        li      t1, 0x0422
        sh      t1, (t0)
        nop


        /*
         *  enable cache
         */
        mfc0    t0, $16
        li      t1, 0xfffffff8
        and     t0, t0, t1
        or      t0, t0, 0x00000003      /* K0 = 3 */
        mtc0    t0, $16                 /* config */
        nop
        nop
        nop

        /*
         * initialize cache
         */
        mtc0    zero, $28               /* TagLo */

        lui     t0, 0x8000              /* vaddr */
        ori     t1, zero, 0x1000        /* cache size = 4KB */
cache_clear:
        .set    push
        .set    mips3
        cache   0x00, (t0)              /* Index_Invalidate */
        cache   0x09, (t0)              /* Index_Store_Tag */
        .set    pop
        addiu   t1, t1, -0x10
        bgtz    t1, cache_clear
        addiu   t0, t0, 0x10            /* increment of line size */


        /* LED3 ON */
        li      t0, 0xab000306
        li      t1, 0x0800
        sh      t1, (t0)

        li      t0, 0xab000308
        sh      zero, (t0)
        nop
        /* LED3 ON */

        /*
         * now early bus configuration is done.
         */


        /*
         *  copy bootloader ROM to RAM
         */
        li      t1, LCBOOT_ROMSTARTADDR
        la      t2, start
        la      t3, edata
1:
        lw      t0, (t1)
        nop
        sw      t0, (t2)
        addu    t2, t2, 4
        sltu    t0, t2, t3
        .set    push
        .set    noreorder
        .set    nomacro
        bne     t0, zero, 1b
        addu    t1, t1, 4
        .set    pop
        

        /* verify */
        li      t1, LCBOOT_ROMSTARTADDR
        la      t2, start
        la      t3, edata
1:
        lw      t0, (t1)
        lw      t4, (t2)
        addu    t2, t2, 4
        bne     t0, t4, 2f
        sltu    t0, t2, t3
        .set    push
        .set    noreorder
        .set    nomacro
        bne     t0, zero, 1b
        addu    t1, t1, 4
        .set    pop
        b       4f
        nop
2:
        /* panic. stop LED */
        li      t0, 0xab000248          /* LEDCNTREG */
        sh      zero, (t0)
3:
        b       3b
        nop
4:      
        /* verify done */
                

        /* LED4 ON */
        li      t0, 0xab000306
        li      t1, 0x8800
        sh      t1, (t0)

        li      t0, 0xab000308
        sh      zero, (t0)
        /* LED4 ON */

        /*
         * now we've got a working RAM with cache.
         */


#else /* !ROMICE */
        /*
         * enable cache
         */
        mfc0    t0, $16
        li      t1, 0xfffffff8
        and     t0, t0, t1
        or      t0, t0, 0x00000003      /* K0 = 3 */
        mtc0    t0, $16                 /* config */
        nop
        nop
        nop
#endif /* !ROMICE */


        /*
         * zero the bss
         */
        la      t1, edata
        la      t2, end
        sw      zero, (t1)
1:
        addu    t1, t1, 4
        .set    push
        .set    mips3
        .set    noreorder
        .set    nomacro
        sltu    t0, t1, t2
        bnel    t0, zero, 1b
        sw      zero, (t1)              /* delay slot */
        .set    pop




#ifdef DEBUG_LED
        /* LED5 ON */
        li      t0, 0xab000302
        li      t1, 0x0002
        sh      t1, (t0)

        li      t0, 0xab00030a
        sh      zero, (t0)
        /* LED5 ON */
#endif  
        
#ifdef DEBUG_LED
        /* LED6 ON */
        li      t0, 0xab000300
        li      t1, 0x0020
        sh      t1, (t0)

        li      t0, 0xab00030a
        sh      zero, (t0)
        /* LED6 ON */
#endif



        /*
         * call lcboot main()
         */
        move    a0, zero                /* a0:  argc = 0 */
        move    a1, zero                /* a1 */
        move    a2, zero                /* a2 */
        move    a3, zero                /* a3 */
        move    k0, zero                /* k0 */
        move    k1, zero                /* k1 */
        la      gp, _C_LABEL(_gp)       /* global pointer */
        la      sp, start               /* stack pointer */
        la      v0, main
        jalr    v0
        nop

        .globl  start_netbsd
start_netbsd:
        /*
         * all LED OFF
         */
        li      t0, 0xab000248          /* LEDCNTREG */
        sh      zero, (t0)
        li      t1, 0xffff
        li      t0, 0xab000308
        sh      t1, (t0)
        li      t0, 0xab00030a
        sh      t1, (t0)

        /*
         * initialize registers
         */
        li      a0, 1                   /* a0:  argc = 1 */
        la      a1, argv0               /* a1:  argv */
        la      a2, bootinfo            /* a2:  bootinfo */
        move    a3, zero                /* a3 */
        move    k0, zero                /* k0 */
        move    k1, zero                /* k1 */
        /* no need to set grobal pointer. it set in locore.S */
        la      sp, NETBSD_STARTADDR    /* stack pointer */
        /*
         * call netbsd
         */
        jr      sp
        nop


/*
 * arguments for mach_init()
 */
        .data
argv0:
        .word   argv0c
argv1:
        .word   0
argv0c:
        .asciiz "netbsd"

bootinfo:
        .half   34              /* length */
        .half   0               /* reserved */
        .word   0x13536135      /* magic */
        .word   0               /* fb_addr */
        .half   0               /* fb_line_bytes */
        .half   0               /* fb_width */
        .half   0               /* fb_height */
        .half   0               /* fb_type */
        .half   2               /* BI_CNUSE_SERIAL */
        .half   0               /* padding */
        .word   0x04104400      /* PLATID_CPU_MIPS_VR_4181 */
        .word   0x03810100      /* PLATID_MACH_LASER5_L_CARD */
        .word   0               /* GMT */

/*
 * End of start.S
 */