/*---------------------------------------------------------------------------*
  Project:  NitroSDK - libraries - loader
  File:     boot.c

  Copyright 2003-2006 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  Revision 1.6  2006/01/18 02:11:19  kitase_hirotake
  do-indent

  Revision 1.5  2005/11/24 00:44:56  yosizaki
  fix warnings about implicit cast.

  Revision 1.4  2005/02/28 05:26:01  yosizaki
  do-indent.

  Revision 1.3  2004/09/04 10:01:18  sato_masaki
  includeヘッダを、mb_private.hに変更。

  Revision 1.2  2004/09/03 07:09:25  sato_masaki
  MBライブラリのファイル分割による更新。NVRAMまわりのリネームに対応。

  Revision 1.1  2004/08/31 11:00:13  sato_masaki
  initial check-in

 *---------------------------------------------------------------------------*/

#include <nitro.h>

#if	defined(SDK_ARM7)
#include <nitro_wl/ARM7/WlLib.h>
#endif


#include <nitro/mb.h>
#include <mb_private.h>
#include "loader.h"
#include "boot.h"


/*----------------------------------------------------------------------------*/
/* definition */
#define INITi_HW_DTCM   SDK_AUTOLOAD_DTCM_START

/*----------------------------------------------------------------------------*/
/* static functions */
static void BOOTi_PxiSync(void);
static void BOOTi_ClearRegisters(void);


/*----------------------------------------------------------------------------*/
/* メモリインターフェース(ARM9) */
#if	defined(SDK_ARM9)

#include <nitro/code32.h>

static asm void my_MI_CpuClear32( register u32 data, register void *destp, register u32 size )
{
        add     r12, r1, r2             // r12: destEndp = destp + size

@20:
        cmp     r1, r12                 // while (destp < destEndp)
        stmltia r1!, {r0}               // *((vu32 *)(destp++)) = data
        blt     @20

        bx      lr
}

#endif // SDK_ARM9

/* メモリインターフェース(common) */
#ifdef SDK_ARM9
#  define MI_DMA_TIMING_MASK         (REG_MI_DMA0CNT_MODE_MASK) // mask  of start field
#else
#define MI_DMA_TIMING_MASK			(REG_MI_DMA0CNT_TIMING_MASK)    // mask  of start field
#endif
#define MI_DMA_ENABLE				(1UL << REG_MI_DMA0CNT_E_SHIFT) // ＤＭＡ許可
#define MI_DMA_CONTINUOUS_ON		(1UL << REG_MI_DMA0CNT_CM_SHIFT)        // continuous mode on


static void my_MI_StopDma(u32 dmaNo)
{
    OSIntrMode enabled = OS_DisableInterrupts();
    vu16   *dmaCntp = &((vu16 *)REG_DMA0SAD_ADDR)[dmaNo * 6 + 5];

    *dmaCntp &= ~((MI_DMA_TIMING_MASK | MI_DMA_CONTINUOUS_ON) >> 16);
    *dmaCntp &= ~(MI_DMA_ENABLE >> 16);

    {
        s32     dummy = dmaCntp[0];
    }
    {
        s32     dummy = dmaCntp[0];
    }

    (void)OS_RestoreInterrupts(enabled);
}


/*---------------------------------------------------------------------------*
  Name:         BOOTi_PxiSync

  Description:  他方の CPU と同期を取る

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void BOOTi_PxiSync(void)
{
#if	defined(SDK_ARM7)
    reg_PXI_MAINPINTF = 1 << REG_PXI_MAINPINTF_A7STATUS_SHIFT;
    while ((reg_PXI_MAINPINTF & REG_PXI_MAINPINTF_A9STATUS_MASK) != 1)
    {
        SVC_WaitByLoop(1);
    }
#else
    while ((reg_PXI_SUBPINTF & REG_PXI_SUBPINTF_A7STATUS_MASK) != 1)
    {
        SVC_WaitByLoop(1);
    }
    reg_PXI_SUBPINTF = 1 << REG_PXI_SUBPINTF_A9STATUS_SHIFT;
#endif
}


/*---------------------------------------------------------------------------*
  Name:         BOOTi_ClearRegisters

  Description:  clear registers

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
static void BOOTi_ClearRegisters(void)
{
    OS_SetTimerControl(OS_TIMER_0, 0);
    OS_SetTimerControl(OS_TIMER_1, 0);
    OS_SetTimerControl(OS_TIMER_2, 0);
    OS_SetTimerControl(OS_TIMER_3, 0);

    my_MI_StopDma(0);
    my_MI_StopDma(1);
    my_MI_StopDma(2);
    my_MI_StopDma(3);

    reg_PXI_FIFO_CNT = 0;

#if	defined(SDK_ARM7)
    reg_SPI_SPICNT = 0;
    EXIi_SetRcnt0L(0);
    EXIi_SetRcnt0H(0);
    EXIi_SetRcnt1(0);
#endif
}


/*---------------------------------------------------------------------------*
  Name:         BOOT_Start

  Description:  boot multiboot image

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
BOOL BOOT_Start(void)
{
    MBDownloadFileInfo *mdfi = (MBDownloadFileInfo *) MB_DOWNLOAD_FILEINFO_ADDRESS;
    void    (*funcp) (void) = NULL;



#if	defined(SDK_ARM7)
    funcp = (void (*)(void))(mdfi->header.arm7EntryAddr);
#else
    funcp = (void (*)(void))(mdfi->header.arm9EntryAddr);
#endif

    if (funcp)
    {
        // マルチブートアプリケーション起動の同期
        BOOTi_PxiSync();
        // PXI関連するレジスタをクリア
        BOOTi_ClearRegisters();

        // メモリのクリア
#if	defined(SDK_ARM9)
        my_MI_CpuClear32(0x0000, (void *)HW_PLTT, HW_PLTT_SIZE);        // PLTT
        my_MI_CpuClear32(0x0200, (void *)HW_OAM, HW_OAM_SIZE);  // OAM
//              my_MI_CpuClear32(       0x0000, (void*)INITi_HW_DTCM,   HW_DTCM_SIZE    );      // DTCM
#endif

        funcp();
    }
    return FALSE;
}
