1 /*
2  * Copyright 2022, 2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_xbar.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.xbar_1"
17 #endif
18 
19 #define XBAR_INST_FROM_INPUT(input)   ((uint16_t)(input) >> 8U)
20 #define XBAR_INST_FROM_OUTPUT(output) ((uint16_t)(output) >> 8U)
21 
22 #define XBAR_EXTRACT_INPUT(input)   ((uint16_t)(input)&0xFFU)
23 #define XBAR_EXTRACT_OUTPUT(output) ((uint16_t)(output)&0xFFU)
24 
25 #define XBAR_CTRL_STAT_SHIFT 4U
26 #define XBAR_CTRL_STAT_MASK  ((xbar_reg_t)1U << 4U)
27 
28 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
29 #define XBAR_CTRL_ALL_STAT_MASK (XBAR_CTRL_STAT_MASK)
30 #else
31 #define XBAR_CTRL_ALL_STAT_MASK (XBAR_CTRL_STAT_MASK | (XBAR_CTRL_STAT_MASK << 8U))
32 #endif
33 
34 /* Array of XBAR clock name. */
35 static const clock_ip_name_t s_xbaraClock[] = XBAR_CLOCKS;
36 
37 static const xbar_info_t s_xbarInfo[] = XBAR_INFO;
38 
39 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
40 /*!
41  * brief Get the XBAR peripheral address CTRL register address.
42  *
43  * param output XBAR output signal.
44  * param ctrlReg Addr XBAR control register address.
45  * retval kStatus_Success Signal connection set successfully.
46  * retval kStatus_InvalidArgument Failed because of invalid argument.
47  */
XBAR_GetCtrlReg(xbar_output_signal_t output,volatile xbar_reg_t ** ctrlRegAddr)48 static status_t XBAR_GetCtrlReg(xbar_output_signal_t output, volatile xbar_reg_t **ctrlRegAddr)
49 {
50     status_t status;
51     uint16_t inst        = XBAR_INST_FROM_OUTPUT(output);
52     uint16_t outputIndex = XBAR_EXTRACT_OUTPUT(output);
53 
54     if ((inst > ARRAY_SIZE(s_xbarInfo)) || (outputIndex > (s_xbarInfo[inst - 1U].regCtrlNum)))
55     {
56         status = kStatus_InvalidArgument;
57     }
58     else
59     {
60         *ctrlRegAddr = s_xbarInfo[inst - 1U].baseAddr + (s_xbarInfo[inst - 1U].regCtrlOffset + outputIndex);
61         status       = kStatus_Success;
62     }
63 
64     return status;
65 }
66 #else
67 /*!
68  * brief Get the XBAR peripheral address and shift.
69  *
70  * Example:
71    code
72    XBAR_GetCtrlRegAndShift(kXBAR_DSC1_InputLogicLow, XBAR_DSC1_BASE, 1);
73    endcode
74  *
75  * param output XBAR output signal.
76  * param ctrlReg Addr XBAR control register address.
77  * param shift Number of XBAR control register.
78  * retval kStatus_Success Signal connection set successfully.
79  * retval kStatus_InvalidArgument Failed because of invalid argument.
80  */
XBAR_GetCtrlRegAndShift(xbar_output_signal_t output,volatile xbar_reg_t ** ctrlRegAddr,uint8_t * shift)81 static status_t XBAR_GetCtrlRegAndShift(xbar_output_signal_t output, volatile xbar_reg_t **ctrlRegAddr, uint8_t *shift)
82 {
83     status_t status;
84     uint16_t inst        = XBAR_INST_FROM_OUTPUT(output);
85     uint16_t outputIndex = XBAR_EXTRACT_OUTPUT(output);
86 
87     if ((inst > ARRAY_SIZE(s_xbarInfo)) || (outputIndex > (s_xbarInfo[inst - 1U].regCtrlNum * 2U)))
88     {
89         status = kStatus_InvalidArgument;
90     }
91     else
92     {
93         *ctrlRegAddr = s_xbarInfo[inst - 1U].baseAddr + ((s_xbarInfo[inst - 1U].regCtrlOffset + outputIndex) / 2U);
94         *shift       = (uint8_t)(uint16_t)(8U * (outputIndex % 2U));
95         status       = kStatus_Success;
96     }
97 
98     return status;
99 }
100 #endif
101 
102 /*!
103  * brief Initializes the XBAR module.
104  *
105  * This function un-gates the XBAR clock.
106  *
107  * param xbarInstance XBAR peripheral address.
108  */
XBAR_Init(xbar_instance_t xbarInstance)109 void XBAR_Init(xbar_instance_t xbarInstance)
110 {
111 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
112     /* Enable XBARA module clock. */
113     (void)CLOCK_EnableClock(s_xbaraClock[xbarInstance]);
114 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
115 }
116 
117 /*!
118  * brief Shuts down the XBAR module.
119  *
120  * This function disables XBAR clock.
121  *
122  * param xbarInstance XBAR peripheral address.
123  */
XBAR_Deinit(xbar_instance_t xbarInstance)124 void XBAR_Deinit(xbar_instance_t xbarInstance)
125 {
126 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
127     /* Disable XBARA module clock. */
128     (void)CLOCK_DisableClock(s_xbaraClock[xbarInstance]);
129 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
130 }
131 
132 /*!
133  * brief Sets a connection between the selected XBAR_IN[*] input and the XBAR_OUT[*] output signal.
134  *
135  * This function connects the XBAR input to the selected XBAR output.
136  * If more than one XBAR module is available, only the inputs and outputs from the same module
137  * can be connected.
138  *
139  * Example:
140    code
141    XBAR_SetSignalsConnection(kXBAR_DSC1_InputLogicLow, kXBAR_DSC1_OutputTriggerSyncIn0);
142    endcode
143  *
144  * param input XBAR input signal.
145  * param output XBAR output signal.
146  * retval kStatus_Success Signal connection set successfully.
147  * retval kStatus_InvalidArgument Failed because of invalid argument.
148  */
XBAR_SetSignalsConnection(xbar_input_signal_t input,xbar_output_signal_t output)149 status_t XBAR_SetSignalsConnection(xbar_input_signal_t input, xbar_output_signal_t output)
150 {
151     status_t status;
152     uint16_t inst        = XBAR_INST_FROM_OUTPUT(output);
153     uint16_t outputIndex = XBAR_EXTRACT_OUTPUT(output);
154     uint16_t inputIndex  = XBAR_EXTRACT_INPUT(input);
155     volatile xbar_reg_t *selRegAddr;
156 
157 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
158     if ((inst > ARRAY_SIZE(s_xbarInfo)) || (outputIndex > (s_xbarInfo[inst - 1U].regSelNum)))
159     {
160         status = kStatus_InvalidArgument;
161     }
162     else
163     {
164         selRegAddr  = s_xbarInfo[inst - 1U].baseAddr + ((s_xbarInfo[inst - 1U].regSelOffset + outputIndex));
165         *selRegAddr = (*selRegAddr & ~((xbar_reg_t)0xFFU)) | (inputIndex);
166         status      = kStatus_Success;
167     }
168 #else
169     uint8_t shiftInReg;
170 
171     if ((inst > ARRAY_SIZE(s_xbarInfo)) || (outputIndex > (s_xbarInfo[inst - 1U].regSelNum * 2U)))
172     {
173         status = kStatus_InvalidArgument;
174     }
175     else
176     {
177         selRegAddr  = s_xbarInfo[inst - 1U].baseAddr + ((s_xbarInfo[inst - 1U].regSelOffset + outputIndex) / 2U);
178         shiftInReg  = (uint8_t)(uint16_t)(8U * (outputIndex % 2U));
179         *selRegAddr = (*selRegAddr & ~((xbar_reg_t)0xFFU << shiftInReg)) | (inputIndex << shiftInReg);
180         status      = kStatus_Success;
181     }
182 #endif
183 
184     return status;
185 }
186 
187 /*!
188  * brief Clears the edge detection status flags.
189  *
190  * param output XBAR output signal.
191  * retval kStatus_Success Signal connection set successfully.
192  * retval kStatus_InvalidArgument Failed because of invalid argument.
193  */
XBAR_ClearOutputStatusFlag(xbar_output_signal_t output)194 status_t XBAR_ClearOutputStatusFlag(xbar_output_signal_t output)
195 {
196     status_t status;
197     volatile xbar_reg_t *ctrlRegAddr;
198 
199 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
200     status = XBAR_GetCtrlReg(output, &ctrlRegAddr);
201 
202     if (status == kStatus_Success)
203     {
204         *ctrlRegAddr |= XBAR_CTRL_STAT_MASK;
205     }
206 #else
207     uint8_t shiftInReg;
208 
209     status = XBAR_GetCtrlRegAndShift(output, &ctrlRegAddr, &shiftInReg);
210 
211     if (status == kStatus_Success)
212     {
213         *ctrlRegAddr = (*ctrlRegAddr & (~XBAR_CTRL_ALL_STAT_MASK)) | (XBAR_CTRL_STAT_MASK << shiftInReg);
214     }
215 #endif
216 
217     return status;
218 }
219 
220 /*!
221  * brief Gets the active edge detection status.
222  *
223  * This function gets the active edge detect status of all XBAR_OUTs. If the
224  * active edge occurs, the return value is asserted. When the interrupt or the DMA
225  * functionality is enabled for the XBAR_OUTx, this field is 1 when the interrupt
226  * or DMA request is asserted and 0 when the interrupt or DMA request has been
227  * cleared.
228  *
229  * param output XBAR output signal.
230  * param flag get XBAR output status flag.
231  * retval kStatus_Success Signal connection set successfully.
232  * retval kStatus_InvalidArgument Failed because of invalid argument.
233  */
XBAR_GetOutputStatusFlag(xbar_output_signal_t output,bool * flag)234 status_t XBAR_GetOutputStatusFlag(xbar_output_signal_t output, bool *flag)
235 {
236     status_t status;
237     volatile xbar_reg_t *ctrlRegAddr;
238 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
239     status = XBAR_GetCtrlReg(output, &ctrlRegAddr);
240 
241     if (status == kStatus_Success)
242     {
243         *flag = (0U != (*ctrlRegAddr & ((xbar_reg_t)XBAR_CTRL_STAT_MASK)));
244     }
245 #else
246     uint8_t shiftInReg;
247 
248     status = XBAR_GetCtrlRegAndShift(output, &ctrlRegAddr, &shiftInReg);
249 
250     if (status == kStatus_Success)
251     {
252         *flag = (0U != (*ctrlRegAddr & ((xbar_reg_t)XBAR_CTRL_STAT_MASK << shiftInReg)));
253     }
254 #endif
255 
256     return status;
257 }
258 
259 /*!
260  * brief Configures the XBAR control register.
261  *
262  * This function configures an XBAR control register. The active edge detection
263  * and the DMA/IRQ function on the corresponding XBAR output can be set.
264  *
265  * Example:
266    code
267    xbar_control_config_t userConfig;
268    userConfig.activeEdge = kXBAR_EdgeRising;
269    userConfig.requestType = kXBAR_RequestInterruptEnable;
270    XBAR_SetOutputSignalConfig(kXBAR_DSC1_OutputTriggerSyncIn0, &userConfig);
271    endcode
272  *
273  * param output XBAR output signal.
274  * param controlConfig Pointer to structure that keeps configuration of control register.
275  * retval kStatus_Success Signal connection set successfully.
276  * retval kStatus_InvalidArgument Failed because of invalid argument.
277  */
XBAR_SetOutputSignalConfig(xbar_output_signal_t output,const xbar_control_config_t * controlConfig)278 status_t XBAR_SetOutputSignalConfig(xbar_output_signal_t output, const xbar_control_config_t *controlConfig)
279 {
280     status_t status;
281     volatile xbar_reg_t *ctrlRegAddr;
282 #if defined(FSL_FEATURE_XBAR_REG_WIDTH) && (FSL_FEATURE_XBAR_REG_WIDTH == 32)
283     status = XBAR_GetCtrlReg(output, &ctrlRegAddr);
284 
285     if (status == kStatus_Success)
286     {
287         *ctrlRegAddr |= ((((xbar_reg_t)controlConfig->activeEdge)) << 2) |
288                         (((xbar_reg_t)controlConfig->requestType));
289     }
290 #else
291     uint8_t shiftInReg;
292 
293     status = XBAR_GetCtrlRegAndShift(output, &ctrlRegAddr, &shiftInReg);
294 
295     if (status == kStatus_Success)
296     {
297         *ctrlRegAddr |= ((((xbar_reg_t)controlConfig->activeEdge) << shiftInReg) << 2) |
298                         (((xbar_reg_t)controlConfig->requestType) << shiftInReg);
299     }
300 #endif
301 
302     return status;
303 }
304