/** * \file * * \brief Generic CMCC(Cortex M Cache Controller) related functionality. * * Copyright (c)2018 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * Subject to your compliance with these terms, you may use Microchip * software and any derivatives exclusively with Microchip products. * It is your responsibility to comply with third party license terms applicable * to your use of third party software (including open source software) that * may accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * \asf_license_stop * */ /* * Support and FAQ: visit Microchip Support */ #include #include #include /** * \brief Initialize Cache Module * * This function does low level cache configuration. * * \return initialize status */ int32_t _cmcc_init(void) { int32_t return_value; _cmcc_disable(CMCC); if (_is_cache_disabled(CMCC)) { hri_cmcc_write_CFG_reg( CMCC, (CMCC_CFG_CSIZESW(CONF_CMCC_CACHE_SIZE) | (CONF_CMCC_DATA_CACHE_DISABLE << CMCC_CFG_DCDIS_Pos) | (CONF_CMCC_INST_CACHE_DISABLE << CMCC_CFG_ICDIS_Pos) | (CONF_CMCC_CLK_GATING_DISABLE))); _cmcc_enable(CMCC); return_value = _is_cache_enabled(CMCC) == true ? ERR_NONE : ERR_FAILURE; } else { return_value = ERR_NOT_INITIALIZED; } return return_value; } /** * \brief Configure CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] cache configuration structure pointer * * \return status of operation */ int32_t _cmcc_configure(const void *hw, struct _cache_cfg *cache_ctrl) { int32_t return_value; _cmcc_disable(hw); if (_is_cache_disabled(hw)) { hri_cmcc_write_CFG_reg( hw, (CMCC_CFG_CSIZESW(cache_ctrl->cache_size) | (cache_ctrl->data_cache_disable << CMCC_CFG_DCDIS_Pos) | (cache_ctrl->inst_cache_disable << CMCC_CFG_ICDIS_Pos) | (cache_ctrl->gclk_gate_disable))); return_value = ERR_NONE; } else { return_value = ERR_NOT_INITIALIZED; } return return_value; } /** * \brief Enable data cache in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] boolean 1 -> Enable the data cache, 0 -> disable the data cache * * \return status of operation */ int32_t _cmcc_enable_data_cache(const void *hw, bool value) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_CFG_reg(hw); tmp &= ~CMCC_CFG_DCDIS; tmp |= ((!value) << CMCC_CFG_DCDIS_Pos); ret = _cmcc_disable(hw); hri_cmcc_write_CFG_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Enable instruction cache in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] boolean 1 -> Enable the inst cache, 0 -> disable the inst cache * * \return status of operation */ int32_t _cmcc_enable_inst_cache(const void *hw, bool value) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_CFG_reg(hw); tmp &= ~CMCC_CFG_ICDIS; tmp |= ((!value) << CMCC_CFG_ICDIS_Pos); ret = _cmcc_disable(hw); hri_cmcc_write_CFG_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Enable clock gating in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] boolean 1 -> Enable the clock gate, 0 -> disable the clock gate * * \return status of operation */ int32_t _cmcc_enable_clock_gating(const void *hw, bool value) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_CFG_reg(hw); tmp |= value; ret = _cmcc_disable(hw); hri_cmcc_write_CFG_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Configure the cache size in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] element from cache size configuration enumerator * 0->1K, 1->2K, 2->4K(default) * * \return status of operation */ int32_t _cmcc_configure_cache_size(const void *hw, enum conf_cache_size size) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_CFG_reg(hw); tmp &= (~CMCC_CFG_CSIZESW_Msk); tmp |= (size << CMCC_CFG_CSIZESW_Pos); ret = _cmcc_disable(hw); hri_cmcc_write_CFG_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Lock the mentioned WAY in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] element from "way_num_index" enumerator * * \return status of operation */ int32_t _cmcc_lock_way(const void *hw, enum way_num_index num) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_LCKWAY_reg(hw); tmp |= CMCC_LCKWAY_LCKWAY(num); ret = _cmcc_disable(hw); hri_cmcc_write_LCKWAY_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Unlock the mentioned WAY in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] element from "way_num_index" enumerator * * \return status of operation */ int32_t _cmcc_unlock_way(const void *hw, enum way_num_index num) { uint32_t tmp; int32_t ret; tmp = hri_cmcc_read_LCKWAY_reg(hw); tmp &= (~CMCC_LCKWAY_LCKWAY(num)); ret = _cmcc_disable(hw); hri_cmcc_write_LCKWAY_reg(hw, tmp); ret = _cmcc_enable(hw); return ret; } /** * \brief Invalidate the mentioned cache line in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] element from "way_num" enumerator (valid arg is 0-3) * \param[in] line number (valid arg is 0-63 as each way will have 64 lines) * * \return status of operation */ int32_t _cmcc_invalidate_by_line(const void *hw, uint8_t way_num, uint8_t line_num) { int32_t return_value; if ((way_num < CMCC_WAY_NOS) && (line_num < CMCC_LINE_NOS)) { _cmcc_disable(hw); while (!(_is_cache_disabled(hw))) ; hri_cmcc_write_MAINT1_reg(hw, (CMCC_MAINT1_INDEX(line_num) | CMCC_MAINT1_WAY(way_num))); return_value = ERR_NONE; } else { return_value = ERR_INVALID_ARG; } return return_value; } /** * \brief Invalidate entire cache entries in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * * \return status of operation */ int32_t _cmcc_invalidate_all(const void *hw) { int32_t return_value; _cmcc_disable(hw); if (_is_cache_disabled(hw)) { hri_cmcc_write_MAINT0_reg(hw, CMCC_MAINT0_INVALL); return_value = ERR_NONE; } else { return_value = ERR_FAILURE; } return return_value; } /** * \brief Configure cache monitor in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * \param[in] element from cache monitor configurations enumerator * * \return status of operation */ int32_t _cmcc_configure_monitor(const void *hw, enum conf_cache_monitor monitor_cfg) { hri_cmcc_write_MCFG_reg(hw, CMCC_MCFG_MODE(monitor_cfg)); return ERR_NONE; } /** * \brief Enable cache monitor in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * * \return status of operation */ int32_t _cmcc_enable_monitor(const void *hw) { hri_cmcc_write_MEN_reg(hw, CMCC_MEN_MENABLE); return ERR_NONE; } /** * \brief Disable cache monitor in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * * \return status of operation */ int32_t _cmcc_disable_monitor(const void *hw) { hri_cmcc_write_MEN_reg(hw, (CMCC_MONITOR_DISABLE << CMCC_MEN_MENABLE_Pos)); return ERR_NONE; } /** * \brief Reset cache monitor in CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * * \return status of operation */ int32_t _cmcc_reset_monitor(const void *hw) { hri_cmcc_write_MCTRL_reg(hw, CMCC_MCTRL_SWRST); return ERR_NONE; } /** * \brief Get cache monitor event counter value from CMCC module * * \param[in] pointer pointing to the starting address of CMCC module * * \return event counter value */ uint32_t _cmcc_get_monitor_event_count(const void *hw) { return hri_cmcc_read_MSR_reg(hw); }