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