--- /dev/null
+/*****************************************************************************\r
+* © 2015 Microchip Technology Inc. and its subsidiaries.\r
+* You may use this software and any derivatives exclusively with\r
+* Microchip products.\r
+* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS".\r
+* NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,\r
+* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,\r
+* AND FITNESS FOR A PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP\r
+* PRODUCTS, COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.\r
+* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,\r
+* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND\r
+* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS\r
+* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.\r
+* TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL\r
+* CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF\r
+* FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.\r
+* MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE\r
+* OF THESE TERMS.\r
+******************************************************************************\r
+\r
+Version Control Information (Perforce)\r
+******************************************************************************\r
+$Revision: #1 $ \r
+$DateTime: 2016/09/22 08:03:49 $ \r
+$Author: pramans $\r
+Last Change: Renamed ecia_init to interrupt_init\r
+******************************************************************************/\r
+/** @file interrupt_api.c\r
+* \brief Interrupt APIs Source File\r
+* \author jvasanth\r
+* \r
+* This file implements the Interrupt Source file \r
+******************************************************************************/\r
+\r
+/** @defgroup Interrupt\r
+ * @{\r
+ */\r
+ \r
+#include "common_lib.h"\r
+#include "interrupt.h"\r
+#include "..\pcr\pcr.h"\r
+\r
+static uint8_t interrupt_is_girq_direct(uint8_t girq_num);\r
+\r
+/* ------------------------------------------------------------------------------- */\r
+/* NVIC,ECIA Routing Policy for Direct Mode */\r
+/* ------------------------------------------------------------------------------- */\r
+/* In Direct Mode, some interrupts could be configured to be used as aggregated.\r
+ * Configuration:\r
+ * 1. Always set ECS Interrupt Direct enable bit. \r
+ * 2. If GIRQn aggregated set Block Enable bit.\r
+ * 3. If GIRQn direct then clear Block Enable bit and enable individual NVIC inputs.\r
+ * Switching issues:\r
+ * Aggregate enable/disable requires set/clear single GIRQn bit in GIRQ Block En/Clr registers.\r
+ * Also requires set/clear of individual NVIC Enables.\r
+ * \r
+ * Note: interrupt_is_girq_direct() internal function uses this policy to detect \r
+ * if any interrupt is configured as direct or aggregated\r
+*/\r
+\r
+/** Initialize EC Interrupt Aggregator\r
+ * @param mode 1 - Direct Map mode, 0 - Fully Aggregated Mode \r
+ * @param girq_bitmask - BitMask of GIRQ to be configured as aggregated \r
+ * This parameter is only applicable in direct mode.\r
+ * @note All GPIO's and wake capable sources are always \r
+ * aggregated! GPIO's interrupts will still work in direct mode.\r
+ * Block wakes are not be routed to the processor in direct \r
+ * mode. \r
+ * Note2: This function disables and enables global interrupt \r
+ */\r
+void interrupt_init(uint8_t mode, uint32_t girq_bitmask)\r
+{\r
+ uint32_t isave;\r
+ \r
+ isave = __get_PRIMASK();\r
+ __disable_irq();\r
+ \r
+ //Clear Sleep for Interrupt block\r
+ pcr_sleep_enable(PCR_INT, 0);\r
+\r
+ interrupt_mode_set(mode);\r
+\r
+ p_interrupt_ecia_girqs_enable_reset(); \r
+ \r
+ p_interrupt_nvic_enpend_clr();\r
+ \r
+ p_interrupt_nvic_priorities_default_set();\r
+ \r
+ if (mode)\r
+ {//If direct mode, enable specific GIRQs to be aggregated\r
+ p_interrupt_ecia_block_enable_bitmask_set(girq_bitmask);\r
+ }\r
+ \r
+ if (!isave) {\r
+ __enable_irq();\r
+ }\r
+}\r
+\r
+/** Set interrupt routing mode to aggregated or direct. \r
+ * @param mode 1 = Direct (except GPIO & wake), 0 = All Aggregated \r
+ * @note In direct mode, one could enable certain GIRQs as aggregated using \r
+ * p_interrupt_ecia_block_enable_set function\r
+ */\r
+void interrupt_mode_set(uint8_t mode)\r
+{\r
+ if (mode) \r
+ {\r
+ p_interrupt_ecia_block_enable_all_clr(); \r
+ } \r
+ else \r
+ {\r
+ p_interrupt_ecia_block_enable_all_set(); \r
+ }\r
+ \r
+ p_interrupt_control_set(mode);\r
+}\r
+\r
+/** Clears all individual interrupts Enables and Source in ECIA,\r
+ * and Clears all NVIC external enables and pending bits \r
+ */\r
+void interrupt_reset(void)\r
+{ \r
+ p_interrupt_ecia_girqs_enable_reset();\r
+ p_interrupt_ecia_girqs_source_reset(); \r
+\r
+ p_interrupt_nvic_enpend_clr();\r
+}\r
+\r
+/** Enables interrupt for a device \r
+ * @param dev_iroute - source IROUTING information \r
+ * @note This function disables and enables global interrupt \r
+ */\r
+void interrupt_device_enable(uint32_t dev_iroute)\r
+{\r
+ uint32_t isave;\r
+ IRQn_Type nvic_num;\r
+ uint8_t girq_num;\r
+ uint8_t ia_bitpos;\r
+ \r
+ girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
+ ia_bitpos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu; \r
+ \r
+ if (interrupt_is_girq_direct(girq_num)) \r
+ { // GIRQ is hooked direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ } \r
+ else \r
+ { // GIRQ is aggregated \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ isave = __get_PRIMASK();\r
+ __disable_irq();\r
+\r
+ NVIC_EnableIRQ(nvic_num);\r
+ p_interrupt_ecia_girq_enable_set(girq_num, ia_bitpos); \r
+ __DSB(); \r
+\r
+ if (!isave) {\r
+ __enable_irq();\r
+ }\r
+}\r
+\r
+\r
+/** Disables interrupt for a device\r
+ * @param dev_iroute - source IROUTING information \r
+ * @note This function disables and enables global interrupt \r
+ */\r
+void interrupt_device_disable(uint32_t dev_iroute)\r
+{\r
+ uint32_t isave;\r
+ IRQn_Type nvic_num;\r
+ uint8_t girq_num;\r
+ uint8_t ia_bitpos;\r
+\r
+ girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
+ ia_bitpos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu; \r
+ \r
+ isave = __get_PRIMASK();\r
+ __disable_irq();\r
+ \r
+ if (interrupt_is_girq_direct(girq_num)) \r
+ { // GIRQ is hooked direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ NVIC_DisableIRQ(nvic_num);\r
+ } \r
+ \r
+ p_interrupt_ecia_girq_enable_clr(girq_num, ia_bitpos); \r
+ __DSB(); \r
+\r
+ if (!isave) {\r
+ __enable_irq();\r
+ }\r
+}\r
+\r
+/** ecia_is_girq_direct - Return true if GIRQn sources can be directly \r
+ * connected to the NVIC - based on ECS->INTERRUPT_CONTROL and GIRQ block enable\r
+ * @param girq_num - enum MEC_GIRQ_IDS\r
+ * @return 1 if GIRQn sources can be directly routed to the NVIC, else 0\r
+ */\r
+static uint8_t interrupt_is_girq_direct(uint8_t girq_num)\r
+{ \r
+ uint32_t bpos;\r
+ uint8_t retVal;\r
+ uint8_t girq_block_enabled;\r
+ \r
+ retVal = 0;\r
+ \r
+ bpos = (girq_num & 0x1Fu) + 8u;\r
+ \r
+ if ((ECIA_GIRQ_DIRECT_BITMAP) & (1ul << bpos)) \r
+ { \r
+ if (p_interrupt_control_get()) \r
+ {// direct NVIC enabled\r
+ \r
+ girq_block_enabled = p_interrupt_ecia_block_enable_get(girq_num);\r
+ \r
+ if (!girq_block_enabled)\r
+ {\r
+ retVal = 1;\r
+ }\r
+ }\r
+ }\r
+ return retVal;\r
+}\r
+\r
+\r
+/* ------------------------------------------------------------------------------- */\r
+/* ECIA APIs using device IROUTE() as input */ \r
+/* ------------------------------------------------------------------------------- */\r
+\r
+/** Clear Source in the ECIA for the device \r
+ * @param devi - device IROUTING value \r
+ */\r
+void interrupt_device_ecia_source_clear(const uint32_t dev_iroute)\r
+{ \r
+ uint8_t girq_num;\r
+ uint8_t ia_bit_pos;\r
+ \r
+ girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
+ ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu; \r
+ \r
+ p_interrupt_ecia_girq_source_clr(girq_num, ia_bit_pos); \r
+ __DSB();\r
+}\r
+\r
+/** Get the Source bit in the ECIA for the device \r
+ * @param devi - device IROUTING value \r
+ * @return 0 if source bit not set; else non-zero value\r
+ */\r
+uint32_t interrupt_device_ecia_source_get(const uint32_t dev_iroute)\r
+{ \r
+ uint8_t girq_num;\r
+ uint8_t ia_bit_pos;\r
+ uint8_t retVal;\r
+ \r
+ girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
+ ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu; \r
+ \r
+ retVal = p_interrupt_ecia_girq_source_get(girq_num, ia_bit_pos); \r
+ return retVal;\r
+}\r
+\r
+/** Get the Result bit in the ECIA for the device \r
+ * @param devi - device IROUTING value \r
+ * @return 0 if result bit not set; else non-zero value\r
+ */\r
+uint32_t interrupt_device_ecia_result_get(const uint32_t dev_iroute)\r
+{ \r
+ uint8_t girq_num;\r
+ uint8_t ia_bit_pos;\r
+ uint8_t retVal;\r
+ \r
+ girq_num = (uint8_t)(dev_iroute >> (ECIA_GIRQ_ID_BITPOS)) & 0x1Fu;\r
+ ia_bit_pos = (uint8_t)(dev_iroute >> (ECIA_GIRQ_BIT_BITPOS)) & 0x1Fu; \r
+ \r
+ retVal = p_interrupt_ecia_girq_result_get(girq_num, ia_bit_pos); \r
+ return retVal;\r
+}\r
+\r
+/* ------------------------------------------------------------------------------- */\r
+/* NVIC APIs using device IROUTE() as input */ \r
+/* ------------------------------------------------------------------------------- */\r
+/* Note that if the device interrupt is aggregated, then these APIs would affect the \r
+ * NVIC corresponding to the aggregated GIRQ \r
+ */\r
+\r
+/** Enable/Disable the NVIC (in the NVIC controller) for the device\r
+ * @param dev_iroute : source IROUTING information (encoded in a uint32_t)\r
+ * @param en_flag : 1 = Enable the NVIC IRQ, 0 = Disable the NVIC IRQ \r
+ * @note 1. Recommended to use interrupt_device_enable, interrupt_device_disable\r
+ * to enable/disable interrupts for the device, since those APIs configure ECIA as well\r
+ * 2. This function disables and enables global interrupt \r
+ */\r
+void interrupt_device_nvic_enable(uint32_t dev_iroute, uint8_t en_flag)\r
+{\r
+ uint32_t isave;\r
+ IRQn_Type nvic_num;\r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ isave = __get_PRIMASK();\r
+ __disable_irq();\r
+ \r
+ p_interrupt_nvic_enable(nvic_num, en_flag); \r
+ \r
+ if (!isave) {\r
+ __enable_irq();\r
+ }\r
+}\r
+\r
+\r
+/** Set NVIC priority for specified peripheral interrupt \r
+ * @param dev_iroute - source IROUTING information (encoded in a uint32_t)\r
+ * @param nvic_pri - NVIC Priority\r
+ * @note If ECIA is in aggregated mode, the priority affects all interrupt \r
+ * sources in the GIRQ. \r
+ */\r
+void interrupt_device_nvic_priority_set(const uint32_t dev_iroute, const uint8_t nvic_pri)\r
+{\r
+ IRQn_Type nvic_num;\r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ NVIC_SetPriority(nvic_num, (uint32_t)nvic_pri);\r
+}\r
+\r
+/** Return NVIC priority for the device's interrupt\r
+ * @param dev_iroute - source IROUTING information \r
+ * @return uint32_t NVIC priority \r
+ */\r
+uint32_t interrupt_device_nvic_priority_get(const uint32_t dev_iroute)\r
+{\r
+ IRQn_Type nvic_num;\r
+ uint32_t nvic_priority;\r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ nvic_priority = NVIC_GetPriority(nvic_num);\r
+ \r
+ return nvic_priority;\r
+}\r
+\r
+\r
+/** Return NVIC pending for the device\r
+ * @param dev_iroute - source IROUTING information \r
+ * @return uint8_t 0(not pending), 1 (pending in NVIC) \r
+ * \r
+ */\r
+uint8_t interrupt_device_nvic_pending_get(const uint32_t dev_iroute)\r
+{\r
+ IRQn_Type nvic_num;\r
+ uint8_t nvic_pending;\r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ nvic_pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));\r
+ \r
+ return nvic_pending;\r
+}\r
+\r
+\r
+/** Set NVIC pending for interrupt source\r
+ * @param dev_iroute - source IROUTING information \r
+ */\r
+void interrupt_device_nvic_pending_set(const uint32_t dev_iroute)\r
+{\r
+ IRQn_Type nvic_num; \r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ NVIC_SetPendingIRQ(nvic_num); \r
+}\r
+\r
+/** Clears NVIC pending for interrupt source\r
+ * @param dev_iroute - source IROUTING information \r
+ * @return uint8_t 0(not pending), 1 (pending in NVIC) - before clear \r
+ * @note This function disables and enables global interrupt \r
+ */\r
+uint8_t interrupt_device_nvic_pending_clear(const uint32_t dev_iroute)\r
+{\r
+ uint32_t was_masked;\r
+ IRQn_Type nvic_num;\r
+ uint8_t pending;\r
+ \r
+ if (p_interrupt_control_get()) \r
+ { // direct \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_NVIC_ID_BITPOS)) & 0xFFul); \r
+ } \r
+ else // fully aggregated\r
+ { \r
+ nvic_num = (IRQn_Type)((dev_iroute >> (ECIA_IA_NVIC_ID_BITPOS)) & 0xFFul);\r
+ }\r
+ \r
+ was_masked = __get_PRIMASK();\r
+ __disable_irq();\r
+ \r
+ pending = (uint8_t)(NVIC_GetPendingIRQ(nvic_num));\r
+\r
+ NVIC_ClearPendingIRQ(nvic_num);\r
+ __DSB();\r
+ \r
+ if (!was_masked) {\r
+ __enable_irq();\r
+ }\r
+ \r
+ return pending;\r
+}\r
+\r
+/* ------------------------------------------------------------------------------- */\r
+\r
+/* end interrupt_api.c */\r
+/** @}\r
+ */\r