/*      $NetBSD: gemini_start.S,v 1.10 2024/11/19 05:00:09 andvar Exp $ */

/*
* Machine dependent startup code for GEMINI boards.
* Based on omap_start.S
*
* Copyright (c) 2002, 2003  Genetec Corporation.  All rights reserved.
* Written by Hiroyuki Bessho for Genetec Corporation.
*
* 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. The name of Genetec Corporation may not be used to endorse or
*    promote products derived from this software without specific prior
*    written permission.
*
* THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION
* 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.
*
* Copyright (c) 2003
*      Ichiro FUKUHARA <[email protected]>.
* 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 ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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.
*
* Copyright (c) 2007 Microsoft
* 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 Microsoft
*
* 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 OR CONTRIBUTERS 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 "opt_gemini.h"
#include "opt_com.h"

#include <machine/asm.h>
#include <arm/armreg.h>
#include "assym.h"

RCSID("$NetBSD: gemini_start.S,v 1.10 2024/11/19 05:00:09 andvar Exp $")


#if defined(VERBOSE_INIT_ARM)
# define _PUTCHAR(addr, areg, breg, c)                  \
       ldr     areg, addr;                             \
1:                                                      \
       ldr     breg, [areg, #0x14];    /* LSR    */    \
       tst     breg, #0x20;            /* TXRDY? */    \
       beq     1b;                                     \
       mov     breg, #(c);             /*   c    */    \
       str     breg, [areg];           /* TXDATA */    \
2:                                                      \
       ldr     breg, [areg, #0x14];    /* LSR    */    \
       tst     breg, #0x40;            /* TSRE?  */    \
       beq     2b;
#else
# define _PUTCHAR(addr, areg, breg, c)
#endif


/*
* Kernel start routine for GEMINI Eval board.
* At this point, this code has been loaded into SDRAM
* and the MMU is off
*/
       .section .start,"ax",%progbits

       .global _C_LABEL(gemini_start)
_C_LABEL(gemini_start):
       /* Move into supervisor mode and disable IRQs/FIQs. */
       mrs     r0, cpsr
       bic     r0, r0, #PSR_MODE
       orr     r0, r0, #(I32_bit | F32_bit | PSR_SVC32_MODE)
       msr     cpsr, r0

       _PUTCHAR(Lconsole_pbase, r4, r3, 'a')

       /*
        * Set up a preliminary mapping in the MMU to allow us to run
        * at KERNEL_BASE with caches on.
        */
       /* Build page table from scratch */
       ldr     r0, Ltemp_l1_table
       mov     r1, r0                  /* Save the page table address. */
       /* Zero the entire table so all virtual addresses are invalid. */
       mov     r2, #L1_TABLE_SIZE      /* in bytes */
       mov     r3, #0
       mov     r4, r3
       mov     r5, r3
       mov     r6, r3
       mov     r7, r3
       mov     r8, r3
       mov     r10, r3
       mov     r11, r3
1:      stmia   r1!, {r3-r8,r10-r11}
       stmia   r1!, {r3-r8,r10-r11}
       stmia   r1!, {r3-r8,r10-r11}
       stmia   r1!, {r3-r8,r10-r11}
       subs    r2, r2, #(4 * 4 * 8)    /* bytes per loop */
       bne     1b

       _PUTCHAR(Lconsole_pbase, r4, r3, 'b')

       /* Now create our entries per the mmu_init_table. */
       l1table .req r0
       va      .req r1
       pa      .req r2
       n_sec   .req r3
       attr    .req r4
       itable  .req r5
       l1sfrm  .req r6
       ldr     l1table, Ltemp_l1_table
       adr     itable, mmu_init_table
       ldr     l1sfrm, Ll1_s_frame
       b       3f
2:      str     pa, [l1table, va]
       add     va, va, #4
       add     pa, pa, #(L1_S_SIZE)
       adds    n_sec, n_sec, #-1
       bhi     2b
3:      ldmia   itable!, {va,pa,n_sec,attr}
       /* Convert va to l1 offset:     va = 4 * (va >> L1_S_SHIFT)     */
       mov     va, va, LSR #L1_S_SHIFT
       mov     va, va, LSL #2
       /* Convert pa to l1 entry:      pa = (pa & L1_S_FRAME) | attr   */
       and     pa, pa, l1sfrm
       orr     pa, pa, attr
       cmp     n_sec, #0
       bne     2b
       mov     r5, r0                  /* l1table */
       .unreq  va
       .unreq  pa
       .unreq  n_sec
       .unreq  attr
       .unreq  itable
       .unreq  l1table
       .unreq  l1sfrm

       _PUTCHAR(Lconsole_pbase, r4, r3, 'c')

       /*
        * using FA526 -specific cache ops here...
        */
       mov     r0, #0
       mcr     p15, 0, r0, c7, c5,  0  /* Invalidate Entire I cache */
       mcr     p15, 0, r0, c7, c14, 0  /* Clean & Invalidate Entire D cache */

       ldr     r2, Lctl_ID_dis         /* Disable I+D caches */
       mrc     p15, 0, r1, c1, c0, 0   /*  "       "   "     */
       and     r1, r1, r2              /*  "       "   "     */
       mcr     p15, 0, r1, c1, c0, 0   /*  "       "   "     */

       _PUTCHAR(Lconsole_pbase, r4, r3, 'd')

       mcr     p15, 0, r0, c7, c5, 6   /* invalidate BTB all */
       mcr     p15, 0, r0, c7, c10, 4  /* Drain the write buffers. */
       mcr     p15, 0, r5, c2, c0, 0   /* Set Translation Table Base */
       mcr     p15, 0, r0, c8, c7, 0   /* Invalidate TLBs */

       /* Set the Domain Access register */
       mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
       mcr     p15, 0, r0, c3, c0, 0

       /*
        * set Extension Control Enable in ECR, so we can use BTB
        */
       ldr     r0, Lecr_set
       mcr     p15, 0, r0, c1, c1, 0

       /*
        * Enable the MMU, etc.
        */
       mrc     p15, 0, r0, c1, c0, 0
       ldr     r1, Lcontrol_wax
       and     r0, r0, r1
       ldr     r1, Lcontrol_clr
       mvn     r1, r1
       and     r0, r0, r1
       ldr     r1, Lcontrol_set
       orr     r0, r0, r1
       mcr     p15, 0, r0, c1, c0, 0

       /*
        * Ensure that the coprocessor has finished turning on the MMU.
        */
       mrc     p15, 0, r0, c2, c0, 0   /* Read an arbitrary value. */
       mov     r0, r0                  /* Stall until read completes. */

       _PUTCHAR(Luart_vbase, r4, r3, 'e')

       /*
        * Zero .bss
        */
       ldr     r0, L_edata
       ldr     r1, L_end
       mov     r2, #0
1:
       str     r2, [r0], #0x04         /* *r0++ = r2 */
       cmp     r0, r1
       bne     1b

#if 0
       /*
        * Jump to start in locore.S, which in turn will call initarm and main.
        */
       adr     r0, Ltestjmp
       ldr     pc, [r0]
       nop
       nop
       nop
       nop
testjmp:
#endif

       _PUTCHAR(Luart_vbase, r4, r3, 'f')

       adr     r0, Lstart
       ldr     pc, [r0]
       nop
       nop
       nop
       nop

       /* NOTREACHED */

L_edata:
       .word   _C_LABEL(_edata)
L_end:
       .word   _C_LABEL(_end)

#if 0
Ltestjmp:
       .word   testjmp
#endif

Lstart:
       .word   start
Ll1_s_frame:
       .word   L1_S_FRAME
Ltemp_l1_table:
       /* Put the temporary L1 translation table at the end of SDRAM. */
       .word   MEMSIZE * 0x100000 - L1_TABLE_SIZE

/*
* Coprocessor register initialization values
*/
#if !defined(CPU_ECR_ECE)
# define        CPU_ECR_ECE             1
#endif
       /* bits to set in the Extension Control Register */
Lecr_set:
       .word   CPU_ECR_ECE

#if !defined(CPU_CONTROL_BTB_ENABLE)
# define        CPU_CONTROL_BTB_ENABLE  (1 << 11)
#endif
       /* bits to set in the Control Register */
       /* bits 6..4 SB1 */
Lcontrol_set:
       .word CPU_CONTROL_MMU_ENABLE  | \
             CPU_CONTROL_AFLT_ENABLE | \
             CPU_CONTROL_DC_ENABLE   | \
             CPU_CONTROL_WBUF_ENABLE | \
             CPU_CONTROL_32BP_ENABLE | \
             CPU_CONTROL_32BD_ENABLE | \
             CPU_CONTROL_LABT_ENABLE | \
             CPU_CONTROL_SYST_ENABLE | \
             CPU_CONTROL_IC_ENABLE   | \
             CPU_CONTROL_DC_ENABLE   | \
             CPU_CONTROL_BTB_ENABLE

       /* bits to clear in the Control Register */
       /* bits 31..14, 10,  SBZ */
Lcontrol_clr:
       .word   ((~0) << 14) | \
               (1 << 10)

       /* bits to "write as existing" in the Control Register */
Lcontrol_wax:
       .word   CPU_CONTROL_BEND_ENABLE

       /* bits to disable the caches */
Lctl_ID_dis:
       .word   ~(CPU_CONTROL_IC_ENABLE|CPU_CONTROL_DC_ENABLE)

       /* console addressing */
Lconsole_pbase:
#if 0
       .word   CONSADDR
#else
       .word   GEMINI_UART_BASE
#endif
Luart_vbase:
       .word   GEMINI_UART_VBASE


/* We'll modify va and pa at run time so we can use relocatable addresses. */
#define MMU_INIT(va,pa,n_sec,attr) \
       .word   va                                          ; \
       .word   pa                                          ; \
       .word   n_sec                                       ; \
       .word   attr                                        ;

mmu_init_table:
       /* Maintain current 1:1 addressability */
       MMU_INIT(KERNEL_BASE_phys, KERNEL_BASE_phys,
               (MEMSIZE * L1_S_SIZE + L1_S_SIZE - 1) / L1_S_SIZE,
               L1_S_PROTO | L1_S_AP_KRW | L1_S_B | L1_S_C)

       /* Map Kernel base VA:PA, write-back cacheable */
       MMU_INIT(KERNEL_BASE_virt, KERNEL_BASE_phys,
               (MEMSIZE * L1_S_SIZE + L1_S_SIZE - 1) / L1_S_SIZE,
               L1_S_PROTO | L1_S_AP_KRW | L1_S_B | L1_S_C)

       /* Map Gemini GLOBAL regs */
       MMU_INIT(GEMINI_GLOBAL_VBASE, GEMINI_GLOBAL_BASE,
               1,
               L1_S_PROTO | L1_S_AP_KRW)

       /* Map Gemini UART */
       MMU_INIT(GEMINI_UART_VBASE, GEMINI_UART_BASE,
               1,
               L1_S_PROTO | L1_S_AP_KRW)

       /* Map Gemini LPC Host Controller Space */
       MMU_INIT(GEMINI_LPCHC_VBASE, GEMINI_LPCHC_BASE,
               1,
               L1_S_PROTO | L1_S_AP_KRW)

       /* Map Gemini LPC IO Space */
       MMU_INIT(GEMINI_LPCIO_VBASE, GEMINI_LPCIO_BASE,
               1,
               L1_S_PROTO | L1_S_AP_KRW)

       /* Map Gemini DRAM Controller Space */
       MMU_INIT(GEMINI_DRAMC_VBASE, GEMINI_DRAMC_BASE,
               1,
               L1_S_PROTO | L1_S_AP_KRW)

       /* end of table */
       MMU_INIT(0, 0, 0, 0)