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