blob: bf54ffc599b86b25b55e75bd32cb3ccfe52ba824 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/**
* \brief Check if Level 2 cache is enable.
*/
unsigned int L2CC_IsEnabled(L2cc* pL2CC)
{
return ((pL2CC->L2CC_CR) & L2CC_CR_L2CEN);
}
/**
* \brief Enable Level 2 cache.
*/
void L2CC_Enable(L2cc* pL2CC)
{
pL2CC->L2CC_CR |= L2CC_CR_L2CEN;
TRACE_INFO("L2 cache is enabled");
}
/**
* \brief Disbale Level 2 cache.
*/
void L2CC_Disable(L2cc* pL2CC)
{
pL2CC->L2CC_CR &= (!L2CC_CR_L2CEN);
TRACE_INFO("L2 cache is Disabled");
}
/**
* \brief Configures Level 2 cache as exclusive cache.
*/
void L2CC_ExclusiveCache(L2cc* pL2CC, uint8_t Enable)
{
uint32_t Aux_Cfg;
if(L2CC_IsEnabled(pL2CC))
{
pL2CC->L2CC_CR = DISABLE;
}
Aux_Cfg = pL2CC->L2CC_ACR;
if(Enable)
{
CP15_ExclusiveCache();
Aux_Cfg |= L2CC_ACR_EXCC;
TRACE_INFO("L2 Exclusive mode Enabled\n\r");
}
else
{
CP15_NonExclusiveCache();
Aux_Cfg &= ~L2CC_ACR_EXCC;
TRACE_INFO("L2 Exclusive mode Disabled\n\r");
}
pL2CC->L2CC_ACR |= Aux_Cfg;
}
/**
* \brief Configures Level 2 cache RAM Latency (Tag and Data).
* \param pLat Structure containing RAM Tag and Data latencies
*/
void L2CC_ConfigLatRAM(L2cc* pL2CC, RAMLatencyControl *pLat)
{
if(L2CC_IsEnabled(pL2CC))
{
pL2CC->L2CC_CR = DISABLE;
}
pL2CC->L2CC_TRCR = (L2CC_TRCR_TSETLAT(pLat->TagRAM.SetupLAT) | L2CC_TRCR_TRDLAT(pLat->TagRAM.ReadLAT) | L2CC_TRCR_TWRLAT(pLat->TagRAM.WriteLAT));
pL2CC->L2CC_DRCR = (L2CC_DRCR_DSETLAT(pLat->DataRAM.SetupLAT) | L2CC_DRCR_DRDLAT(pLat->DataRAM.ReadLAT) | L2CC_DRCR_DWRLAT(pLat->DataRAM.WriteLAT));
}
/**
* \brief Configures Level 2 cache.
* \param L2cc_Config Configuration values to put in Auxiliary, prefetch, debug and powercontrol registers
*/
void L2CC_Config(L2cc* pL2CC, L2CC_Control L2cc_Config)
{
uint32_t AuxiliaryControl, DebugControl, PrefetchControl, PowerControl;
if(L2cc_Config.OFFSET_Val >31)
{
assert(0);
}
if((L2cc_Config.OFFSET_Val >7) && (L2cc_Config.OFFSET_Val <15))
{
assert(0);
}
if((L2cc_Config.OFFSET_Val >15) && (L2cc_Config.OFFSET_Val <23))
{
assert(0);
}
if((L2cc_Config.OFFSET_Val >23) && (L2cc_Config.OFFSET_Val <31))
{
assert(0);
}
// if( ((L2cc_Config.IDLEN_Val==1) || (L2cc_Config.DLFWRDIS_Val==0)) && L2cc_Config.DLEN_Val==0)
// {
// TRACE_ERROR(" DLEN is not enabled for Double Line fill");
// assert(0);
// }
if(L2CC_IsEnabled(pL2CC))
{
pL2CC->L2CC_CR = DISABLE;
}
AuxiliaryControl = ((L2cc_Config.HPSO_Val << 10) |
(L2cc_Config.SBDLE_Val << 11) |
(L2cc_Config.SAIE_Val << 13) |
(L2cc_Config.EMBEN_Val << 20) |
(L2cc_Config.PEN_Val << 21) |
(L2cc_Config.SAOEN_Val << 22) |
(L2CC_ACR_FWA(L2cc_Config.FWA_Val)) |
(L2cc_Config.CRPOL_Val << 25) |
(L2cc_Config.NSLEN_Val << 26) |
(L2cc_Config.NSIAC_Val << 27) |
(L2cc_Config.DPEN_Val << 28) |
(L2cc_Config.IPEN_Val << 29) );
DebugControl = ((L2cc_Config.DCL_Val << 0) |
(L2cc_Config.DWB_Val << 1) );
PrefetchControl = ((L2cc_Config.OFFSET_Val << 0) |
(L2cc_Config.NSIDEN_Val << 21) |
(L2cc_Config.IDLEN_Val << 23) |
(L2cc_Config.PDEN_Val << 24) |
(L2cc_Config.DLFWRDIS_Val << 27) |
(L2cc_Config.DPEN_Val << 28) |
(L2cc_Config.IPEN_Val << 29) |
(L2cc_Config.DLEN_Val << 30));
PowerControl = ((L2cc_Config.DCL_Val << 0) |
(L2cc_Config.DWB_Val << 1));
pL2CC->L2CC_ACR = AuxiliaryControl;
pL2CC->L2CC_DCR = DebugControl;
pL2CC->L2CC_PCR = PrefetchControl;
pL2CC->L2CC_POWCR = PowerControl;
}
/**
* \brief Enables Data prefetch on L2
*/
void L2CC_DataPrefetchEnable(L2cc* pL2CC )
{
pL2CC->L2CC_PCR |= L2CC_PCR_DATPEN;
}
/**
* \brief Enables instruction prefetch on L2
*/
void L2CC_InstPrefetchEnable(L2cc* pL2CC )
{
pL2CC->L2CC_PCR |= L2CC_PCR_INSPEN;
}
/**
* \brief Enables instruction prefetch on L2
*/
void L2CC_EnableResetCounter(L2cc* pL2CC , uint8_t EvenetCounter)
{
assert((EvenetCounter>3)?0:1);
pL2CC->L2CC_ECR = (L2CC_ECR_EVCEN | (EvenetCounter << 1 ));
}
/**
* \brief Configures Event of Level 2 cache.
* \param EventCounter Eventcounter 1 or 0
* \param Source Event Genration source
* \param IntGen Event Counter Interrupt Generation condition
*/
void L2CC_EventConfig(L2cc* pL2CC, uint8_t EventCounter, uint8_t Source, uint8_t IntGen)
{
if(L2CC_IsEnabled(pL2CC))
{
pL2CC->L2CC_CR = DISABLE;
}
assert((EventCounter > 1)?0:1);
if(!EventCounter)
{
pL2CC->L2CC_ECFGR0 = (Source | IntGen);
}
else
{
pL2CC->L2CC_ECFGR1 = (Source | IntGen );
}
}
/**
* \brief Reads Eventcounter value.
* \param EventCounter choose Eventcounter 1 or 0
*/
unsigned int L2CC_EventCounterValue(L2cc* pL2CC, uint8_t EventCounter)
{
assert((EventCounter > 1)?0:1);
if(!EventCounter)
{
return pL2CC->L2CC_EVR0;
}
else
{
return pL2CC->L2CC_EVR1;
}
}
/**
* \brief Enable interrupts
* \param ITSource Interrupt source
*/
void L2CC_EnableIT(L2cc* pL2CC, uint16_t ITSource)
{
pL2CC->L2CC_IMR |= ITSource;
}
/**
* \brief Disable interrupts
* \param ITSource Interrupt source
*/
void L2CC_DisableIT(L2cc* pL2CC, uint16_t ITSource)
{
pL2CC->L2CC_IMR &= (!ITSource);
}
/**
* \brief Enabled interrupt's raw status
* \param ITSource Interrupt source
*/
unsigned short L2CC_ITStatusRaw(L2cc* pL2CC, uint16_t ITSource)
{
return ((pL2CC->L2CC_RISR) & ITSource)?1:0;
}
/**
* \brief Status of masked interrupts
* \param ITSource Interrupt source
*/
unsigned short L2CC_ITStatusMask(L2cc* pL2CC, uint16_t ITSource)
{
return ((pL2CC->L2CC_MISR) & ITSource)?1:0;
}
/**
* \brief Clear interrupts
* \param ITSource Interrupt source
*/
void L2CC_ITClear(L2cc* pL2CC, uint16_t ITSource)
{
pL2CC->L2CC_ICR |= ITSource;
}
/**
* \brief Poll SPNIDEN signal
*/
uint8_t L2CC_PollSPNIDEN(L2cc* pL2CC)
{
return ((pL2CC->L2CC_DCR & L2CC_DCR_SPNIDEN) >> 2);
}
/**
* \brief Synchronizes the L2 cache
*/
void L2CC_CacheSync(L2cc* pL2CC)
{
while((pL2CC->L2CC_CSR) & L2CC_CSR_C);
pL2CC->L2CC_CSR = L2CC_CSR_C;
while((pL2CC->L2CC_CSR) & L2CC_CSR_C);
}
/**
* \brief Invalidate cache by Physical addersse
* \param P_Address Physical addresse
*/
void L2CC_InvalidatePAL(L2cc* pL2CC, uint32_t P_Address)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (P_Address >> (OFFSET_BIT + INDEX_BIT));
Index = (P_Address >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
pL2CC->L2CC_IPALR = (L2CC_IPALR_TAG(Tag) | L2CC_IPALR_IDX(Index) | L2CC_IPALR_C);
while((pL2CC->L2CC_IPALR) & L2CC_IPALR_C);
}
/**
* \brief Clean cache by Physical addersse
* \param P_Address Physical addresse
*/
void L2CC_CleanPAL(L2cc* pL2CC, uint32_t P_Address)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (P_Address >> (OFFSET_BIT + INDEX_BIT));
Index = (P_Address >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
pL2CC->L2CC_CPALR = (L2CC_CPALR_TAG(Tag) | L2CC_CPALR_IDX(Index) | L2CC_CPALR_C);
while((pL2CC->L2CC_CPALR) & L2CC_CPALR_C);
}
/**
* \brief Clean index cache by Physical addersse
* \param P_Address Physical addresse
*/
void L2CC_CleanIx(L2cc* pL2CC, uint32_t P_Address)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (P_Address >> (OFFSET_BIT + INDEX_BIT));
Index = (P_Address >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
pL2CC->L2CC_CIPALR = (L2CC_CIPALR_TAG(Tag) | L2CC_CIPALR_IDX(Index) | L2CC_CIPALR_C);
while((pL2CC->L2CC_CIPALR) & L2CC_CIPALR_C);
}
/**
* \brief Invalidate cache by way
* \param Way Way number
*/
void L2CC_InvalidateWay(L2cc* pL2CC, uint8_t Way)
{
pL2CC->L2CC_IWR = Way;
while(pL2CC->L2CC_IWR);
while(pL2CC->L2CC_CSR);
}
/**
* \brief Clean cache by way
* \param Way Way number
*/
void L2CC_CleanWay(L2cc* pL2CC, uint8_t Way)
{
pL2CC->L2CC_CWR = Way;
while(pL2CC->L2CC_CWR);
while(pL2CC->L2CC_CSR);
}
/**
* \brief Clean Invalidate cache by way
* \param Way Way number
*/
static void L2CC_CleanInvalidateWay(L2cc* pL2CC, uint8_t Way)
{
pL2CC->L2CC_CIWR = Way;
while(pL2CC->L2CC_CSR);
}
/**
* \brief Clean cache by Index
* \param P_Address Physical addresse
* \param Way Way number
*/
void L2CC_CleanIndex(L2cc* pL2CC, uint32_t P_Address, uint8_t Way)
{
static uint16_t Index;
Index = (P_Address >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
pL2CC->L2CC_CIR = (L2CC_CIR_IDX(Index) | L2CC_CIR_WAY(Way) | L2CC_CIR_C);
while((pL2CC->L2CC_CIR) & L2CC_CIR_C);
}
/**
* \brief Clean Invalidate cache by index
* \param P_Address Physical addresse
* \param Way Way number
*/
void L2CC_CleanInvalidateIndex(L2cc* pL2CC, uint32_t P_Address, uint8_t Way)
{
static uint16_t Index;
Index = (P_Address >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
pL2CC->L2CC_CIIR = (L2CC_CIIR_IDX(Index) | L2CC_CIIR_WAY(Index) | L2CC_CIIR_C);
while((pL2CC->L2CC_CIIR) & L2CC_CIIR_C);
}
/**
* \brief cache Data lockdown
* \param Way Way number
*/
void L2CC_DataLockdown(L2cc* pL2CC, uint8_t Way)
{
pL2CC->L2CC_DLKR = Way;
while(pL2CC->L2CC_CSR);
}
/**
* \brief cache instruction lockdown
* \param Way Way number
*/
void L2CC_InstructionLockdown(L2cc* pL2CC, uint8_t Way)
{
pL2CC->L2CC_ILKR = Way;
while(pL2CC->L2CC_CSR);
}
static void L2CC_Clean(void)
{
CP15_CacheClean(CP15_DCache); // Clean of L1; This is broadcast within the cluster
L2CC_CleanWay(L2CC, 0xFF); // forces the address out past level 2
L2CC_CacheSync(L2CC); // Ensures completion of the L2 clean
}
static void L2CC_Invalidate(void)
{
L2CC_InvalidateWay(L2CC, 0xFF); // forces the address out past level 2
L2CC_CacheSync(L2CC); // Ensures completion of the L2 inval
CP15_CacheInvalidate(CP15_DCache); // Inval of L1; This is broadcast within the cluster
}
static void L2CC_CleanInvalidate(void)
{
CP15_CacheClean(CP15_DCache); // Clean of L1; This is broadcast within the cluster
L2CC_CleanInvalidateWay(L2CC, 0xFF); // forces the address out past level 2
L2CC_CacheSync(L2CC); // Ensures completion of the L2 inval
CP15_CacheInvalidate(CP15_DCache); // Inval of L1; This is broadcast within the cluster
}
void L2CC_CacheMaintenance(uint8_t Maint_Op)
{
switch(Maint_Op) {
case DCACHE_CLEAN:
L2CC_Clean();
break;
case DCACHE_INVAL:
L2CC_Invalidate();
break;
case DCACHE_FLUSH:
L2CC_CleanInvalidate();
break;
}
}
/**
* \brief Enable level two cache controller (L2CC)
*/
void Enable_L2CC(void)
{
L2CC_Control L2Config;
/*****1. configure L2CC ************/
L2Config.IPEN_Val = ENABLE; // Instruction prefetch enable
L2Config.DPEN_Val = ENABLE; // Data prefetch enable
L2Config.DLEN_Val = ENABLE;
L2Config.IDLEN_Val = ENABLE;
//L2Config.DWB_Val = ENABLE; // Disable Write back (enables write through, Use this setting if DDR2 mem is not write-back)
L2Config.FWA_Val = FWA_NO_ALLOCATE;
L2Config.OFFSET_Val= 31;
L2Config.PDEN_Val= ENABLE;
L2Config.STBYEN_Val= ENABLE;
L2Config.DCKGATEN_Val= ENABLE;
L2CC_EventConfig(L2CC, 0, L2CC_ECFGR0_ESRC_SRC_DRHIT, L2CC_ECFGR0_EIGEN_INT_DIS);
L2CC_EventConfig(L2CC, 1, L2CC_ECFGR0_ESRC_SRC_DWHIT, L2CC_ECFGR0_EIGEN_INT_DIS);
L2CC_EnableResetCounter(L2CC, RESET_BOTH_COUNTER);
L2CC_Config(L2CC, L2Config);
/* Enable Prefetch */
L2CC_InstPrefetchEnable(L2CC );
L2CC_DataPrefetchEnable(L2CC );
/*2. Inavlidate whole L2C ***********/
L2CC_InvalidateWay(L2CC, 0xFF);
/*3. Diable all L2C Interrupt ***********/
L2CC_DisableIT(L2CC, 0x1FF);
/*4. Clear all L2C Interrupt ***********/
L2CC_ITClear(L2CC, 0);
L2CC_ExclusiveCache(L2CC, ENABLE);
L2CC_Enable(L2CC);
}