]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/l2cc.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / l2cc.c
diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/l2cc.c b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/l2cc.c
new file mode 100644 (file)
index 0000000..d87677b
--- /dev/null
@@ -0,0 +1,433 @@
+/* ----------------------------------------------------------------------------\r
+ *         SAM Software Package License\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2015, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \file */\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Headers\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "chip.h"\r
+#include "peripherals/l2cc.h"\r
+#include "cortex-a/cp15.h"\r
+#include "trace.h"\r
+\r
+#include <assert.h>\r
+#include <stdbool.h>\r
+#include <string.h>\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+uint32_t l2cc_is_enabled(void)\r
+{\r
+       return ((L2CC->L2CC_CR) & L2CC_CR_L2CEN);\r
+}\r
+\r
+void l2cc_enable(void)\r
+{\r
+       L2CC->L2CC_CR |= L2CC_CR_L2CEN;\r
+       asm volatile("": : :"memory");\r
+       asm("dsb");\r
+       asm("isb");\r
+       trace_info("L2 cache is enabled\r\n");\r
+}\r
+\r
+void l2cc_disable(void)\r
+{\r
+       L2CC->L2CC_CR &= ~L2CC_CR_L2CEN;\r
+       asm volatile("": : :"memory");\r
+       asm("dsb");\r
+       asm("isb");\r
+       trace_info("L2 cache is disabled\r\n");\r
+}\r
+\r
+void l2cc_exclusive_cache(uint8_t enable)\r
+{\r
+       uint32_t cfg;\r
+       if (l2cc_is_enabled()) {\r
+               l2cc_disable();\r
+       }\r
+       cfg = L2CC->L2CC_ACR;\r
+       if (enable) {\r
+               cp15_exclusive_cache();\r
+               cfg |= L2CC_ACR_EXCC;\r
+               trace_info("L2 Exclusive mode enabled\n\r");\r
+       } else {\r
+               cp15_non_exclusive_cache();\r
+               cfg &= ~L2CC_ACR_EXCC;\r
+               trace_info("L2 Exclusive mode disabled\n\r");\r
+       }\r
+       L2CC->L2CC_ACR |= cfg;\r
+}\r
+\r
+void l2cc_config_lat_ram(struct _ram_latency_control * latencies)\r
+{\r
+       if (l2cc_is_enabled()) {\r
+               l2cc_disable();\r
+       }\r
+\r
+       L2CC->L2CC_TRCR =\r
+               (L2CC_TRCR_TSETLAT(latencies->tag.setup) |\r
+                L2CC_TRCR_TRDLAT(latencies->tag.read) |\r
+                L2CC_TRCR_TWRLAT(latencies->tag.write));\r
+       L2CC->L2CC_DRCR =\r
+               (L2CC_DRCR_DSETLAT(latencies->data.setup) |\r
+                L2CC_DRCR_DRDLAT(latencies->data.read) |\r
+                L2CC_DRCR_DWRLAT(latencies->data.write));\r
+}\r
+\r
+void l2cc_set_config(const struct _l2cc_control* cfg)\r
+{\r
+       uint32_t aux_control, debug_control, prefetch_control, power_control;\r
+\r
+       if (cfg->offset > 31) {\r
+               assert(0);\r
+       }\r
+       if ((cfg->offset > 7) && (cfg->offset < 15)) {\r
+               assert(0);\r
+       }\r
+       if ((cfg->offset > 15) && (cfg->offset < 23)) {\r
+               assert(0);\r
+       }\r
+       if ((cfg->offset > 23) && (cfg->offset < 31)) {\r
+               assert(0);\r
+       }\r
+\r
+       if (l2cc_is_enabled()) {\r
+               l2cc_disable();\r
+       }\r
+\r
+       aux_control = ((cfg->high_prior_so << 10) |\r
+                      (cfg->store_buff_dev_limit << 11) |\r
+                      (cfg->shared_attr_invalidate << 13) |\r
+                      (cfg->evt_mon_bus << 20) |\r
+                      (cfg->parity << 21) |\r
+                      (cfg->shared_attr_override << 22) |\r
+                      (L2CC_ACR_FWA(cfg->force_write_alloc)) |\r
+                      (cfg->cache_replacement << 25) |\r
+                      (cfg->non_sec_lockdown << 26) |\r
+                      (cfg->it_acces_non_sec << 27) |\r
+                      (cfg->data_prefetch << 28) |\r
+                      (cfg->instruct_prefetch << 29));\r
+\r
+       debug_control = ((cfg->no_cache_linefill << 0) |\r
+                        (cfg->no_write_back << 1));\r
+\r
+       prefetch_control = ((L2CC_PCR_OFFSET(cfg->offset << 0)) |\r
+                           (cfg->exclusive_seq_same_id << 21) |\r
+                           (cfg->incr_double_linefill << 23) |\r
+                           (cfg->prefetch_drop << 24) |\r
+                           (cfg->DLFWRDIS << 27) |\r
+                           (cfg->data_prefetch << 28) |\r
+                           (cfg->instruct_prefetch << 29) |\r
+                           (cfg->double_linefill << 30));\r
+\r
+       power_control = ((cfg->standby_mode << 0) |\r
+                        (cfg->dyn_clock_gating << 1));\r
+\r
+       L2CC->L2CC_ACR = aux_control;\r
+       L2CC->L2CC_DCR = debug_control;\r
+       L2CC->L2CC_PCR = prefetch_control;\r
+       L2CC->L2CC_POWCR = power_control;\r
+}\r
+\r
+void l2cc_data_prefetch_enable(void)\r
+{\r
+       L2CC->L2CC_PCR |= L2CC_PCR_DATPEN;\r
+}\r
+\r
+void l2cc_inst_prefetch_enable(void)\r
+{\r
+       L2CC->L2CC_PCR |= L2CC_PCR_INSPEN;\r
+}\r
+\r
+void l2cc_enable_reset_counter(uint8_t event_counter)\r
+{\r
+       assert((event_counter > 3) ? 0 : 1);\r
+       L2CC->L2CC_ECR = (L2CC_ECR_EVCEN | (event_counter << 1));\r
+}\r
+\r
+void l2cc_event_config(uint8_t event_counter, uint8_t source, uint8_t it)\r
+{\r
+       if (l2cc_is_enabled()) {\r
+               L2CC->L2CC_CR = false;\r
+       }\r
+       assert((event_counter > 1) ? 0 : 1);\r
+       if (!event_counter) {\r
+               L2CC->L2CC_ECFGR0 = (source | it);\r
+       } else {\r
+               L2CC->L2CC_ECFGR1 = (source | it);\r
+       }\r
+\r
+}\r
+\r
+uint32_t l2cc_event_counter_value(uint8_t event_counter)\r
+{\r
+       assert((event_counter > 1) ? 0 : 1);\r
+       if (!event_counter) {\r
+               return L2CC->L2CC_EVR0;\r
+       } else {\r
+               return L2CC->L2CC_EVR1;\r
+       }\r
+}\r
+\r
+void l2cc_enable_it(uint16_t sources)\r
+{\r
+       L2CC->L2CC_IMR |= sources;\r
+}\r
+\r
+void l2cc_disable_it(uint16_t sources)\r
+{\r
+       L2CC->L2CC_IMR &= (!sources);\r
+}\r
+\r
+unsigned short l2cc_it_status_raw(uint16_t sources)\r
+{\r
+       return ((L2CC->L2CC_RISR) & sources) ? 1 : 0;\r
+}\r
+\r
+uint16_t l2cc_it_status_mask(uint16_t sources)\r
+{\r
+       return ((L2CC->L2CC_MISR) & sources) ? 1 : 0;\r
+}\r
+\r
+void l2cc_it_clear(uint16_t sources)\r
+{\r
+       L2CC->L2CC_ICR |= sources;\r
+}\r
+\r
+uint8_t l2cc_poll_spniden()\r
+{\r
+       return ((L2CC->L2CC_DCR & L2CC_DCR_SPNIDEN) >> 2);\r
+}\r
+\r
+void l2cc_cache_sync()\r
+{\r
+       while ((L2CC->L2CC_CSR) & L2CC_CSR_C) ;\r
+       L2CC->L2CC_CSR = L2CC_CSR_C;\r
+       while ((L2CC->L2CC_CSR) & L2CC_CSR_C) ;\r
+}\r
+\r
+void l2cc_invalidate_pal(uint32_t phys_addr)\r
+{\r
+       static uint32_t Tag;\r
+       static uint16_t Index;\r
+       Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));\r
+       Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);\r
+       L2CC->L2CC_IPALR = (L2CC_IPALR_TAG(Tag) | L2CC_IPALR_IDX(Index) | L2CC_IPALR_C);\r
+       while ((L2CC->L2CC_IPALR) & L2CC_IPALR_C) ;\r
+}\r
+\r
+void l2cc_clean_pal(uint32_t phys_addr)\r
+{\r
+       static uint32_t Tag;\r
+       static uint16_t Index;\r
+\r
+       Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));\r
+       Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);\r
+       L2CC->L2CC_CPALR =\r
+           (L2CC_CPALR_TAG(Tag) | L2CC_CPALR_IDX(Index) | L2CC_CPALR_C);\r
+       while ((L2CC->L2CC_CPALR) & L2CC_CPALR_C) ;\r
+}\r
+\r
+void l2cc_clean_ix(uint32_t phys_addr)\r
+{\r
+       static uint32_t Tag;\r
+       static uint16_t Index;\r
+\r
+       Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));\r
+       Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);\r
+       L2CC->L2CC_CIPALR =\r
+           (L2CC_CIPALR_TAG(Tag) | L2CC_CIPALR_IDX(Index) | L2CC_CIPALR_C);\r
+       while ((L2CC->L2CC_CIPALR) & L2CC_CIPALR_C) ;\r
+}\r
+\r
+void l2cc_invalidate_way(uint8_t way)\r
+{\r
+       L2CC->L2CC_IWR = way;\r
+       while (L2CC->L2CC_IWR) ;\r
+       while (L2CC->L2CC_CSR) ;\r
+}\r
+\r
+void l2cc_clean_way(uint8_t way)\r
+{\r
+       L2CC->L2CC_CWR = way;\r
+       while (L2CC->L2CC_CWR) ;\r
+       while (L2CC->L2CC_CSR) ;\r
+}\r
+\r
+/**\r
+ * \brief Clean Invalidate cache by way\r
+ * \param way  way number\r
+ */\r
+static void l2cc_clean_invalidate_way(uint8_t way)\r
+{\r
+       L2CC->L2CC_CIWR = way;\r
+       while (L2CC->L2CC_CSR) ;\r
+}\r
+\r
+void l2cc_clean_index(uint32_t phys_addr, uint8_t way)\r
+{\r
+       static uint16_t Index;\r
+\r
+       Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);\r
+       L2CC->L2CC_CIR =\r
+           (L2CC_CIR_IDX(Index) | L2CC_CIR_WAY(way) | L2CC_CIR_C);\r
+       while ((L2CC->L2CC_CIR) & L2CC_CIR_C) ;\r
+}\r
+\r
+void l2cc_clean_invalidate_index(uint32_t phys_addr, uint8_t way)\r
+{\r
+       static uint16_t Index;\r
+\r
+       (void) way;\r
+       Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);\r
+       L2CC->L2CC_CIIR =\r
+           (L2CC_CIIR_IDX(Index) | L2CC_CIIR_WAY(Index) | L2CC_CIIR_C);\r
+       while ((L2CC->L2CC_CIIR) & L2CC_CIIR_C) ;\r
+}\r
+\r
+void l2cc_data_lockdown(uint8_t way)\r
+{\r
+       L2CC->L2CC_DLKR = way;\r
+       while (L2CC->L2CC_CSR) ;\r
+}\r
+\r
+void l2cc_instruction_lockdown(uint8_t way)\r
+{\r
+       L2CC->L2CC_ILKR = way;\r
+       while (L2CC->L2CC_CSR) ;\r
+}\r
+\r
+static void l2cc_clean(void)\r
+{\r
+       // Clean of L1; This is broadcast within the cluster\r
+       cp15_dcache_clean();\r
+       if (l2cc_is_enabled()) {\r
+               // forces the address out past level 2\r
+               l2cc_clean_way(0xFF);\r
+               // Ensures completion of the L2 clean\r
+               l2cc_cache_sync();\r
+       }\r
+}\r
+\r
+static void l2cc_invalidate(void)\r
+{\r
+       if (l2cc_is_enabled()) {\r
+               // forces the address out past level 2\r
+               l2cc_invalidate_way(0xFF);\r
+               // Ensures completion of the L2 inval\r
+               l2cc_cache_sync();\r
+       }\r
+       // Inval of L1; This is broadcast within the cluster\r
+       cp15_dcache_invalidate();\r
+}\r
+\r
+static void l2cc_clean_invalidate(void)\r
+{\r
+       /* Clean of L1; This is broadcast within the cluster */\r
+       cp15_dcache_clean();\r
+\r
+       if (l2cc_is_enabled()) {\r
+               /* forces the address out past level 2 */\r
+               l2cc_clean_invalidate_way(0xFF);\r
+               /* Ensures completion of the L2 inval */\r
+               l2cc_cache_sync();\r
+       }\r
+\r
+       /* Inval of L1; This is broadcast within the cluster */\r
+       cp15_dcache_invalidate();\r
+}\r
+\r
+void l2cc_cache_maintenance(enum _maint_op maintenance)\r
+{\r
+       switch (maintenance) {\r
+               case L2CC_DCACHE_CLEAN:\r
+                       l2cc_clean();\r
+                       break;\r
+               case L2CC_DCACHE_INVAL:\r
+                       l2cc_invalidate();\r
+                       break;\r
+               case L2CC_DCACHE_FLUSH:\r
+                       l2cc_clean_invalidate();\r
+                       break;\r
+       }\r
+}\r
+\r
+void l2cc_invalidate_region(uint32_t start, uint32_t end)\r
+{\r
+       assert(start < end);\r
+       uint32_t current = start & ~0x1fUL;\r
+       if (l2cc_is_enabled()) {\r
+               while (current <= end) {\r
+                       l2cc_invalidate_pal(current);\r
+                       current += 32;\r
+               }\r
+               l2cc_invalidate_pal(end);\r
+       }\r
+       cp15_invalidate_dcache_for_dma(start, end);\r
+}\r
+\r
+void l2cc_clean_region(uint32_t start, uint32_t end)\r
+{\r
+       assert(start < end);\r
+       uint32_t current = start & ~0x1fUL;\r
+       if (l2cc_is_enabled()) {\r
+               while (current <= end) {\r
+                       l2cc_clean_pal(current);\r
+                       current += 32;\r
+               }\r
+               l2cc_clean_pal(end);\r
+       }\r
+       cp15_clean_dcache_for_dma(start, end);\r
+}\r
+\r
+void l2cc_configure(const struct _l2cc_control* cfg)\r
+{\r
+       l2cc_event_config(0, L2CC_ECFGR0_ESRC_SRC_DRHIT,\r
+                         L2CC_ECFGR0_EIGEN_INT_DIS);\r
+       l2cc_event_config(1, L2CC_ECFGR0_ESRC_SRC_DWHIT,\r
+                         L2CC_ECFGR0_EIGEN_INT_DIS);\r
+\r
+       l2cc_enable_reset_counter(L2CC_RESET_BOTH_COUNTER);\r
+       l2cc_set_config(cfg);\r
+       /* Enable Prefetch */\r
+       l2cc_inst_prefetch_enable();\r
+       l2cc_data_prefetch_enable();\r
+       /* Invalidate whole L2CC */\r
+       l2cc_invalidate_way(0xFF);\r
+       /* Disable all L2CC Interrupt */\r
+       l2cc_disable_it(0x1FF);\r
+       /* Clear all L2CC Interrupt */\r
+       l2cc_it_clear(0xFF);\r
+       l2cc_exclusive_cache(true);\r
+       l2cc_enable();\r
+}\r