1 /*
2  * Copyright 2017, 2019-2020 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_ci_pi.h"
9 
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.ci_pi"
13 #endif
14 
15 /*******************************************************************************
16  * Prototypes
17  ******************************************************************************/
18 /*!
19  * @brief Get the CI_PI instance from peripheral base address.
20  *
21  * @param base CI_PI peripheral base address.
22  * @return CI_PI instance.
23  */
24 uint32_t CI_PI_GetInstance(CI_PI_CSR_Type *base);
25 
26 /*******************************************************************************
27  * Variables
28  ******************************************************************************/
29 /* Array of CI_PI peripheral base address. */
30 static CI_PI_CSR_Type *const s_cipiBases[] = CI_PI_CSR_BASE_PTRS;
31 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
32 /* Array of CI_PI clock name. */
33 static const clock_ip_name_t s_cipiClock[] = CI_PI_CLOCKS;
34 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
35 
36 /*******************************************************************************
37  * Code
38  ******************************************************************************/
CI_PI_GetInstance(CI_PI_CSR_Type * base)39 uint32_t CI_PI_GetInstance(CI_PI_CSR_Type *base)
40 {
41     uint32_t instance;
42     uint32_t cipiArrayCount = (sizeof(s_cipiBases) / sizeof(s_cipiBases[0]));
43 
44     /* Find the instance index from base address mappings. */
45     for (instance = 0; instance < cipiArrayCount; instance++)
46     {
47         if (s_cipiBases[instance] == base)
48         {
49             break;
50         }
51     }
52 
53     assert(instance < cipiArrayCount);
54 
55     return instance;
56 }
57 
58 /*!
59  * brief Enables and configures the CI_PI peripheral module.
60  *
61  * param base CI_PI peripheral address.
62  * param config CI_PI module configuration structure.
63  */
CI_PI_Init(CI_PI_CSR_Type * base,const ci_pi_config_t * config)64 void CI_PI_Init(CI_PI_CSR_Type *base, const ci_pi_config_t *config)
65 {
66     uint32_t ifCtrl   = 0U;
67     uint32_t csiCtrl0 = 0U;
68 
69 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
70     /* Enable cipi clock */
71     (void)CLOCK_EnableClock(s_cipiClock[CI_PI_GetInstance(base)]);
72 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
73 
74     CI_PI_Reset(base);
75 
76     CI_PI_Stop(base);
77 
78     /* Configure the pixel link. */
79     ifCtrl = CI_PI_CSR_IF_CTRL_REG_PL_ADDR(config->pixelLinkAddr);
80 
81     base->IF_CTRL_REG.RW = ifCtrl;
82 
83     /* Enable the pixel link. */
84     base->IF_CTRL_REG.SET = CI_PI_CSR_IF_CTRL_REG_PL_ENABLE_MASK | CI_PI_CSR_IF_CTRL_REG_PL_VALID_MASK;
85 
86     /* Configure the CSI. */
87     csiCtrl0 = CI_PI_CSR_CSI_CTRL_REG_HSYNC_FORCE_EN_MASK | CI_PI_CSR_CSI_CTRL_REG_VSYNC_FORCE_EN_MASK |
88                CI_PI_CSR_CSI_CTRL_REG_CCIR_VSYNC_RESET_EN_MASK | config->polarityFlags /* Signal polarity. */
89                | CI_PI_CSR_CSI_CTRL_REG_MASK_VSYNC_COUNTER(2)                          /* Mask 2 frames. */
90                | CI_PI_CSR_CSI_CTRL_REG_CCIR_ECC_ERR_CORRECT_EN_MASK                   /* Enable ECC correction. */
91                | CI_PI_CSR_CSI_CTRL_REG_HSYNC_PULSE(config->hsyncWidth)                /* Set HSYNC pulse. */
92                | CI_PI_CSR_CSI_CTRL_REG_DATA_TYPE_IN(config->inputFormat)              /* CSI data format. */
93                | (uint32_t)config->workMode;                                           /* CSI work mode. */
94 
95     if (config->useExtVsync)
96     {
97         csiCtrl0 |= CI_PI_CSR_CSI_CTRL_REG_CCIR_EXT_VSYNC_EN_MASK;
98     }
99 
100     if (config->swapUV)
101     {
102         csiCtrl0 |= CI_PI_CSR_CSI_CTRL_REG_UV_SWAP_EN_MASK;
103     }
104 
105     base->CSI_CTRL_REG.RW = csiCtrl0;
106 
107     /* CSI_CTRL_REG1[VSYNC_PULSE] means the pixel clock count of VSYNC. */
108     base->CSI_CTRL_REG1.RW = CI_PI_CSR_CSI_CTRL_REG1_VSYNC_PULSE(
109                                  config->vsyncWidth * ((uint32_t)config->width + (uint32_t)config->hsyncWidth)) |
110                              CI_PI_CSR_CSI_CTRL_REG1_PIXEL_WIDTH((uint32_t)config->width - 1U);
111 }
112 
113 /*!
114  * brief Disables the CI_PI peripheral module.
115  *
116  * param base CI_PI peripheral address.
117  */
CI_PI_Deinit(CI_PI_CSR_Type * base)118 void CI_PI_Deinit(CI_PI_CSR_Type *base)
119 {
120     CI_PI_Stop(base);
121     CI_PI_Reset(base);
122 
123 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
124     /* Enable cipi clock */
125     (void)CLOCK_EnableClock(s_cipiClock[CI_PI_GetInstance(base)]);
126 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
127 }
128 
129 /*!
130  * brief Get the default configuration to initialize CI_PI.
131  *
132  * The default configuration value is:
133  *
134  * code
135     config->width = 0;
136     config->vsyncWidth = 3U;
137     config->hsyncWidth = 2U;
138     config->polarityFlags = 0;
139     config->pixelLinkAddr = 0;
140     config->inputFormat = kCI_PI_InputUYVY8888_8BitBus;
141     config->workMode = kCI_PI_NonGatedClockMode;
142     config->useExtVsync = false;
143     config->swapUV = false;
144     endcode
145  *
146  * param config Pointer to the configuration.
147  */
CI_PI_GetDefaultConfig(ci_pi_config_t * config)148 void CI_PI_GetDefaultConfig(ci_pi_config_t *config)
149 {
150     assert(config);
151 
152     /* Initializes the configure structure to zero. */
153     (void)memset(config, 0, sizeof(*config));
154 
155     config->width         = 0;
156     config->vsyncWidth    = 3U;
157     config->hsyncWidth    = 2U;
158     config->polarityFlags = 0;
159     config->pixelLinkAddr = 0;
160     config->inputFormat   = kCI_PI_InputUYVY8888_8BitBus;
161     config->workMode      = kCI_PI_NonGatedClockMode;
162     config->useExtVsync   = false;
163     config->swapUV        = false;
164 }
165 
166 /*!
167  * brief Starts the CI_PI peripheral module to output captured frame.
168  *
169  * param base CI_PI peripheral address.
170  */
CI_PI_Start(CI_PI_CSR_Type * base)171 void CI_PI_Start(CI_PI_CSR_Type *base)
172 {
173     /* Enable the CSI. */
174     base->CSI_CTRL_REG.SET = CI_PI_CSR_CSI_CTRL_REG_CSI_EN_MASK;
175     /* Disable force sync, then the input signal is processed. */
176     base->CSI_CTRL_REG.CLR = CI_PI_CSR_CSI_CTRL_REG_HSYNC_FORCE_EN_MASK | CI_PI_CSR_CSI_CTRL_REG_VSYNC_FORCE_EN_MASK;
177 }
178 
179 /*!
180  * brief Stops the CI_PI peripheral module.
181  *
182  * param base CI_PI peripheral address.
183  */
CI_PI_Stop(CI_PI_CSR_Type * base)184 void CI_PI_Stop(CI_PI_CSR_Type *base)
185 {
186     /* Disable the CSI. */
187     base->CSI_CTRL_REG.CLR = CI_PI_CSR_CSI_CTRL_REG_CSI_EN_MASK;
188     /* Enable force sync, the signal is latched. */
189     base->CSI_CTRL_REG.SET = CI_PI_CSR_CSI_CTRL_REG_HSYNC_FORCE_EN_MASK | CI_PI_CSR_CSI_CTRL_REG_VSYNC_FORCE_EN_MASK;
190 }
191