1 /*
2  * Copyright 2019-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_combo_phy"
17 #endif
18 
19 #define LDB_CH_COUNT 2U
20 
21 #define LDB_DPI_24BIT 5U
22 
23 #define LDB_PM_CTRL_REG_CH_MODE_MASK(ch) ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH0_MODE_MASK << ((ch)*2U))
24 #define LDB_PM_CTRL_REG_CH_DATA_WIDTH_MASK(ch) \
25     ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH0_DATA_WIDTH_MASK << ((ch)*2U))
26 #define LDB_PM_CTRL_REG_CH_BIT_MAPPING_MASK(ch) \
27     ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH0_BIT_MAPPING_MASK << ((ch)*2U))
28 #define LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(di) ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_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 #define LDB_SS_CTRL_CH_VSYNC_POL_MASK(ch) ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_SS_CRTL_CH0_VSYNC_POL_MASK << ((ch)*2U))
37 #define LDB_SS_CTRL_CH_HSYNC_POL_MASK(ch) ((uint32_t)MIPI_DSI_LVDS_COMBO_CSR_SS_CRTL_CH0_HSYNC_POL_MASK << ((ch)*2U))
38 
39 /*******************************************************************************
40  * Variables
41  ******************************************************************************/
42 
43 /*! @brief Pointers to LDB PHY control blocks. */
44 static MIPI_DSI_HOST_Type *const s_ldbPhyBases[] = MIPI_DSI_HOST_BASE_PTRS;
45 /*! @brief Pointers to ldb bases for each instance. */
46 static LDB_Type *const s_ldbBases[] = MIPI_DSI_LVDS_COMBO_CSR_BASE_PTRS;
47 
48 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
49 /*! @brief Pointers to LDB clocks for each instance. */
50 static const clock_ip_name_t s_ldbClocks[] = LDB_CLOCKS;
51 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
52 
53 /*******************************************************************************
54  * Prototypes
55  ******************************************************************************/
56 /*!
57  * @brief Get the LDB instance from peripheral base address.
58  *
59  * @param base LDB peripheral base address.
60  * @return LDB instance.
61  */
62 static uint32_t LDB_GetInstance(LDB_Type *base);
63 
64 /*!
65  * @brief Get the register value based on pixel map.
66  *
67  * @param outputBus Pixel map.
68  * @param ch Channel.
69  * @return Register value.
70  */
71 static uint32_t LDB_GetPixelMapConfig(ldb_output_bus_t outputBus, uint8_t ch);
72 
73 /*!
74  * @brief Get the register value based on pixel map.
75  *
76  * @param outputBus Pixel map.
77  * @param ch Channel.
78  * @return Register value.
79  */
80 static MIPI_DSI_HOST_Type *LDB_GetPhyControlBlock(LDB_Type *base);
81 
82 /*******************************************************************************
83  * Code
84  ******************************************************************************/
LDB_GetInstance(LDB_Type * base)85 static uint32_t LDB_GetInstance(LDB_Type *base)
86 {
87     uint32_t instance;
88 
89     /* Find the instance index from base address mappings. */
90     for (instance = 0U; instance < ARRAY_SIZE(s_ldbBases); instance++)
91     {
92         if (s_ldbBases[instance] == base)
93         {
94             break;
95         }
96     }
97 
98     assert(instance < ARRAY_SIZE(s_ldbBases));
99 
100     return instance;
101 }
102 
LDB_GetPixelMapConfig(ldb_output_bus_t outputBus,uint8_t ch)103 static uint32_t LDB_GetPixelMapConfig(ldb_output_bus_t outputBus, uint8_t ch)
104 {
105     return (uint32_t)outputBus << (ch * 2U);
106 }
107 
LDB_GetPhyControlBlock(LDB_Type * base)108 static MIPI_DSI_HOST_Type *LDB_GetPhyControlBlock(LDB_Type *base)
109 {
110     return s_ldbPhyBases[LDB_GetInstance(base)];
111 }
112 
113 /*!
114  * brief Initializes the LDB module.
115  *
116  * param base LDB peripheral base address.
117  */
LDB_Init(LDB_Type * base)118 void LDB_Init(LDB_Type *base)
119 {
120 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
121     (void)CLOCK_EnableClock(s_ldbClocks[LDB_GetInstance(base)]);
122 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
123 
124     base->SS_CRTL = 0U;
125     base->PM_CTRL = 0U;
126 
127     base->LVDS_PHY_CTRL =
128         MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_LVDS_EN(0) /* Disable. */
129         | MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_RFB(1)   /* Clock edge. 0: Falling edge. 1: Rising edge. */
130         | MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_CA(4)    /* Output current. */
131         | MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_CCM(4);  /* voltage control . */
132 
133     base->PXL2DPI_CTRL = LDB_DPI_24BIT;
134     base->ULPS_CTRL    = MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK; /* Set to lowpower mode. */
135 }
136 
137 /*!
138  * brief De-initializes the LDB module.
139  *
140  * param base LDB peripheral base address.
141  */
LDB_Deinit(LDB_Type * base)142 void LDB_Deinit(LDB_Type *base)
143 {
144     base->LVDS_PHY_CTRL = 0U;
145 
146 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
147     (void)CLOCK_DisableClock(s_ldbClocks[LDB_GetInstance(base)]);
148 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
149 }
150 
151 /*!
152  * brief Initializes the LDB channel.
153  *
154  * param base LDB peripheral base address.
155  * param channel Channel index.
156  * param config Pointer to the configuration.
157  * return Return kStatus_Success if success.
158  */
LDB_InitChannel(LDB_Type * base,uint8_t channel,const ldb_channel_config_t * config)159 status_t LDB_InitChannel(LDB_Type *base, uint8_t channel, const ldb_channel_config_t *config)
160 {
161     assert(channel < LDB_CH_COUNT);
162 
163     uint32_t reg;
164     uint32_t reg_m;
165     uint32_t pixelClock_MHz;
166 
167     MIPI_DSI_HOST_Type *phy = LDB_GetPhyControlBlock(base);
168 
169     reg = base->SS_CRTL & ~(LDB_SS_CTRL_CH_VSYNC_POL_MASK(channel) | LDB_SS_CTRL_CH_HSYNC_POL_MASK(channel));
170 
171     if (0U != (config->inputFlag & (uint32_t)kLDB_InputVsyncActiveHigh))
172     {
173         reg |= LDB_SS_CTRL_CH_VSYNC_POL_MASK(channel);
174     }
175 
176     if (0U != (config->inputFlag & (uint32_t)kLDB_InputHsyncActiveHigh))
177     {
178         reg |= LDB_SS_CTRL_CH_HSYNC_POL_MASK(channel);
179     }
180 
181     base->SS_CRTL = reg;
182 
183     /* CH0 to DI0, CH1 to DI1 */
184     reg = base->PM_CTRL & ~(LDB_PM_CTRL_REG_DI_MASK(channel) | LDB_PM_CTRL_REG_CH_MASK(channel));
185 
186     reg |= LDB_GetPixelMapConfig(config->outputBus, channel);
187 
188     if (0U != (config->inputFlag & (uint32_t)kLDB_InputVsyncActiveHigh))
189     {
190         reg |= LDB_PM_CTRL_REG_DI_VS_POLARITY_MASK(channel);
191     }
192 
193     if (channel == 0U)
194     {
195         reg |= (1UL << MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH0_MODE_SHIFT);
196     }
197     else
198     {
199         reg |= (3UL << MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH1_MODE_SHIFT);
200     }
201 
202     reg |= MIPI_DSI_LVDS_COMBO_CSR_PM_CTRL_CH_SEL(channel);
203 
204     base->PM_CTRL = reg;
205 
206     reg = (base->LVDS_PHY_CTRL & ~MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_RFB_MASK);
207 
208     /*
209      * DPHY_CO is configured based on pixel clock and NB.
210      *
211      * if NB = 1:
212      *         input pixel clock           REG_M
213      *            25M ~ 32M                  2
214      *            33M ~ 64M                  1
215      *            65M ~ 165M                 0
216      *
217      * if NB = 0:
218      *         input pixel clock           REG_M
219      *            25M ~ 45M                  2
220      *            46M ~ 92M                  1
221      *            93M ~ 165M                 0
222      *
223      * Current driver only supports NB=0 (7bit).
224      */
225     pixelClock_MHz = config->pixelClock_Hz / 1000000U;
226     if (pixelClock_MHz <= 45U)
227     {
228         reg_m = 2U;
229     }
230     else if (pixelClock_MHz <= 92U)
231     {
232         reg_m = 1U;
233     }
234     else
235     {
236         reg_m = 0U;
237     }
238 
239     if (0U != ((uint32_t)kLDB_InputDataLatchOnRisingEdge & config->inputFlag))
240     {
241         reg |= MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_RFB_MASK;
242     }
243 
244     base->LVDS_PHY_CTRL = reg;
245     phy->PD_PLL         = 0U;
246     phy->PD_TX          = 0U;
247     phy->CO             = reg_m;
248     base->ULPS_CTRL     = 0U;
249     base->LVDS_PHY_CTRL = reg | MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_LVDS_EN_MASK;
250 
251     return kStatus_Success;
252 }
253 
254 /*!
255  * brief De-initializes the LDB channel.
256  *
257  * param base LDB peripheral base address.
258  * param channel Channel index.
259  */
LDB_DeinitChannel(LDB_Type * base,uint8_t channel)260 void LDB_DeinitChannel(LDB_Type *base, uint8_t channel)
261 {
262     assert(channel < LDB_CH_COUNT);
263 
264     MIPI_DSI_HOST_Type *phy = LDB_GetPhyControlBlock(base);
265 
266     base->LVDS_PHY_CTRL &= ~MIPI_DSI_LVDS_COMBO_CSR_LVDS_PHY_CTRL_LVDS_EN_MASK;
267     base->ULPS_CTRL  = MIPI_DSI_LVDS_COMBO_CSR_ULPS_CTRL_TX_ULPS_MASK;
268     phy->PD_TX       = MIPI_DSI_HOST_PD_TX_PD_TX_MASK;
269     phy->PD_PLL      = MIPI_DSI_HOST_PD_PLL_PD_PLL_MASK;
270 }
271