1 /*
2  * Copyright 2021-2022 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_syspm.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.syspm"
18 #endif
19 
20 /*******************************************************************************
21  * Prototypes
22  ******************************************************************************/
23 
24 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)) && defined(SYSPM_CLOCKS)
25 /*!
26  * @brief Get instance number for ESYSPM.
27  *
28  * @param base ESYSPM peripheral base address.
29  */
30 static uint32_t SYSPM_GetInstance(SYSPM_Type *base);
31 #endif
32 
33 /*******************************************************************************
34  * Variables
35  ******************************************************************************/
36 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)) && defined(SYSPM_CLOCKS)
37 /*! @brief Array to map SYSPM instance number to base pointer. */
38 static SYSPM_Type *const s_syspmBases[] = SYSPM_BASE_PTRS;
39 
40 /*! @brief Array to map SYSPM instance number to clock name. */
41 static const clock_ip_name_t s_syspmClockName[] = SYSPM_CLOCKS;
42 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
43 
44 /*******************************************************************************
45  * Code
46  ******************************************************************************/
47 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)) && defined(SYSPM_CLOCKS)
SYSPM_GetInstance(SYSPM_Type * base)48 static uint32_t SYSPM_GetInstance(SYSPM_Type *base)
49 {
50     uint32_t instance;
51 
52     /* Find the instance index from base address mappings. */
53     for (instance = 0; instance < ARRAY_SIZE(s_syspmBases); instance++)
54     {
55         if (s_syspmBases[instance] == base)
56         {
57             break;
58         }
59     }
60 
61     assert(instance < ARRAY_SIZE(s_syspmBases));
62 
63     return instance;
64 }
65 #endif
66 
67 /*
68  * brief Initializes the SYSPM
69  *
70  * This function enables the SYSPM clock.
71  *
72  * param base  SYSPM peripheral base address.
73  */
SYSPM_Init(SYSPM_Type * base)74 void SYSPM_Init(SYSPM_Type *base)
75 {
76 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)) && defined(SYSPM_CLOCKS)
77     CLOCK_EnableClock(s_syspmClockName[SYSPM_GetInstance(base)]);
78 #endif
79 }
80 
81 /*
82  * brief Deinitializes the SYSPM
83  *
84  * This function disables the SYSPM clock.
85  *
86  * param base  SYSPM peripheral base address.
87  */
SYSPM_Deinit(SYSPM_Type * base)88 void SYSPM_Deinit(SYSPM_Type *base)
89 {
90 #if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)) && defined(SYSPM_CLOCKS)
91     CLOCK_DisableClock(s_syspmClockName[SYSPM_GetInstance(base)]);
92 #endif
93 }
94 
95 /*!
96  * @brief Select event counters
97  *
98  * @param base               SYSPM peripheral base address.
99  * @param monitor            syspm control monitor, see to #syspm_monitor_t.
100  * @param event              syspm select event, see to #syspm_event_t.
101  * @param eventCode          select which event to be counted in PMECTRx., see to table Events.
102  */
SYSPM_SelectEvent(SYSPM_Type * base,syspm_monitor_t monitor,syspm_event_t event,uint8_t eventCode)103 void SYSPM_SelectEvent(SYSPM_Type *base, syspm_monitor_t monitor, syspm_event_t event, uint8_t eventCode)
104 {
105     uint32_t pmcr;
106     uint8_t shift;
107 
108     shift = 7U * (uint8_t)event;
109 
110     pmcr = base->PMCR[(uint8_t)monitor].PMCR;
111     pmcr &= ~(SYSPM_PMCR_SELEVT1_MASK << shift);
112     pmcr |= SYSPM_PMCR_SELEVT1(eventCode) << shift;
113 
114     base->PMCR[(uint8_t)monitor].PMCR = pmcr;
115 }
116 
117 /*!
118  * @brief Reset event counters
119  *
120  * @param base        SYSPM peripheral base address.
121  * @param monitor     syspm control monitor, see to #syspm_monitor_t.
122  */
SYSPM_ResetEvent(SYSPM_Type * base,syspm_monitor_t monitor,syspm_event_t event)123 void SYSPM_ResetEvent(SYSPM_Type *base, syspm_monitor_t monitor, syspm_event_t event)
124 {
125     base->PMCR[(uint8_t)monitor].PMCR |= ((uint32_t)SYSPM_PMCR_RECTR1_MASK << (uint8_t)event);
126 }
127 
128 #if !((defined(FSL_FEATURE_SYSPM_HAS_PMCR_RICTR) && (FSL_FEATURE_SYSPM_HAS_PMCR_RICTR == 0U)))
129 /*!
130  * @brief Reset Instruction Counter
131  *
132  * @param base        SYSPM peripheral base address.
133  * @param monitor     syspm control monitor, see to #syspm_monitor_t.
134  */
SYSPM_ResetInstructionEvent(SYSPM_Type * base,syspm_monitor_t monitor)135 void SYSPM_ResetInstructionEvent(SYSPM_Type *base, syspm_monitor_t monitor)
136 {
137     base->PMCR[(uint8_t)monitor].PMCR |= SYSPM_PMCR_RICTR_MASK;
138 }
139 #endif /* FSL_FEATURE_SYSPM_HAS_PMCR_RICTR */
140 
141 /*!
142  * @brief Set count mode
143  *
144  * @param base               SYSPM peripheral base address.
145  * @param monitor            syspm control monitor, see to #syspm_monitor_t.
146  * @param mode               syspm select counter mode, see to #syspm_mode_t.
147  */
SYSPM_SetCountMode(SYSPM_Type * base,syspm_monitor_t monitor,syspm_mode_t mode)148 void SYSPM_SetCountMode(SYSPM_Type *base, syspm_monitor_t monitor, syspm_mode_t mode)
149 {
150     base->PMCR[(uint8_t)monitor].PMCR =
151         (base->PMCR[(uint8_t)monitor].PMCR & ~SYSPM_PMCR_CMODE_MASK) | SYSPM_PMCR_CMODE(mode);
152 }
153 
154 /*!
155  * @brief  Set Start/Stop Control
156  *
157  * @param base              SYSPM peripheral base address.
158  * @param monitor           syspm control monitor, see to #syspm_monitor_t.
159  * @param ssc               This 3-bit field provides a three-phase mechanism to start/stop the counters. It includes a
160  *                          prioritized scheme with local start > local stop > global start > global stop > conditional
161  * TSTART > TSTOP. The global and conditional start/stop affect all configured PM/PSAM module concurrently so counters
162  * are "coherent". see to #syspm_startstop_control_t
163  */
SYSPM_SetStartStopControl(SYSPM_Type * base,syspm_monitor_t monitor,syspm_startstop_control_t ssc)164 void SYSPM_SetStartStopControl(SYSPM_Type *base, syspm_monitor_t monitor, syspm_startstop_control_t ssc)
165 {
166     base->PMCR[(uint8_t)monitor].PMCR =
167         (base->PMCR[(uint8_t)monitor].PMCR & ~SYSPM_PMCR_SSC_MASK) | SYSPM_PMCR_SSC(ssc);
168 }
169 
170 #if !((defined(FSL_FEATURE_SYSPM_HAS_PMCR_DCIFSH)) && (FSL_FEATURE_SYSPM_HAS_PMCR_DCIFSH == 0U))
171 /*!
172  * @brief Disable Counters if Stopped or Halted
173  *
174  * @param base              SYSPM peripheral base address.
175  * @param monitor           syspm control monitor, see to #syspm_monitor_t.
176  */
SYSPM_DisableCounter(SYSPM_Type * base,syspm_monitor_t monitor)177 void SYSPM_DisableCounter(SYSPM_Type *base, syspm_monitor_t monitor)
178 {
179     base->PMCR[(uint8_t)monitor].PMCR |= SYSPM_PMCR_DCIFSH_MASK;
180 }
181 #endif /* FSL_FEATURE_SYSPM_HAS_PMCR_DCIFSH */
182 
183 /*!
184  * @brief This is the the 40-bits of eventx counter.
185          The value in this register increments each time the event
186          selected in PMCRx[SELEVTx] occurs.
187  *
188  * @param base              SYSPM peripheral base address.
189  * @param monitor           syspm control monitor, see to #syspm_monitor_t.
190  * @param event             syspm select event, see to #syspm_event_t.
191  * @return                  get the the 40 bits of eventx counter.
192  */
SYSPM_GetEventCounter(SYSPM_Type * base,syspm_monitor_t monitor,syspm_event_t event)193 uint64_t SYSPM_GetEventCounter(SYSPM_Type *base, syspm_monitor_t monitor, syspm_event_t event)
194 {
195     uint32_t highOld;
196     uint32_t high;
197     uint32_t low;
198 
199     highOld = base->PMCR[(uint8_t)monitor].PMECTR[(uint8_t)event].HI;
200     while (true)
201     {
202         low  = base->PMCR[(uint8_t)monitor].PMECTR[(uint8_t)event].LO;
203         high = base->PMCR[(uint8_t)monitor].PMECTR[(uint8_t)event].HI;
204         if (high == highOld)
205         {
206             break;
207         }
208         else
209         {
210             highOld = high;
211         }
212     }
213 
214     return ((uint64_t)high << 32U) + low;
215 }
216