/**************************************************************************//**
\file  lowLevelInit.c

\brief Implementation of low level initialization.

\author
    Atmel Corporation: http://www.atmel.com \n
    Support email: avr@atmel.com

  Copyright (c) 2008-2015, Atmel Corporation. All rights reserved.
  Licensed under Atmel's Limited License Agreement (BitCloudTM).

\internal
  History:
    5/12/07 A. Khromykh - Created
*******************************************************************************/
/******************************************************************************
 *   WARNING: CHANGING THIS FILE MAY AFFECT CORE FUNCTIONALITY OF THE STACK.  *
 *   EXPERT USERS SHOULD PROCEED WITH CAUTION.                                *
 ******************************************************************************/

/******************************************************************************
                   Includes section
******************************************************************************/
#include <AT91SAM7X256.h>
#include <dbgPort.h>
#include <types.h>

/******************************************************************************
                   Define(s) section
******************************************************************************/
#define HAL_DISABLE_WDT_FOREVER
//#define HAL_ENABLE_AIC_DEBUG_MODE

#define PLL_MULTIPLIER     25
#define PLL_DIVIDER        5

#define RESET_KEY           0xA5

#define FLASH_USEC_CYCLE_NUM    75ul

/***************************************************************************//*
 \brief This function performs very low level HW initialization
        this function can be use a Stack, depending the compilation
        optimization mode
******************************************************************************/
void lowLevelInit(void)
{
  uint8_t i = 0;

  /* EFC Init. Maximum Operating Frequency 48000000(Hz) > 30 MHz. Read operation is 2 cycle.
     Master clock is 48000000 Hz. It's approximately 50 cycle for 1 us or about 75 cycle in 1.5 us */
  AT91C_BASE_MC->MC_FMR = (AT91C_MC_FMCN & (FLASH_USEC_CYCLE_NUM << 16)) | AT91C_MC_FWS_1FWS;

#ifdef HAL_DISABLE_WDT_FOREVER
  /* Watchdog Disable */
  AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
#endif

  /* enable clock on port A */
  AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOA);


  /* Set MCK at 47 923 200 Hz. Crystal 18,432 MHz. */
  /* 1 Enabling the Main Oscillator: */
  /* Typically startup time 1.4 ms for 16 MHz crystal.
     Slow clock = 1/32768 = 30.51 us approximately.
     Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms */
  AT91C_BASE_PMC->PMC_MOR = ((AT91C_CKGR_OSCOUNT & (0x06 << 8)) | AT91C_CKGR_MOSCEN);
  // Wait the startup time
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
  /* 2 Checking the Main Oscillator Frequency (Optional) */
  /* 3 Setting PLL and divider: */
  /* divider is 5. (18,432 / 5) = 3,6864.
     multiplier is (25+1). Fout = (3,6864 *26) = 95,8464 MHz.
     for 96 MHz the error is 0.16%.
     AT91C_CKGR_PLLCOUNT was counted ATMEL utilite.
     USB source clock is PLL clock output divided by 2. */
  AT91C_BASE_PMC->PMC_PLLR = ((AT91C_CKGR_DIV & PLL_DIVIDER) |
                             (AT91C_CKGR_PLLCOUNT & (28 << 8)) |
                             (AT91C_CKGR_MUL & (PLL_MULTIPLIER << 16))) |
                             AT91C_CKGR_USBDIV_1;
  // Wait the startup time
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK));
  /* 4. Selection of Master Clock and Processor Clock */
  /* select the PLL clock divided by 2 */
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2 ;
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
  AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
  while(!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));


  /* Reset AIC: assign default handler for each interrupt source */
  AT91C_BASE_AIC->AIC_SVR[0] = (int)default_fiq_handler ;
  for (i = 1; i < 31; i++) {
    AT91C_BASE_AIC->AIC_SVR[i] = (int)default_irq_handler ;
  }
  AT91C_BASE_AIC->AIC_SPU = (int)default_spurious_handler;
  // Perform 8 IT acknowledge (write any value in EOICR)
  for (i = 0; i < 8 ; i++) {
    AT91C_BASE_AIC->AIC_EOICR = 0;
  }

#ifdef HAL_ENABLE_AIC_DEBUG_MODE
  // Enable the Debug mode
  AT91C_BASE_AIC->AIC_DCR = AT91C_AIC_DCR_PROT;
#endif

  // Enable hardware reset on RST pin
  AT91C_BASE_RSTC->RSTC_RMR = AT91C_RSTC_URSTEN | (0x1 << 8) | (RESET_KEY << 24);
}

