1 /*
2 * Copyright 2018-2020 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_ldb.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.ldb"
17 #endif
18
19 #define LDB_CH_COUNT 2U
20
21 #define LDB_DPI_24BIT 5U
22
23 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
24
25 #define LDB_PM_CTRL_REG_CH_MODE_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_MODE_MASK << ((ch)*2U))
26 #define LDB_PM_CTRL_REG_CH_DATA_WIDTH_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_DATA_WIDTH_MASK << ((ch)*2U))
27 #define LDB_PM_CTRL_REG_CH_BIT_MAPPING_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_BIT_MAPPING_MASK << ((ch)*2U))
28 #define LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(di) ((uint32_t)LDB_PM_CTRL_REG_DI0_VS_POLARITY_MASK << (di))
29
30 #define LDB_PM_CTRL_REG_CH_MASK(ch) \
31 (LDB_PM_CTRL_REG_CH_MODE_MASK(ch) | LDB_PM_CTRL_REG_CH_DATA_WIDTH_MASK(ch) | \
32 LDB_PM_CTRL_REG_CH_BIT_MAPPING_MASK(ch))
33
34 #define LDB_PM_CTRL_REG_DI_MASK(di) (LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(di))
35
36 #else
37
38 #define LDB_PM_CTRL_REG_CH_MODE_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_MODE_MASK << ((ch)*2U))
39 #define LDB_PM_CTRL_REG_CH_DATA_WIDTH_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_DATA_WIDTH_MASK << ((ch)*2U))
40 #define LDB_PM_CTRL_REG_CH_BIT_MAPPING_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_BIT_MAPPING_MASK << ((ch)*2U))
41 #define LDB_PM_CTRL_REG_CH_10B_EN_MASK(ch) ((uint32_t)LDB_PM_CTRL_REG_CH0_10B_EN_MASK << (ch))
42 #define LDB_PM_CTRL_REG_DI_DATA_WIDTH_MASK(di) ((uint32_t)LDB_PM_CTRL_REG_DI0_DATA_WIDTH_MASK << ((di)*2U))
43 #define LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(di) ((uint32_t)LDB_PM_CTRL_REG_DI0_VS_POLARITY_MASK << (di))
44
45 #define LDB_PM_CTRL_REG_CH_MASK(ch) \
46 (LDB_PM_CTRL_REG_CH_MODE_MASK(ch) | LDB_PM_CTRL_REG_CH_DATA_WIDTH_MASK(ch) | \
47 LDB_PM_CTRL_REG_CH_BIT_MAPPING_MASK(ch) | LDB_PM_CTRL_REG_CH_10B_EN_MASK(ch))
48
49 #define LDB_PM_CTRL_REG_DI_MASK(di) (LDB_PM_CTRL_REG_DI_DATA_WIDTH_MASK(di) | LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(di))
50
51 #endif
52
53 #define LDB_SS_CTRL_CH_VSYNC_POL_MASK(ch) ((uint32_t)LDB_SS_CTRL_CH0_VSYNC_POL_MASK << ((ch)*2U))
54 #define LDB_SS_CTRL_CH_HSYNC_POL_MASK(ch) ((uint32_t)LDB_SS_CTRL_CH0_HSYNC_POL_MASK << ((ch)*2U))
55
56 /*******************************************************************************
57 * Variables
58 ******************************************************************************/
59 /*! @brief Pointers to ldb bases for each instance. */
60 static LDB_Type *const s_ldbBases[] = LDB_BASE_PTRS;
61
62 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
63 /*! @brief Pointers to LDB clocks for each instance. */
64 static const clock_ip_name_t s_ldbClocks[] = LDB_CLOCKS;
65 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
66
67 /*******************************************************************************
68 * Prototypes
69 ******************************************************************************/
70 /*!
71 * @brief Get the LDB instance from peripheral base address.
72 *
73 * @param base LDB peripheral base address.
74 * @return LDB instance.
75 */
76 static uint32_t LDB_GetInstance(LDB_Type *base);
77
78 /*!
79 * @brief Get the register value based on pixel map.
80 *
81 * @param outputBus Pixel map.
82 * @param ch Channel.
83 * @return Register value.
84 */
85 static uint32_t LDB_GetPixelMapConfig(ldb_output_bus_t outputBus, uint8_t ch);
86
87 /*******************************************************************************
88 * Code
89 ******************************************************************************/
LDB_GetInstance(LDB_Type * base)90 static uint32_t LDB_GetInstance(LDB_Type *base)
91 {
92 uint32_t instance;
93
94 /* Find the instance index from base address mappings. */
95 for (instance = 0U; instance < ARRAY_SIZE(s_ldbBases); instance++)
96 {
97 if (s_ldbBases[instance] == base)
98 {
99 break;
100 }
101 }
102
103 assert(instance < ARRAY_SIZE(s_ldbBases));
104
105 return instance;
106 }
107
LDB_GetPixelMapConfig(ldb_output_bus_t outputBus,uint8_t ch)108 static uint32_t LDB_GetPixelMapConfig(ldb_output_bus_t outputBus, uint8_t ch)
109 {
110 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
111 return outputBus << (ch * 2U);
112 #else
113 uint32_t reg = 0U;
114
115 /* Handle the LDB_PM_CTRL_REG_DI_DATA_WIDTH */
116 reg |= (((uint32_t)outputBus & LDB_PM_CTRL_REG_CH0_10B_EN_MASK) << (ch));
117 reg |= (((uint32_t)outputBus & ~LDB_PM_CTRL_REG_CH0_10B_EN_MASK) << (ch * 2U));
118
119 return reg;
120 #endif
121 }
122
123 /*!
124 * brief Initializes the LDB module.
125 *
126 * param base LDB peripheral base address.
127 */
LDB_Init(LDB_Type * base)128 void LDB_Init(LDB_Type *base)
129 {
130 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
131 (void)CLOCK_EnableClock(s_ldbClocks[LDB_GetInstance(base)]);
132 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
133
134 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
135 base->PHY_SS_CTRL = 0U;
136 base->PM_CTRL_REG = 0U;
137
138 base->PHY_CTRL = LDB_PHY_CTRL_LVDS_EN(0) /* Disable. */
139 | LDB_PHY_CTRL_RFB(1) /* Clock edge. 0: Falling edge. 1: Rising edge. */
140 | LDB_PHY_CTRL_CA(4) /* Output current. */
141 | LDB_PHY_CTRL_CCM(4); /* voltage control . */
142
143 base->PXL2DPI = LDB_DPI_24BIT;
144 base->ULPS = LDB_ULPS_ULPS_ENABLE_MASK; /* Set to lowpower mode. */
145 #else
146 base->PHY_SS_CTRL = 0U;
147 base->PM_CTRL_REG = 0U;
148
149 /*
150 * Initialize the PHY.
151 *
152 * CA:
153 * 2 1 0 (mA)
154 * 0 0 0 2.52
155 * 0 0 1 2.77
156 * 0 1 0 3.02
157 * 0 1 1 3.27
158 * 1 0 0 3.52 <
159 * 1 0 1 3.77
160 * 1 1 0 4.01
161 * 1 1 1 4.26
162 *
163 * CCM:
164 * 2 1 0 (V)
165 * 0 0 0 0.95
166 * 0 0 1 1.0
167 * 0 1 0 1.05
168 * 0 1 1 1.10
169 * 1 0 0 1.15
170 * 1 0 1 1.20 <
171 * 1 1 0 1.25
172 * 1 1 1 1.30
173 */
174 base->PHY_CTRL = LDB_PHY_CTRL_PD(0) /* Power up. */
175 | LDB_PHY_CTRL_RFB(1) /* Clock edge. 0: Falling edge. 1: Rising edge. */
176 | LDB_PHY_CTRL_NB(0) /* 0: 7-bit. 1: 10-bit. */
177 | LDB_PHY_CTRL_TST(0x25) /* Test valud, default 0x25. */
178 | LDB_PHY_CTRL_CA(4) /* Output current. */
179 | LDB_PHY_CTRL_CCM(5); /* voltage control . */
180 #endif /* FSL_FEATURE_LDB_COMBO_PHY */
181 }
182
183 /*!
184 * brief De-initializes the LDB module.
185 *
186 * param base LDB peripheral base address.
187 */
LDB_Deinit(LDB_Type * base)188 void LDB_Deinit(LDB_Type *base)
189 {
190 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
191 base->PHY_CTRL = 0U;
192 #else
193 base->PHY_CTRL |= LDB_PHY_CTRL_PD_MASK;
194 #endif
195
196 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
197 (void)CLOCK_DisableClock(s_ldbClocks[LDB_GetInstance(base)]);
198 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
199 }
200
201 /*!
202 * brief Initializes the LDB channel.
203 *
204 * param base LDB peripheral base address.
205 * param channel Channel index.
206 * param config Pointer to the configuration.
207 * return Return kStatus_Success if success.
208 */
LDB_InitChannel(LDB_Type * base,uint8_t channel,const ldb_channel_config_t * config)209 status_t LDB_InitChannel(LDB_Type *base, uint8_t channel, const ldb_channel_config_t *config)
210 {
211 assert(channel < LDB_CH_COUNT);
212
213 uint32_t reg;
214 uint32_t reg_m;
215 uint32_t pixelClock_MHz;
216
217 reg = base->PHY_SS_CTRL & ~(LDB_SS_CTRL_CH_VSYNC_POL_MASK(channel) | LDB_SS_CTRL_CH_HSYNC_POL_MASK(channel));
218
219 if (0U != (config->inputFlag & (uint32_t)kLDB_InputVsyncActiveHigh))
220 {
221 reg |= LDB_SS_CTRL_CH_VSYNC_POL_MASK(channel);
222 }
223
224 if (0U != (config->inputFlag & (uint32_t)kLDB_InputHsyncActiveHigh))
225 {
226 reg |= LDB_SS_CTRL_CH_HSYNC_POL_MASK(channel);
227 }
228
229 base->PHY_SS_CTRL = reg;
230
231 /* CH0 to DI0, CH1 to DI1 */
232 reg = base->PM_CTRL_REG & ~(LDB_PM_CTRL_REG_DI_MASK(channel) | LDB_PM_CTRL_REG_CH_MASK(channel));
233
234 reg |= LDB_GetPixelMapConfig(config->outputBus, channel);
235
236 if (0U != (config->inputFlag & (uint32_t)kLDB_InputVsyncActiveHigh))
237 {
238 reg |= LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(channel);
239 }
240
241 if (channel == 0U)
242 {
243 reg |= (1U << LDB_PM_CTRL_REG_CH0_MODE_SHIFT);
244 }
245 else
246 {
247 reg |= (3U << LDB_PM_CTRL_REG_CH1_MODE_SHIFT);
248 }
249
250 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
251 reg |= LDB_PM_CTRL_REG_CH_SEL(channel);
252 #endif
253
254 base->PM_CTRL_REG = reg;
255
256 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
257 reg = (base->PHY_CTRL & ~LDB_PHY_CTRL_RFB_MASK);
258
259 /*
260 * DPHY_CO is configured based on pixel clock and NB.
261 *
262 * if NB = 1:
263 * input pixel clock REG_M
264 * 25M ~ 32M 2
265 * 33M ~ 64M 1
266 * 65M ~ 165M 0
267 *
268 * if NB = 0:
269 * input pixel clock REG_M
270 * 25M ~ 45M 2
271 * 46M ~ 92M 1
272 * 93M ~ 165M 0
273 *
274 * Current driver only supports NB=0 (7bit).
275 */
276 pixelClock_MHz = config->pixelClock_Hz / 1000000U;
277 if (pixelClock_MHz <= 45U)
278 {
279 reg_m = 2U;
280 }
281 else if (pixelClock_MHz <= 92U)
282 {
283 reg_m = 1U;
284 }
285 else
286 {
287 reg_m = 0U;
288 }
289
290 #else
291 /*
292 * LDB_PHY_CTRL_M is configured based on pixel clock and NB.
293 *
294 * if NB = 1:
295 * input pixel clock REG_M
296 * 25M ~ 31M 2
297 * 32M ~ 62M 1
298 * 63M ~ 165M 0
299 *
300 * if NB = 0:
301 * input pixel clock REG_M
302 * 25M ~ 43M 2
303 * 44M ~ 89M 1
304 * 90M ~ 165M 0
305 *
306 * Current driver only supports NB=0 (7bit).
307 */
308 pixelClock_MHz = config->pixelClock_Hz / 1000000U;
309 if (pixelClock_MHz < 24U)
310 {
311 return kStatus_InvalidArgument;
312 }
313 else if (pixelClock_MHz <= 43U)
314 {
315 reg_m = 2U;
316 }
317 else if (pixelClock_MHz <= 89U)
318 {
319 reg_m = 1U;
320 }
321 else if (pixelClock_MHz <= 165U)
322 {
323 reg_m = 0U;
324 }
325 else
326 {
327 return kStatus_InvalidArgument;
328 }
329
330 reg = (base->PHY_CTRL & ~(LDB_PHY_CTRL_RFB_MASK | LDB_PHY_CTRL_M_MASK)) | LDB_PHY_CTRL_M(reg_m);
331 #endif
332
333 if (0U != ((uint32_t)kLDB_InputDataLatchOnRisingEdge & config->inputFlag))
334 {
335 reg |= LDB_PHY_CTRL_RFB_MASK;
336 }
337
338 base->PHY_CTRL = reg;
339
340 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
341 base->DPHY_PD_PLL = 0U;
342 base->DPHY_PD_TX = 0U;
343 base->DPHY_CO = reg_m;
344 base->ULPS = 0U;
345 base->PHY_CTRL = reg | LDB_PHY_CTRL_LVDS_EN_MASK;
346 #else
347 base->PHY_CTRL = reg | ((uint32_t)LDB_PHY_CTRL_CH0_EN_MASK << channel);
348 #endif
349
350 return kStatus_Success;
351 }
352
353 /*!
354 * brief De-initializes the LDB channel.
355 *
356 * param base LDB peripheral base address.
357 * param channel Channel index.
358 */
LDB_DeinitChannel(LDB_Type * base,uint8_t channel)359 void LDB_DeinitChannel(LDB_Type *base, uint8_t channel)
360 {
361 assert(channel < LDB_CH_COUNT);
362
363 #if (defined(FSL_FEATURE_LDB_COMBO_PHY) && FSL_FEATURE_LDB_COMBO_PHY)
364 base->PHY_CTRL &= ~LDB_PHY_CTRL_LVDS_EN_MASK;
365 base->ULPS = LDB_ULPS_ULPS_ENABLE_MASK;
366 base->DPHY_PD_TX = LDB_DPHY_PD_PLL_PD_MASK;
367 base->DPHY_PD_PLL = LDB_DPHY_PD_PLL_PD_MASK;
368 #else
369 base->PM_CTRL_REG &= ~(LDB_PM_CTRL_REG_CH_MODE_MASK(channel));
370
371 /* Power off the PHY */
372 base->PHY_CTRL &= ~((uint32_t)LDB_PHY_CTRL_CH0_EN_MASK << channel);
373 #endif
374 }
375