#include "driver_public.h"
#include <string.h>

#if defined(__ICCARM__)
#pragma default_function_attributes = @ "RAM_CODE"
#endif
    
SET_ANY_RW_4 volatile uint64_t driver_tick=0;
SET_ANY_RW_4 static uint32_t delay_us_mul=0; 
    
SET_VECTOR_TABLE static uint8_t vector_table[0x400];
#if defined(__ICCARM__)
extern const uint32_t __vector_table[];
#define SYSTEM_VECTOR_TABLE __vector_table
#else
extern const uint32_t __Vectors[];
#define SYSTEM_VECTOR_TABLE __Vectors
#endif
//extern const uint32_t __initial_sp;
SET_ANY_RW_4 uint32_t STACK2[2];
static void default_mpu_config(void);
   

/*!
    \brief      enable the CPU cache
    \param[in]  none
    \param[out] none
    \retval     none
*/
SET_FLASH_AREA void cache_enable(void)
{
    /* enable I-Cache and D-Cache */
		
    SCB_EnableICache();
    SCB_EnableDCache();
}


SET_FLASH_AREA void cache_disable(void)
{
    /* enable I-Cache and D-Cache */
    SCB_DisableICache();
    
    if (SCB->CCR & SCB_CCR_DC_Msk)// Dcache��δʹ�ܹ��Ļ�clearcache���з���
    {
        SCB_DisableDCache();
    }
}

/*!
* ˵��     systic��ʼ����Ĭ��1ms��
* ����[1]  ��
* ����ֵ   ��
*/
SET_FLASH_AREA static void systick_config(void)
{          
    /* setup systick timer for 1000Hz interrupts */
    if (SysTick_Config(SystemCoreClock / 1000U)){
        /* capture error */
        while (1){
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0xFU);
}

/*!
* ˵��     delay��ʼ��
* ����[1]  ��
* ����ֵ   ��
*/
SET_FLASH_AREA void delay_init(void)
{
    uint32_t temp;
    
    SystemCoreClockUpdate();
    
    temp=SystemCoreClock/1000;
    
    if ((temp - 1UL) > SysTick_LOAD_RELOAD_Msk)
    {
        return;                                                   /* Reload value impossible */
    }

    SysTick->LOAD  = (uint32_t)(temp - 1UL);                         /* set reload register */

    SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
    SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
    
    delay_us_mul=SystemCoreClock/1000000;                           /* Function successful */
}

/*!
* ˵��     driver��ع���������ʼ��
* ����[1]  ��
* ����ֵ   ��
*/
SET_FLASH_AREA void driver_init(void)
{          
    uint8_t *p_vector_table = vector_table;
    __disable_irq(); 
    
    driver_system_config();    
        
    memcpy(p_vector_table, (const void *)SYSTEM_VECTOR_TABLE, sizeof(vector_table));
    
    default_mpu_config();    
            
    nvic_vector_table_set((uint32_t)(&vector_table[0]), 0);   
        
    cache_enable();
        
    __enable_irq();

    systick_config();
    
    delay_init();
}

/*!
* ˵��     1us��ʱ
* ����[1]  count��us��λ
* ����ֵ   ��
*/
SET_RAM_CODE void delay_us(uint32_t count)
{
    uint32_t temp;
    
    if(delay_us_mul==0)
    {
        delay_init();    
    }
    SysTick->CTRL  |= SysTick_CTRL_CLKSOURCE_Msk |
                     SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
    count=count*delay_us_mul;

    if(count>SysTick->LOAD ){
        count=SysTick->LOAD ;
    }
    temp=SysTick->VAL;
    if(temp>count)
    {
        while(SysTick->VAL>(temp-count) && SysTick->VAL<=temp);
    }
    else {
        while(SysTick->VAL<=temp);
        while(SysTick->VAL>(SysTick->LOAD-(count-temp)));        
    }
}

/*!
* ˵��     ����������ʱ
* ����[1]  count���������ڸ���
* ����ֵ   ��
*/
SET_RAM_CODE void delay_sysclk(uint32_t count)
{
    uint32_t temp;
    
    if(delay_us_mul==0)
    {
        delay_init();    
    }
    
    SysTick->CTRL  |= SysTick_CTRL_CLKSOURCE_Msk |
                     SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */   
    if(count>SysTick->LOAD ){
        count=SysTick->LOAD ;
    }
    temp=SysTick->VAL;
    if(temp>count)
    {
        while(SysTick->VAL>(temp-count) && SysTick->VAL<=temp);
    }
    else {
        while(SysTick->VAL<=temp);
        while(SysTick->VAL>(SysTick->LOAD-(count-temp)));        
    }
}

/*!
* ˵��     1ms��ʱ
* ����[1]  count��ma��λ
* ����ֵ   ��
*/
SET_RAM_CODE void delay_ms(uint32_t count)
{  
    count=count*10;
    do{
        delay_us(100);
    }while(count--);
}


//ʹ�ô˺������ò���Ҫ�ٹ���MPU_REGION_NUMBERx�����Զ�����
/*!
    \param[in]  mpu_init_struct: MPU initialization structure
                  region_base_address: region base address
                  region_size: MPU_REGION_SIZE_32B, MPU_REGION_SIZE_64B, MPU_REGION_SIZE_128B, MPU_REGION_SIZE_256B, MPU_REGION_SIZE_512B, 
                               MPU_REGION_SIZE_1KB, MPU_REGION_SIZE_2KB, MPU_REGION_SIZE_4KB, MPU_REGION_SIZE_8KB, MPU_REGION_SIZE_16KB, 
                               MPU_REGION_SIZE_32KB, MPU_REGION_SIZE_64KB, MPU_REGION_SIZE_128KB, MPU_REGION_SIZE_256KB, MPU_REGION_SIZE_512KB,
                               MPU_REGION_SIZE_1MB, MPU_REGION_SIZE_2MB, MPU_REGION_SIZE_4MB, MPU_REGION_SIZE_8MB, MPU_REGION_SIZE_16MB, 
                               MPU_REGION_SIZE_32MB, MPU_REGION_SIZE_64MB, MPU_REGION_SIZE_128MB, MPU_REGION_SIZE_256MB, MPU_REGION_SIZE_512MB, 
                               MPU_REGION_SIZE_1GB, MPU_REGION_SIZE_2GB, MPU_REGION_SIZE_4GB
                  access_permission: MPU_AP_NO_ACCESS, MPU_AP_PRIV_RW, MPU_AP_PRIV_RW_UNPRIV_RO, MPU_AP_FULL_ACCESS, MPU_AP_PRIV_RO,
                                     MPU_AP_PRIV_UNPRIV_RO
                  access_bufferable: MPU_ACCESS_BUFFERABLE, MPU_ACCESS_NON_BUFFERABLE
                  access_cacheable: MPU_ACCESS_CACHEABLE, MPU_ACCESS_NON_CACHEABLE
                  access_shareable: MPU_ACCESS_SHAREABLE, MPU_ACCESS_NON_SHAREABLE
                  instruction_exec: MPU_INSTRUCTION_EXEC_PERMIT, MPU_INSTRUCTION_EXEC_NOT_PERMIT
                  tex_type: MPU_TEX_TYPE0, MPU_TEX_TYPE1, MPU_TEX_TYPE2
    \param[out] none
    \retval     none
*/
SET_FLASH_AREA void mpu_config(uint32_t region_base_address,uint32_t region_size,uint32_t access_permission,\
                                    uint32_t access_bufferable,uint32_t access_cacheable,uint32_t access_shareable,\
                                    uint32_t instruction_exec,uint32_t tex_type)
{
    mpu_region_init_struct mpu_init_struct;
    mpu_region_struct_para_init(&mpu_init_struct);
    
    static uint8_t MPU_REGION_NUMBERx=7;

    /* ����MPUǰͬ�����ڴ�*/
    if (SCB->CCR & SCB_CCR_DC_Msk)// Dcache������������CleanInvali
    {    
         SCB_CleanInvalidateDCache(); 
    }        
    
    /* configure the MPU attributes for all */
    mpu_init_struct.region_base_address = region_base_address;
    mpu_init_struct.region_size         = region_size;
    mpu_init_struct.access_permission   = access_permission;
    mpu_init_struct.access_bufferable   = access_bufferable;
    mpu_init_struct.access_cacheable    = access_cacheable;
    mpu_init_struct.access_shareable    = access_shareable;
    mpu_init_struct.region_number       = MPU_REGION_NUMBERx;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = instruction_exec;
    mpu_init_struct.tex_type            = tex_type;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();  
    
    /* enable the MPU */
    ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT);  

    MPU_REGION_NUMBERx++;
}


//Ĭ��MPU����
SET_FLASH_AREA static void default_mpu_config(void)
{
    mpu_region_init_struct mpu_init_struct;
    mpu_region_struct_para_init(&mpu_init_struct);
    
    /* ����MPUǰͬ�����ڴ�*/    
    if (SCB->CCR & SCB_CCR_DC_Msk)// Dcache������������CleanInvali
    {
        SCB_CleanInvalidateDCache();
    }    

    /* enable the MPU */
    ARM_MPU_Disable();  
    
    /* disable the MPU */
    ARM_MPU_SetRegion(0U, 0U);
    
    /*Ĭ�������ⲿ�洢����*/
    /* configure the MPU attributes for all */
    mpu_init_struct.region_base_address = 0;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_4GB;
    mpu_init_struct.access_permission   = MPU_AP_NO_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_NON_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER0;
    mpu_init_struct.subregion_disable   = 0x87;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();  
    
    /*SRAM0 1�ر�cacheԤ������̫������*/    
    /* configure the MPU attributes for DMA_RAM */
    mpu_init_struct.region_base_address = 0x30000000;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_32KB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_NON_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER1;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE1;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();   

    /*AXI SRAMԤ��64K�ر�cache��Ӳ��dma���ʣ���ɢ���غ�ʹ��SET_DMA_AREA_RAM*/  
    /* configure the MPU attributes for DMA AXI_SRAM */
    mpu_init_struct.region_base_address = 0x24070000;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_64KB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_NON_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER2;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE1;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();

    /*SDRAMĬ�����ÿ�cache����֧�ַǶ�����ʣ���ɢ���غ�ʹ��SET_SDRAM*/  
    /* configure the MPU attributes for SDRAM */
    mpu_init_struct.region_base_address = 0xC0000000;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_32MB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER3;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();  
    
    /*SDRAM����2MB�ر�cache��Ӳ��DMA���ʣ�����DCI��TLI����ɢ���غ�ʹ��SET_DMA_AREA_SDRAM*/  
    mpu_init_struct.region_base_address = 0xC0600000;
    mpu_init_struct.region_size         = MPU_REGION_SIZE_2MB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER4;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();  
       
    /*ITC�����ٽ�ջ�����������óɿɶ�д������һ������*/ 
    /* configure the MPU attributes for ITC */
    mpu_init_struct.region_base_address = (0);
    mpu_init_struct.region_size         = MPU_REGION_SIZE_16KB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER6;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_NOT_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable(); 

    /*ִ�д˴�ʱITC�������Ѿ�������ϣ�����������ֻ����ֹ�ڴ��ƻ�����ɢ���غ�ʹ��SET_RAM_CODE*/      
    /* configure the MPU attributes for ITC */
    mpu_init_struct.region_base_address = (uint32_t)(0);
    mpu_init_struct.region_size         = MPU_REGION_SIZE_512KB;
    mpu_init_struct.access_permission   = MPU_AP_PRIV_UNPRIV_RO;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER5;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE1;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable(); 

    /* enable the MPU */
    ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT);       
}

//�ڽ���main֮ǰ��SystemInit�е���
SET_FLASH_AREA static void ob_ram_config(void)
{
    uint32_t itcram=0,dtcram=0,itcram_ecc,dtcram0_ecc,dtcram1_ecc;
    
    ob_tcm_ecc_get(&itcram_ecc,&dtcram0_ecc,&dtcram1_ecc);
    ob_tcm_shared_ram_size_get(&itcram,&dtcram);
    
#ifndef CHIP_DEF     
    if( itcram!=512 || dtcram!=0 ||\
                itcram_ecc!=OB_ITCMECCEN_ENABLE || dtcram0_ecc!=OB_DTCM0ECCEN_ENABLE || dtcram1_ecc!=OB_DTCM1ECCEN_ENABLE)
    {
        ob_unlock();
        
        ob_tcm_shared_ram_config(OB_ITCM_SHARED_RAM_512KB, OB_DTCM_SHARED_RAM_0KB);
        ob_tcm_ecc_config(OB_ITCMECCEN_ENABLE, OB_DTCM0ECCEN_ENABLE, OB_DTCM1ECCEN_ENABLE);
        
        ob_start();
        
        ob_lock(); 

        __DSB();                                                          /* Ensure all outstanding memory accesses included
                                                                           buffered write are completed before reset */
        SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
                               (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                                SCB_AIRCR_SYSRESETREQ_Msk    );         /* Keep priority group unchanged */
        __DSB();                                                          /* Ensure completion of memory access */

        for(;;)                                                           /* wait until reset */
        {
            __NOP();
        }
    } 
#else
    if( itcram!=64 || dtcram!=64 ||\
                itcram_ecc!=OB_ITCMECCEN_ENABLE || dtcram0_ecc!=OB_DTCM0ECCEN_ENABLE || dtcram1_ecc!=OB_DTCM1ECCEN_ENABLE)
    {
        ob_unlock();
        
        ob_tcm_shared_ram_config(OB_ITCM_SHARED_RAM_64KB, OB_DTCM_SHARED_RAM_64KB);
        ob_tcm_ecc_config(OB_ITCMECCEN_ENABLE, OB_DTCM0ECCEN_ENABLE, OB_DTCM1ECCEN_ENABLE);
        
        ob_start();
        
        ob_lock(); 

        __DSB();                                                          /* Ensure all outstanding memory accesses included
                                                                           buffered write are completed before reset */
        SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
                               (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                                SCB_AIRCR_SYSRESETREQ_Msk    );         /* Keep priority group unchanged */
        __DSB();                                                          /* Ensure completion of memory access */

        for(;;)                                                           /* wait until reset */
        {
            __NOP();
        }
    }
#endif    
}

void mcu_app_jump(uint32_t jump_address)  //��ת��app����λһЩʹ�õ�����ͱ�Ҫ��MPU��λ
{
    typedef  void (*pFunction)(void);    
    __IO uint32_t delay=0;
    static uint32_t addr;
    static pFunction Jump_To_Application; 

    mpu_region_init_struct mpu_init_struct;
    mpu_region_struct_para_init(&mpu_init_struct);    
    
    addr=jump_address;

    __disable_irq();

    rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV2);
    for(delay=0;delay<0xfff;delay++);
    rcu_deinit();
    for(delay=0;delay<0xfff;delay++);    
      
    /*������λ�õ�������*/


    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    for (uint8_t i = 0; i < 8; i++)
    {
        NVIC->ICER[i]=0xFFFFFFFF;
        NVIC->ICPR[i]=0xFFFFFFFF;
    }  

    __enable_irq(); 

    /*ִ�д˴�ʱITC�������Ѿ�������ϣ�����������ֻ����ֹ�ڴ��ƻ�����ɢ���غ�ʹ��SET_RAM_CODE*/      
    /* configure the MPU attributes for ITC */
    mpu_init_struct.region_base_address = (uint32_t)(0);
    mpu_init_struct.region_size         = MPU_REGION_SIZE_512KB;
    mpu_init_struct.access_permission   = MPU_AP_FULL_ACCESS;
    mpu_init_struct.access_bufferable   = MPU_ACCESS_BUFFERABLE;
    mpu_init_struct.access_cacheable    = MPU_ACCESS_NON_CACHEABLE;
    mpu_init_struct.access_shareable    = MPU_ACCESS_NON_SHAREABLE;
    mpu_init_struct.region_number       = MPU_REGION_NUMBER5;
    mpu_init_struct.subregion_disable   = MPU_SUBREGION_ENABLE;
    mpu_init_struct.instruction_exec    = MPU_INSTRUCTION_EXEC_PERMIT;
    mpu_init_struct.tex_type            = MPU_TEX_TYPE0;
    mpu_region_config(&mpu_init_struct);
    mpu_region_enable();     

    if ( ((*(__IO uint32_t*)addr) & 0x24000000 ) == 0x24000000 || ((*(__IO uint32_t*)addr) & 0xFFF00000 ) == 0x0000 || ((*(__IO uint32_t*)addr) & 0x20000000 ) == 0x20000000) //ApplicationAddressΪ�³������ʼ��ַ�����ջ����ַ�Ƿ�Ϸ�����ջ����ַ�Ƿ�Ϊ0x2000xxxx������SRAM��
    {            
        Jump_To_Application = (pFunction) (*(__IO uint32_t*) (addr + 4));             
        nvic_vector_table_set(addr, 0);                           //�����³���ε��ж�����
        __set_MSP(*(__IO uint32_t*) addr);                        //��ʼ��APP��ջָ��
        Jump_To_Application();                                    // ����PCָ��Ϊ�³���λ�жϺ����ĵ�ַ        
    }     
}


SET_FLASH_AREA void driver_system_config(void)    
{
    ob_ram_config();    
}

#if defined(__ICCARM__)
#pragma default_function_attributes =
#endif

