1 /*
2  * Copyright 2017, 2019-2020 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_mipi_csi2rx.h"
10 
11 /*
12  * The MIPI CSI2 peripheral can not work independently, some other control and
13  * status registers must be used together. There are two integration methods
14  * with these registers.
15  *
16  * 1. The registers are collected in one dedicated module: CSR.
17  * 2. The registers are scattered in multiple modules.
18  *
19  */
20 
21 /*******************************************************************************
22  * Definitions
23  ******************************************************************************/
24 
25 /* Component ID definition, used by tools. */
26 #ifndef FSL_COMPONENT_ID
27 #define FSL_COMPONENT_ID "platform.drivers.mipi_csi2rx"
28 #endif
29 
30 #if (defined(FSL_FEATURE_CSI2RX_CSR_OFFSET) && FSL_FEATURE_CSI2RX_CSR_OFFSET)
31 #define CSI2RX_GET_CSR(csi_base) (MIPI_CSI_CSR_Type *)((uint32_t)(csi_base) - (uint32_t)FSL_FEATURE_CSI2RX_CSR_OFFSET)
32 #define MIPI_CSI2RX_HAS_CSR      1
33 #else
34 #define MIPI_CSI2RX_HAS_CSR 0
35 #include "fsl_soc_mipi_csi2rx.h"
36 #endif
37 
38 #if MIPI_CSI2RX_HAS_CSR
39 
40 /* Macro Map */
41 #ifndef MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK
42 #define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK \
43     MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(2U)
44 #define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK \
45     MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(1U)
46 #endif
47 
48 #ifndef MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK
49 #define MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK MIPI_CSI_CSR_PHY_CTRL_CONT_CLK_MODE_MASK
50 #endif
51 
52 #ifndef MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE
53 #define MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(x) MIPI_CSI_CSR_PHY_CTRL_S_PRG_RXHS_SETTLE(x)
54 #endif
55 
56 #endif
57 
58 /*******************************************************************************
59  * Prototypes
60  ******************************************************************************/
61 
62 /*!
63  * @brief Returns an instance number given a base address.
64  *
65  * If an invalid base address is passed, debug builds will assert. Release builds will just return
66  * instance number 0.
67  *
68  * @param base The CSI2RX peripheral base address.
69  * @return CSI2RX instance number starting from 0.
70  */
71 uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base);
72 
73 #if MIPI_CSI2RX_HAS_CSR
74 
75 /*!
76  * @brief Perform CSI2RX resource reset in system level.
77  *
78  * @param base The CSI2RX peripheral base address.
79  * @param reset Pass in true to set to reset state, false to release reset.
80  */
81 static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset);
82 
83 /*!
84  * @brief Initialize the CSI2RX interface.
85  *
86  * @param base The CSI2RX peripheral base address.
87  * @param tHsSettle_EscClk t-HS_SETTLE in esc clock period.
88  */
89 static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk);
90 
91 /*!
92  * @brief Deinitialize the CSI2RX interface.
93  *
94  * @param base The CSI2RX peripheral base address.
95  */
96 static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base);
97 
98 #endif
99 
100 /*******************************************************************************
101  * Variables
102  ******************************************************************************/
103 
104 /*! @brief Array to map MIPI CSI2RX instance number to base address. */
105 static const uint32_t s_csi2rxBaseAddrs[] = MIPI_CSI2RX_BASE_ADDRS;
106 
107 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
108 /*! @brief Pointers to MPI CSI2RX clocks for each instance. */
109 static const clock_ip_name_t s_csi2rxClocks[] = MIPI_CSI2RX_CLOCKS;
110 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
111 
112 /*******************************************************************************
113  * Code
114  ******************************************************************************/
115 
116 #if MIPI_CSI2RX_HAS_CSR
MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type * base,bool reset)117 static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset)
118 {
119     MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
120 
121     if (reset)
122     {
123         csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
124     }
125     else
126     {
127         csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
128         csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK |
129                                               MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
130     }
131 }
132 
MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type * base,uint8_t tHsSettle_EscClk)133 static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk)
134 {
135     MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
136 
137     /* Pixel link control */
138     csr->PLM_CTRL = 0;
139 
140     /* Configure the PHY. */
141     csr->PHY_CTRL = MIPI_CSI_CSR_PHY_CTRL_RX_ENABLE_MASK |  /* Enable RX. */
142                     MIPI_CSI_CSR_PHY_CTRL_AUTO_PD_EN_MASK | /* Auto power down unused lanes. */
143                     MIPI_CSI_CSR_PHY_CTRL_PD_MASK | MIPI_CSI_CSR_PHY_CTRL_DDRCLK_EN_MASK | /* Enable the DDR clock. */
144                     MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK |                            /* Continue clock. */
145                     MIPI_CSI_CSR_PHY_CTRL_RTERM_SEL_MASK | /*  LPRX voltage level enable HS termination */
146                     MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(tHsSettle_EscClk - 1UL); /* T(HS-SETTLE) */
147 
148     /* Don't support interlace currently. */
149     csr->VC_INTERLACED = 0U;
150 
151     /* Don't mask any data type */
152 #if defined(MIPI_CSI_CSR_DATA_TYPE_DISABLE_BF_DATA_TYPE_DISABLE_MASK)
153     csr->DATA_TYPE_DISABLE_BF = 0U;
154 #else
155     csr->DATA_TYPE_DIS       = 0U;
156 #endif
157 
158     /* VC fence. */
159 #if defined(MIPI_CSI_CSR_STREAM_FENCING_CONTROL_STREAM_FENCING_CONTROL_MASK)
160     csr->STREAM_FENCING_CONTROL = 0U;
161 #else
162     csr->STREAM_FENCING_CTRL = 0U;
163 #endif
164 
165 #if defined(MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK)
166     /* Wait for PL clock active. */
167     while (0UL != (csr->PLM_CTRL & MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK))
168     {
169     }
170 #endif
171 
172     /* Enable pixel link master. */
173     csr->PLM_CTRL |= (MIPI_CSI_CSR_PLM_CTRL_ENABLE_MASK | MIPI_CSI_CSR_PLM_CTRL_VALID_OVERRIDE_MASK);
174 
175     /* Power up PHY. */
176     csr->PHY_CTRL &= ~MIPI_CSI_CSR_PHY_CTRL_PD_MASK;
177 
178     /* Start clock. */
179     csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK;
180 }
181 
MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type * base)182 static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base)
183 {
184     MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
185 
186     /* Disable the PHY. */
187     csr->PHY_CTRL = 0;
188 
189     /* Disable the pixel link master. */
190     csr->PLM_CTRL = 0;
191 
192     /* Stop the clock and assert reset. */
193     csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
194 }
195 #endif
196 
CSI2RX_GetInstance(MIPI_CSI2RX_Type * base)197 uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base)
198 {
199     uint32_t i;
200 
201     for (i = 0U; i < ARRAY_SIZE(s_csi2rxBaseAddrs); i++)
202     {
203         if ((uint32_t)base == s_csi2rxBaseAddrs[i])
204         {
205             return i;
206         }
207     }
208 
209     assert(false);
210 
211     return 0;
212 }
213 
214 /*!
215  * brief Enables and configures the CSI2RX peripheral module.
216  *
217  * param base CSI2RX peripheral address.
218  * param config CSI2RX module configuration structure.
219  */
CSI2RX_Init(MIPI_CSI2RX_Type * base,const csi2rx_config_t * config)220 void CSI2RX_Init(MIPI_CSI2RX_Type *base, const csi2rx_config_t *config)
221 {
222     assert(NULL != config);
223 
224 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
225     /* un-gate clock */
226     (void)CLOCK_EnableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
227 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
228 
229     MIPI_CSI2RX_SoftwareReset(base, false);
230 
231     CSI2RX_REG_CFG_NUM_LANES(base) = config->laneNum - 1UL;
232     CSI2RX_REG_CFG_DISABLE_DATA_LANES(base) =
233         MIPI_CSI2RX_CSI2RX_CFG_NUM_LANES_csi2rx_cfg_num_lanes_MASK & ~((1UL << (uint32_t)config->laneNum) - 1UL);
234 
235     /* Don't disable data types. */
236     CSI2RX_REG_CFG_DISABLE_PAYLOAD_0(base) = 0;
237     CSI2RX_REG_CFG_DISABLE_PAYLOAD_1(base) = 0;
238 
239     /* Disable all interrupts. */
240     CSI2RX_REG_IRQ_MASK(base) = MIPI_CSI2RX_CSI2RX_IRQ_MASK_csi2rx_irq_mask_MASK;
241 
242     MIPI_CSI2RX_InitInterface(base, config->tHsSettle_EscClk);
243 }
244 
245 /*!
246  * brief Disables the CSI2RX peripheral module.
247  *
248  * param base CSI2RX peripheral address.
249  */
CSI2RX_Deinit(MIPI_CSI2RX_Type * base)250 void CSI2RX_Deinit(MIPI_CSI2RX_Type *base)
251 {
252     MIPI_CSI2RX_DeinitInterface(base);
253 
254     MIPI_CSI2RX_SoftwareReset(base, true);
255 
256 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
257     /* gate clock */
258     (void)CLOCK_DisableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
259 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
260 }
261