1 /*
2  * Copyright 2018, 2020 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_video_common.h"
9 #include "fsl_display.h"
10 #include "fsl_it6263.h"
11 
12 /*******************************************************************************
13  * Definitions
14  ******************************************************************************/
15 #define IT6263_LVDS_ID (0x66U / 2U)
16 
17 #define IT6263_HDMI_VENDER_ID 0x01ca1376U
18 #define IT6263_LVDS_VENDER_ID 0x15ca6162U
19 
20 #define IT6263_I2C_WriteReg(handle, addr, reg, value)                                 \
21     VIDEO_I2C_WriteReg(addr, kVIDEO_RegAddr8Bit, (reg), kVIDEO_RegWidth8Bit, (value), \
22                        ((const it6263_resource_t *)((handle)->resource))->i2cSendFunc)
23 
24 #define IT6263_I2C_ReadReg(handle, addr, reg, value)                                 \
25     VIDEO_I2C_ReadReg(addr, kVIDEO_RegAddr8Bit, (reg), kVIDEO_RegWidth8Bit, (value), \
26                       ((const it6263_resource_t *)((handle)->resource))->i2cReceiveFunc)
27 
28 #define IT6263_I2C_ModifyReg(handle, addr, reg, mask, value)                                 \
29     VIDEO_I2C_ModifyReg(addr, kVIDEO_RegAddr8Bit, (reg), kVIDEO_RegWidth8Bit, mask, (value), \
30                         ((const it6263_resource_t *)((handle)->resource))->i2cReceiveFunc,   \
31                         ((const it6263_resource_t *)((handle)->resource))->i2cSendFunc)
32 
33 #define IT6263_I2C_ReadRegs(handle, addr, reg, value, len)                              \
34     VIDEO_I2C_ReadReg(addr, kVIDEO_RegAddr8Bit, (reg), (video_reg_width_t)len, (value), \
35                       ((const it6263_resource_t *)((handle)->resource))->i2cReceiveFunc)
36 
37 #define IT6263_SET_LVDS_ID_REG    0x1DU
38 #define IT6263_ENABLE_LVDS_ID_REG 0x1EU
39 
40 #define IT6263_HDMI_VENDER_ID_REG 0
41 #define IT6263_LVDS_VENDER_ID_REG 0
42 
43 #define IT6263_LVDS_COLOR_DEPTH(x)   ((x) << 0U)
44 #define IT6263_LVDS_COLOR_DEPTH_MASK (3U << 0U)
45 #define IT6263_LVDS_MAP(x)           ((x) << 4U)
46 #define IT6263_LVDS_MAP_MASK         (1U << 4U)
47 #define IT6263_LVDS_DUAL_MODE(x)     ((x) << 7U)
48 #define IT6263_LVDS_DUAL_MODE_MASK   (1U << 7U)
49 
50 /* Color depth. */
51 #define IT6263_LVDS_COLOR_6BIT  IT6263_LVDS_COLOR_DEPTH(0U)
52 #define IT6263_LVDS_COLOR_8BIT  IT6263_LVDS_COLOR_DEPTH(1U)
53 #define IT6263_LVDS_COLOR_10BIT IT6263_LVDS_COLOR_DEPTH(2U)
54 #define IT6263_LVDS_COLOR_12BIT IT6263_LVDS_COLOR_DEPTH(3U)
55 
56 /* Pixel map. */
57 #define IT6263_LVDS_JEIDA IT6263_LVDS_MAP(0U)
58 #define IT6263_LVDS_VESA  IT6263_LVDS_MAP(1U)
59 
60 /* Dual mode. */
61 #define IT6263_LVDS_DISO   IT6263_LVDS_DUAL_MODE(1U) /* Dual In / Single Out */
62 #define IT6263_LVDS_DIRECT IT6263_LVDS_DUAL_MODE(0U) /* Single In / Single Out or Dual In / Dual Out */
63 
64 /* HDMI register 0x04. */
65 #define HDMI_REG_SW_RST                0x04U
66 #define IT6263_HDMI_04_SOFTREFRST_MASK (1U << 5U)
67 #define IT6263_HDMI_04_SOFTARST_MASK   (1U << 4U)
68 #define IT6263_HDMI_04_SOFTVRST_MASK   (1U << 3U)
69 #define IT6263_HDMI_04_AUDRST_MASK     (1U << 2U)
70 #define IT6263_HDMI_04_HDCPRST_MASK    (1U << 0U)
71 #define IT6263_HDMI_04_ALLRST_MASK     ((1U << 5U) | (1U << 4U) | (1U << 3U) | (1U << 2U) | (1U << 0U))
72 
73 /* HDMI register 0x61. */
74 #define IT6263_HDMI_61_DRV_PWD_MASK (1U << 5U)
75 #define IT6263_HDMI_61_DRV_RST_MASK (1U << 4U)
76 
77 /* HDMI register 0xC1. */
78 #define IT6263_HDMI_C1_AVMUTE_MASK (1U << 0U)
79 
80 /* HDMI register 0xC6. */
81 #define IT6263_HDMI_C6_PKTGENCTRLRPT_MASK (1U << 1U)
82 #define IT6263_HDMI_C6_PKTGENCTRLEN_MASK  (1U << 0U)
83 
84 /* LVDS register 0x05. */
85 #define IT6263_LVDS_05_SOFTREFRST_MASK (1U << 0U)
86 #define IT6263_LVDS_05_SOFTRST_MASK    (1U << 1U)
87 
88 #define IT6263_CHECK_RET(x)            \
89     do                                 \
90     {                                  \
91         status = (x);                  \
92         if (kStatus_Success != status) \
93         {                              \
94             return status;             \
95         }                              \
96     } while (false)
97 
98 /*******************************************************************************
99  * Variables
100  ******************************************************************************/
101 const display_operations_t it6263_ops = {
102     .init   = IT6263_Init,
103     .deinit = IT6263_Deinit,
104     .start  = IT6263_Start,
105     .stop   = IT6263_Stop,
106 };
107 
108 /*******************************************************************************
109  * Code
110  ******************************************************************************/
111 
IT6263_HardwareReset(display_handle_t * handle)112 static void IT6263_HardwareReset(display_handle_t *handle)
113 {
114     const it6263_resource_t *resource = (const it6263_resource_t *)(handle->resource);
115 
116     resource->pullResetPin(true);
117 
118     VIDEO_DelayMs(1);
119 
120     resource->pullResetPin(false);
121 
122     VIDEO_DelayMs(40);
123 
124     resource->pullResetPin(true);
125 
126     VIDEO_DelayMs(10);
127 }
128 
IT6263_LVDSReset(display_handle_t * handle)129 static status_t IT6263_LVDSReset(display_handle_t *handle)
130 {
131     status_t status;
132 
133     /* Reset the AFE PLL. */
134     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x3C, 0x1, 0x0));
135     VIDEO_DelayMs(1);
136     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x3C, 0x1, 0x1));
137 
138     /* Reset the PCLK. */
139     status =
140         IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x05, IT6263_LVDS_05_SOFTRST_MASK, IT6263_LVDS_05_SOFTRST_MASK);
141     if (kStatus_Success != status)
142     {
143         return status;
144     }
145 
146     VIDEO_DelayMs(1);
147     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x05, IT6263_LVDS_05_SOFTRST_MASK, 0));
148 
149     VIDEO_DelayMs(1);
150 
151     return kStatus_Success;
152 }
153 
IT6263_InitLVDS_ID(display_handle_t * handle)154 static status_t IT6263_InitLVDS_ID(display_handle_t *handle)
155 {
156     status_t status;
157 
158     uint8_t i2cAddr = (((const it6263_resource_t *)(handle->resource))->i2cAddr) / 2U;
159 
160     status = IT6263_I2C_WriteReg(handle, i2cAddr, IT6263_SET_LVDS_ID_REG, IT6263_LVDS_ID * 2U);
161 
162     if (kStatus_Success == status)
163     {
164         status = IT6263_I2C_WriteReg(handle, i2cAddr, IT6263_ENABLE_LVDS_ID_REG, 1);
165     }
166 
167     return status;
168 }
169 
IT6263_Identify(display_handle_t * handle)170 static status_t IT6263_Identify(display_handle_t *handle)
171 {
172     status_t status;
173     uint32_t hdmiVendorID = 0U;
174     uint32_t lvdsVendorID = 0U;
175 
176     uint8_t i2cAddr = (((const it6263_resource_t *)(handle->resource))->i2cAddr) / 2U;
177 
178     status = IT6263_I2C_ReadRegs(handle, i2cAddr, IT6263_HDMI_VENDER_ID_REG, &hdmiVendorID, sizeof(hdmiVendorID));
179     if (kStatus_Success != status)
180     {
181         return status;
182     }
183 
184     status =
185         IT6263_I2C_ReadRegs(handle, IT6263_LVDS_ID, IT6263_LVDS_VENDER_ID_REG, &lvdsVendorID, sizeof(lvdsVendorID));
186     if (kStatus_Success != status)
187     {
188         return status;
189     }
190 
191     if ((hdmiVendorID != IT6263_HDMI_VENDER_ID) || (lvdsVendorID != IT6263_LVDS_VENDER_ID))
192     {
193         return kStatus_Fail;
194     }
195     else
196     {
197         return kStatus_Success;
198     }
199 }
200 
IT6263_InitLVDS(display_handle_t * handle)201 static status_t IT6263_InitLVDS(display_handle_t *handle)
202 {
203     status_t status;
204     uint8_t mask;
205     uint8_t val;
206 
207     /* Configure LVDS. */
208     mask = IT6263_LVDS_COLOR_DEPTH_MASK | IT6263_LVDS_MAP_MASK | IT6263_LVDS_DUAL_MODE_MASK;
209     val  = IT6263_LVDS_COLOR_8BIT | IT6263_LVDS_JEIDA | IT6263_LVDS_DIRECT;
210 
211     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x2C, mask, val));
212 
213     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x52, 0x02, 0x00));
214 
215     /* AFE */
216     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, IT6263_LVDS_ID, 0x3E, 0xAA));
217     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, IT6263_LVDS_ID, 0x3F, 0x02));
218     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, IT6263_LVDS_ID, 0x47, 0xAA));
219     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, IT6263_LVDS_ID, 0x48, 0x02));
220     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, IT6263_LVDS_ID, 0x4F, 0x11));
221 
222     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, IT6263_LVDS_ID, 0x3C, 0x07, 0));
223 
224     return kStatus_Success;
225 }
226 
IT6263_Init(display_handle_t * handle,const display_config_t * config)227 status_t IT6263_Init(display_handle_t *handle, const display_config_t *config)
228 {
229     assert(handle);
230 
231     status_t status;
232 
233     uint8_t i2cAddr = ((const it6263_resource_t *)(handle->resource))->i2cAddr / 2U;
234 
235     IT6263_HardwareReset(handle);
236 
237     /* Software reset. */
238     status = IT6263_I2C_WriteReg(handle, i2cAddr, 0x04, IT6263_HDMI_04_ALLRST_MASK);
239     if (kStatus_Success != status)
240     {
241         return status;
242     }
243 
244     VIDEO_DelayMs(1);
245 
246     status = IT6263_InitLVDS_ID(handle);
247     if (kStatus_Success != status)
248     {
249         return status;
250     }
251 
252     status = IT6263_Identify(handle);
253     if (kStatus_Success != status)
254     {
255         return status;
256     }
257 
258     IT6263_CHECK_RET(IT6263_LVDSReset(handle));
259 
260     IT6263_CHECK_RET(IT6263_InitLVDS(handle));
261 
262     /*
263      * Set color:
264      * 0 RGB
265      * 1 YUV422
266      * 2 YUV444
267      */
268     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x70, 0x03U << 6U, 0));
269 
270     /*
271      * No color space conversion.
272      * 0: No conversion
273      * 1: RGB -> YUV
274      * 2: YUV -> RGB
275      */
276     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x72, 0x03U << 0U, 0));
277 
278     /*
279      * HDMI color dpeth:
280      * 000 - color depth is not indicate (as 8bit)
281      * 100 - 8/8/8 bit color
282      * 101 - 10/10/10 bit color
283      * 110 - 12/12/12 bit color)
284      */
285     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0xC1, 0x07U << 4U, 0x04U << 0U));
286 
287     /* Select HDMI. */
288     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0xC0, 0x01));
289 
290     /* Set AFE */
291     if (config->pixelClock_Hz > 80000000U)
292     {
293         IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x62, 0x88));
294         IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x64, 0x84));
295     }
296     else
297     {
298         IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x62, 0x18));
299         IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x64, 0x0C));
300     }
301     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x63, 0x10));
302 
303     /*
304      * Output Color Mode
305      * 00 - RGB444 mode
306      * 01 - YCbCr422 mode
307      * 10 - YCbCr444 mode
308      */
309     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x0F, 0x03U << 0U, 0x01U << 0U)); /* Bank 0 */
310     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x58, 0x03U << 5U, 0x00U << 5U));
311     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x0F, 0x03U << 0U, 0x00U << 0U)); /* Bank 1 */
312 
313     /* software video reset */
314     status = IT6263_I2C_ModifyReg(handle, i2cAddr, 0x04, IT6263_HDMI_04_SOFTVRST_MASK, IT6263_HDMI_04_SOFTVRST_MASK);
315     if (kStatus_Success != status)
316     {
317         return status;
318     }
319 
320     VIDEO_DelayMs(100);
321 
322     return kStatus_Success;
323 }
324 
IT6263_Deinit(display_handle_t * handle)325 status_t IT6263_Deinit(display_handle_t *handle)
326 {
327     const it6263_resource_t *resource = (const it6263_resource_t *)(handle->resource);
328 
329     resource->pullResetPin(false);
330 
331     return kStatus_Success;
332 }
333 
IT6263_Start(display_handle_t * handle)334 status_t IT6263_Start(display_handle_t *handle)
335 {
336     status_t status;
337 
338     uint8_t i2cAddr = ((const it6263_resource_t *)(handle->resource))->i2cAddr / 2U;
339 
340     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0x04, IT6263_HDMI_04_SOFTVRST_MASK, 0));
341     IT6263_CHECK_RET(IT6263_I2C_WriteReg(handle, i2cAddr, 0x61, 0));
342     IT6263_CHECK_RET(IT6263_I2C_ModifyReg(handle, i2cAddr, 0xC1, IT6263_HDMI_C1_AVMUTE_MASK, 0));
343     return IT6263_I2C_WriteReg(handle, i2cAddr, 0xc6,
344                                IT6263_HDMI_C6_PKTGENCTRLRPT_MASK | IT6263_HDMI_C6_PKTGENCTRLEN_MASK);
345 }
346 
IT6263_Stop(display_handle_t * handle)347 status_t IT6263_Stop(display_handle_t *handle)
348 {
349     status_t status;
350     uint8_t i2cAddr = ((const it6263_resource_t *)(handle->resource))->i2cAddr / 2U;
351 
352     status = IT6263_I2C_ModifyReg(handle, i2cAddr, 0xC1, IT6263_HDMI_C1_AVMUTE_MASK, IT6263_HDMI_C1_AVMUTE_MASK);
353 
354     if (kStatus_Success == status)
355     {
356         status = IT6263_I2C_WriteReg(handle, i2cAddr, 0xC6, 0);
357     }
358 
359     if (kStatus_Success == status)
360     {
361         status =
362             IT6263_I2C_ModifyReg(handle, i2cAddr, 0x04, IT6263_HDMI_04_SOFTVRST_MASK, IT6263_HDMI_04_SOFTVRST_MASK);
363     }
364 
365     if (kStatus_Success == status)
366     {
367         status = IT6263_I2C_WriteReg(handle, i2cAddr, 0x61, IT6263_HDMI_61_DRV_PWD_MASK | IT6263_HDMI_61_DRV_RST_MASK);
368     }
369 
370     return status;
371 }
372