/*---------------------------------------------------------------------------*
  Project:  TwlSDK - OS - include
  File:     spinLock.h

  Copyright 2003-2008 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.

  $Date:: 2008-09-17#$
  $Rev: 8556 $
  $Author: okubata_ryoma $

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

#ifndef NITRO_OS_SPINLOCK_H_
#define NITRO_OS_SPINLOCK_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <nitro/types.h>

#ifdef SDK_NITRO
#ifdef	SDK_ARM9
#include	<nitro/hw/ARM9/mmap_global.h>
#else  //SDK_ARM7
#include	<nitro/hw/ARM7/mmap_global.h>
#endif
#else // SDK_TWL
#include    <twl/hw/common/mmap_shared.h>
#ifdef	SDK_ARM9
#include	<twl/hw/ARM9/mmap_global.h>
#else  //SDK_ARM7
#include	<twl/hw/ARM7/mmap_global.h>
#endif
#endif //SDK_NITRO

//======================================================================
//                      Lock Functions
//
//Use these functions to exclusively control dedicated resources, such as the inter-CPU transfer FIFO, and common resources between CPUs, such as internal work RAM and VRAM-C/D shared by Game Cards, Game Paks, and CPUs.
//  
//  
//======================================================================

// Lock ID

#define OS_UNLOCK_ID            0      // ID when lock variable is not locked
#define OS_MAINP_LOCKED_FLAG    0x40   // Main processor lock verification flag
#define OS_MAINP_LOCK_ID_START  0x40   // Starting number of lock ID assignments, for main processor use
#define OS_MAINP_LOCK_ID_END    0x6f   // Assignment completion number
#define OS_MAINP_DBG_LOCK_ID    0x70   // Debugger reservation number
#define OS_MAINP_SYSTEM_LOCK_ID 0x7f   // System reservation number
#define OS_SUBP_LOCKED_FLAG     0x80   // Lock verification flag by sub processor
#define OS_SUBP_LOCK_ID_START   0x80   // Starting number of lock ID assignments, for sub processor use
#define OS_SUBP_LOCK_ID_END     0xaf   // Assignment completion number
#define OS_SUBP_DBG_LOCK_ID     0xb0   // Debugger reservation number
#define OS_SUBP_SYSTEM_LOCK_ID  0xbf   // System reservation number

#define OS_LOCK_SUCCESS         0      // Lock success
#define OS_LOCK_ERROR           (-1)   // Lock error

#define OS_UNLOCK_SUCCESS       0      // Unlock success
#define OS_UNLOCK_ERROR         (-2)   // Unlock error

#define OS_LOCK_FREE            0      // Unlocking

#define OS_LOCK_ID_ERROR        (-3)   // Lock ID error


//---- Structure of Lock Variable 
typedef volatile struct OSLockWord
{
    u32     lockFlag;
    u16     ownerID;
    u16     extension;
}
OSLockWord;

/*---------------------------------------------------------------------------*
  Name:         OS_InitLock

  Description:  Initialize system lock variable 
                and privilege to access shared resources.

                * cartridge exclusive control area is not cleared 
                  because debugger uses.

  Arguments:    None.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void    OS_InitLock(void);

//----------------------------------------------------------------------
//          Spinlock
//
//- This conducts spinlock of the lock variables for exclusive control of resources shared between processors and between modules.
//   
//- Trials continue until lock succeeds.
//- Be sure to lock resources shared between processors before using them.
//If the timing of resources exclusively used by one processor can be adjusted, it is okay not to lock them.
//   
//  It's also possible to lock exclusive-use resources just for debugging.
//
//Arguments:
//  lockID:              Lock ID
//  lockp:       Lock variable's pointer
//
//Return values:
//  OS_LOCK_SUCCESS:     Lock success
//----------------------------------------------------------------------
s32     OS_LockByWord(u16 lockID, OSLockWord *lockp, void (*ctrlFuncp) (void));
s32     OS_LockCartridge(u16 lockID);
s32     OS_LockCard(u16 lockID);

//----------------------------------------------------------------------
//          Unlock
//
//- This unlocks and passes access rights of shared resources to the subprocessor.
//- In the case of running a module that is not locked, it will not be unlocked, and OS_UNLOCK_ERROR will be returned.
//   
//
//Arguments:
//  lockID:              Lock ID
//  lockp:       Lock variable's pointer
//
//Return values:
//  OS_UNLOCK_SUCCESS:   Unlock success
//  OS_UNLOCK_ERROR:     Unlock error
//----------------------------------------------------------------------
s32     OS_UnlockByWord(u16 lockID, OSLockWord *lockp, void (*ctrlFuncp) (void));
s32     OS_UnlockCartridge(u16 lockID);
s32     OS_UnlockCard(u16 lockID);

//---- for compatibility with old name ('UnLock' <-> 'Unlock')
//     Because isd lib calls OS_UnLock*, these cannot be inlined.
s32     OS_UnLockByWord(u16 lockID, OSLockWord *lockp, void (*ctrlFuncp) (void));
s32     OS_UnLockCartridge(u16 lockID);
s32     OS_UnLockCard(u16 lockID);

//----------------------------------------------------------------------
//          Lock trials
//
//- Try spinlock once only.
//- Be sure to lock resources shared between processors before using them.
//If the timing of resources exclusively used by one processor can be adjusted, it is okay not to lock them.
//  
//  It's also possible to lock exclusive-use resources just for debugging.
//
//Arguments:
//  lockID:              Lock ID
//  lockp:       Lock variable's pointer
//  CtrlFuncp:           Resource control functions pointer
//
//Return values:
//  TRUE:                  Locked (the previously stored ID)
//  OS_LOCK_SUCCESS:     Lock success
//----------------------------------------------------------------------
s32     OS_TryLockByWord(u16 lockID, OSLockWord *lockp, void (*crtlFuncp) (void));
s32     OS_TryLockCartridge(u16 lockID);
s32     OS_TryLockCard(u16 lockID);

//----------------------------------------------------------------------
//          Read the lock variable's owner module ID
//
//- This reads the lock variable's owner module ID.
//- You can check which processor has ownership rights if the module ID is non-zero.
//   
//In the case of a shared resource, only the state of the main processor side having ownership rights can be maintained by disabling interrupts.
//   
//  In other states, it might be changed by the sub processor.
//- The lock variable may not necessarily be unlocked even if owner module ID is 0.
//
//Arguments:
//  lockp:       Lock variable's pointer
//
//Return values:    Owner module ID
//
//*Note: Be aware that byte access cannot be performed to the main memory unless it is through a cache.
//   
//  Thus, as a basic rule, you should use OS_ReadOwnerOfLockWord() for main memory.
//----------------------------------------------------------------------
u16     OS_ReadOwnerOfLockWord(OSLockWord *lockp);
#define OS_ReadOwnerOfLockCartridge()  OS_ReadOwnerOfLockWord( (OSLockWord *)HW_CTRDG_LOCK_BUF )
#define OS_ReadOwnerOfLockCard()       OS_ReadOwnerOfLockWord( (OSLockWord *)HW_CARD_LOCK_BUF  )



/*---------------------------------------------------------------------------*
  Name:         OS_GetLockID

  Description:  Get lock ID.

  Arguments:    None.

  Returns:      OS_LOCK_ID_ERROR, if fail to get ID

                if ARM9
                   0x40-0x6f:       lockID
                else if ARM7
                   0x80-0xaf:       lockID
                endif

                *Notice:  ID is allocated only 48 pattern at a highest.

 *---------------------------------------------------------------------------*/
s32     OS_GetLockID(void);


/*---------------------------------------------------------------------------*
  Name:         OS_ReleaseLockID

  Description:  Release lock ID.

  Arguments:    lockID: id to tend to release.

  Returns:      None.
 *---------------------------------------------------------------------------*/
void    OS_ReleaseLockID(u16 lockID);



#ifdef SDK_TWL
//================================================================
//   Private Functions
//   These functions are for internal use. Never call them from the application.
#define OSi_SYNCTYPE_SENDER 0
#define OSi_SYNCTYPE_RECVER 1

#define OSi_SYNCVAL_NOT_READY 0
#define OSi_SYNCVAL_READY     1

void OSi_SyncWithOtherProc( int type, void* syncBuf );

static inline void OSi_SetSyncValue( u8 n )
{
	*(vu8*)(HW_INIT_LOCK_BUF+4) = n;
}
static inline u8 OSi_GetSyncValue( void )
{
	return *(vu8*)(HW_INIT_LOCK_BUF+4);
}

#endif


//--------------------------------------------------------------------------------
#ifdef __cplusplus
} /* extern "C" */
#endif

/* NITRO_OS_SPINLOCK_H_ */
#endif
