1 /*
2  * Copyright (c) 2021 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_common.h"
9 #include "hpm_lcdc_drv.h"
10 
11 #define LCDC_FIFO_THRESHOLD (0x70)
12 
lcdc_pixel_format(display_pixel_format_t format)13 static uint32_t lcdc_pixel_format(display_pixel_format_t format)
14 {
15     switch (format) {
16     case display_pixel_format_argb8888:
17         return 9;
18     case display_pixel_format_rgb565:
19         return 4;
20     case display_pixel_format_yuv422:
21         return 7;
22     case display_pixel_format_ycbcr422:
23         return 7;
24     case display_pixel_format_y8:
25         return 0xb;
26     case display_pixel_format_raw8:
27         return 0xb;
28     default:
29         return 9;
30     }
31 }
32 
33 /*!
34  * @brief Get LCDC byteorder value.
35  *
36  * @param byteorder Dispaly byteorder value.
37  * @return LCDC byteorder value.
38  */
lcdc_byteorder(display_byteorder_t byteorder)39 static uint8_t lcdc_byteorder(display_byteorder_t byteorder)
40 {
41     switch (byteorder) {
42     case display_byteorder_a3a2a1a0: /* LSB */
43         return 0;
44     case display_byteorder_a0a1a2a3: /* MSB */
45         return 1;
46     default:
47         return 0;
48     }
49 }
50 
lcdc_get_default_layer_config(LCDC_Type * ptr,lcdc_layer_config_t * layer,display_pixel_format_t pixel_format,uint8_t layer_index)51 void lcdc_get_default_layer_config(LCDC_Type *ptr, lcdc_layer_config_t *layer, display_pixel_format_t pixel_format, uint8_t layer_index)
52 {
53     (void) ptr;
54     layer->max_bytes = lcdc_layer_max_bytes_64;
55     /* different layer has different max_ot configuration */
56     if (layer_index < LCDC_SOC_MAX_CSC_LAYER_COUNT) {
57         layer->max_ot = 0;
58     } else {
59         layer->max_ot = 2;
60     }
61     layer->byteorder = display_byteorder_a3a2a1a0;
62     if (display_pixel_format_is_yuv_format(pixel_format)) {
63         layer->yuv = display_yuv_mode_422_y1u1y2v1; /* If YUV format, change byte sequence to YUYV */
64     } else {
65         layer->yuv = display_yuv_mode_422_u1y1v1y2; /* Not change byte sequence */
66     }
67     layer->pixel_format = pixel_format;
68 
69     layer->alphablend.src_alpha = 0;
70     layer->alphablend.dst_alpha = 0;
71     layer->alphablend.src_alpha_op = display_alpha_op_invalid;
72     layer->alphablend.dst_alpha_op = display_alpha_op_invalid;
73     layer->alphablend.mode = display_alphablend_mode_clear;
74     layer->stride = 0;
75 
76     switch (pixel_format) {
77     case display_pixel_format_yuv422:
78         layer->csc_config.enable = true;
79         layer->csc_config.ycbcr_mode = false;
80         layer->csc_config.yuv2rgb_coef.c0 = 0x100;
81         layer->csc_config.yuv2rgb_coef.uv_offset = 0;
82         layer->csc_config.yuv2rgb_coef.y_offset = 0;
83         layer->csc_config.yuv2rgb_coef.c1 = 0x123;
84         layer->csc_config.yuv2rgb_coef.c2 = 0x76B;
85         layer->csc_config.yuv2rgb_coef.c3 = 0x79C;
86         layer->csc_config.yuv2rgb_coef.c4 = 0x208;
87         break;
88     case display_pixel_format_ycbcr422:
89         layer->csc_config.enable = true;
90         layer->csc_config.ycbcr_mode = true;
91         layer->csc_config.yuv2rgb_coef.c0 = 0x12A;
92         layer->csc_config.yuv2rgb_coef.uv_offset = 0x180;
93         layer->csc_config.yuv2rgb_coef.y_offset = 0x1F0;
94         layer->csc_config.yuv2rgb_coef.c1 = 0x198;
95         layer->csc_config.yuv2rgb_coef.c2 = 0x730;
96         layer->csc_config.yuv2rgb_coef.c3 = 0x79C;
97         layer->csc_config.yuv2rgb_coef.c4 = 0x204;
98         break;
99     default:
100         layer->csc_config.enable = false;
101         layer->csc_config.ycbcr_mode = false;
102         layer->csc_config.yuv2rgb_coef.c0 = 0;
103         layer->csc_config.yuv2rgb_coef.uv_offset = 0;
104         layer->csc_config.yuv2rgb_coef.y_offset = 0;
105         layer->csc_config.yuv2rgb_coef.c1 = 0;
106         layer->csc_config.yuv2rgb_coef.c2 = 0;
107         layer->csc_config.yuv2rgb_coef.c3 = 0;
108         layer->csc_config.yuv2rgb_coef.c4 = 0;
109         break;
110     }
111 }
112 
lcdc_get_default_config(LCDC_Type * ptr,lcdc_config_t * config)113 void lcdc_get_default_config(LCDC_Type *ptr, lcdc_config_t *config)
114 {
115     (void) ptr;
116     config->resolution_x = 480;
117     config->resolution_y = 272;
118     config->hsync.front_porch_pulse = 40;
119     config->hsync.back_porch_pulse = 50;
120     config->hsync.pulse_width = 30;
121     config->vsync.front_porch_pulse = 20;
122     config->vsync.back_porch_pulse = 20;
123     config->vsync.pulse_width = 10;
124     config->background.u = 0x0;
125 
126     config->control.display_mode = lcdc_display_mode_normal;
127     config->control.line_pattern = lcdc_line_pattern_rgb;
128     config->control.invert_pixel_clock = false;
129     config->control.invert_pixel_data = false;
130     config->control.invert_href = false;
131     config->control.invert_vsync = false;
132     config->control.invert_hsync = false;
133 }
134 
lcdc_reset_register_values(LCDC_Type * ptr)135 void lcdc_reset_register_values(LCDC_Type *ptr)
136 {
137     uint8_t i = 0;
138 
139     lcdc_turn_off_display(ptr);
140 
141     ptr->DISP_WN_SIZE = 0;
142     ptr->INT_EN = 0;
143     ptr->ST = 0xFFFFFFFFU;
144     ptr->DMA_ST = 0xFFFFFFFFU;
145     ptr->VSYNC_PARA = 0x00C01803U;
146     ptr->HSYNC_PARA = 0x00C01803U;
147 
148     for (i = 0; i < LCDC_SOC_MAX_LAYER_COUNT; i++) {
149         ptr->LAYER[i].LAYCTRL = 0;
150         ptr->LAYER[i].ALPHAS = 0;
151         ptr->LAYER[i].LAYSIZE = 0;
152         ptr->LAYER[i].LAYPOS = 0;
153         ptr->LAYER[i].START0 = 0;
154         ptr->LAYER[i].LINECFG = 0;
155         ptr->LAYER[i].BG_CL = 0;
156     }
157 
158     for (i = 0; i < LCDC_SOC_MAX_CSC_LAYER_COUNT; i++) {
159         ptr->LAYER[i].CSC_COEF0 = 0;
160         ptr->LAYER[i].CSC_COEF1 = 0;
161         ptr->LAYER[i].CSC_COEF2 = 0;
162     }
163 }
164 
lcdc_init(LCDC_Type * ptr,lcdc_config_t * config)165 void lcdc_init(LCDC_Type *ptr, lcdc_config_t *config)
166 {
167     lcdc_reset_register_values(ptr);
168 
169     ptr->DISP_WN_SIZE = LCDC_DISP_WN_SIZE_X_SET(config->resolution_x) |
170                     LCDC_DISP_WN_SIZE_Y_SET(config->resolution_y);
171     ptr->HSYNC_PARA =
172         LCDC_HSYNC_PARA_FP_SET(config->hsync.front_porch_pulse)
173       | LCDC_HSYNC_PARA_BP_SET(config->hsync.back_porch_pulse)
174       | LCDC_HSYNC_PARA_PW_SET(config->hsync.pulse_width);
175     ptr->BGND_CL = LCDC_BGND_CL_B_SET(config->background.b)
176         | LCDC_BGND_CL_G_SET(config->background.g)
177         | LCDC_BGND_CL_R_SET(config->background.r);
178     ptr->VSYNC_PARA =
179         LCDC_VSYNC_PARA_FP_SET(config->vsync.front_porch_pulse)
180       | LCDC_VSYNC_PARA_BP_SET(config->vsync.back_porch_pulse)
181       | LCDC_VSYNC_PARA_PW_SET(config->vsync.pulse_width);
182     ptr->TXFIFO = LCDC_TXFIFO_THRSH_SET(LCDC_FIFO_THRESHOLD);
183     ptr->CTRL = LCDC_CTRL_DISP_MODE_SET(config->control.display_mode)
184         | LCDC_CTRL_LINE_PATTERN_SET(config->control.line_pattern)
185         | LCDC_CTRL_INV_PXDATA_SET(config->control.invert_pixel_data)
186         | LCDC_CTRL_INV_PXCLK_SET(config->control.invert_pixel_clock)
187         | LCDC_CTRL_INV_HREF_SET(config->control.invert_href)
188         | LCDC_CTRL_INV_VSYNC_SET(config->control.invert_vsync)
189         | LCDC_CTRL_INV_HSYNC_SET(config->control.invert_hsync);
190 }
191 
lcdc_config_layer(LCDC_Type * ptr,uint8_t layer_index,lcdc_layer_config_t * layer,bool enable_layer)192 hpm_stat_t lcdc_config_layer(LCDC_Type *ptr,
193                        uint8_t layer_index,
194                        lcdc_layer_config_t *layer,
195                        bool enable_layer)
196 {
197     uint8_t byteorder;
198     uint32_t pitch;
199     uint32_t format;
200     uint32_t ctrl = ptr->LAYER[layer_index].LAYCTRL;
201 
202     if ((!LCDC_SOC_LAYER_SUPPORTS_CSC(layer_index) && layer->csc_config.enable)
203          || (!LCDC_SOC_LAYER_SUPPORTS_YUV(layer_index)
204              && (display_pixel_format_is_yuv_format(layer->pixel_format)))) {
205         return status_lcdc_layer_not_supported;
206     }
207 
208     ptr->LAYER[layer_index].LAYSIZE =
209         LCDC_LAYER_LAYSIZE_HEIGHT_SET(layer->height)
210       | LCDC_LAYER_LAYSIZE_WIDTH_SET(layer->width);
211     ptr->LAYER[layer_index].LAYPOS =
212         LCDC_LAYER_LAYPOS_X_SET(layer->position_x)
213       | LCDC_LAYER_LAYPOS_Y_SET(layer->position_y);
214     ptr->LAYER[layer_index].START0 = LCDC_LAYER_START0_ADDR0_SET((uint32_t)layer->buffer);
215     ptr->LAYER[layer_index].ALPHAS = LCDC_LAYER_ALPHAS_LOCD_SET(layer->alphablend.src_alpha)
216         | LCDC_LAYER_ALPHAS_IND_SET(layer->alphablend.dst_alpha);
217 
218     pitch = layer->stride > 0 ? layer->stride : display_get_pitch_length_in_byte(layer->pixel_format, layer->width);
219     ptr->LAYER[layer_index].LINECFG = LCDC_LAYER_LINECFG_MPT_SIZE_SET(layer->max_bytes)
220         | LCDC_LAYER_LINECFG_MAX_OT_SET(layer->max_ot)
221         | LCDC_LAYER_LINECFG_PITCH_SET(pitch);
222     ptr->LAYER[layer_index].BG_CL = LCDC_LAYER_BG_CL_ARGB_SET(layer->background.u);
223 
224     ptr->LAYER[layer_index].CSC_COEF0 =
225         LCDC_LAYER_CSC_COEF0_ENABLE_SET(layer->csc_config.enable)
226         | LCDC_LAYER_CSC_COEF0_YCBCR_MODE_SET(layer->csc_config.ycbcr_mode)
227         | LCDC_LAYER_CSC_COEF0_C0_SET(layer->csc_config.yuv2rgb_coef.c0)
228         | LCDC_LAYER_CSC_COEF0_UV_OFFSET_SET(layer->csc_config.yuv2rgb_coef.uv_offset)
229         | LCDC_LAYER_CSC_COEF0_Y_OFFSET_SET(layer->csc_config.yuv2rgb_coef.y_offset);
230     ptr->LAYER[layer_index].CSC_COEF1 =
231         LCDC_LAYER_CSC_COEF1_C1_SET(layer->csc_config.yuv2rgb_coef.c1)
232         | LCDC_LAYER_CSC_COEF1_C4_SET(layer->csc_config.yuv2rgb_coef.c4);
233     ptr->LAYER[layer_index].CSC_COEF2 =
234         LCDC_LAYER_CSC_COEF2_C2_SET(layer->csc_config.yuv2rgb_coef.c2)
235         | LCDC_LAYER_CSC_COEF2_C3_SET(layer->csc_config.yuv2rgb_coef.c3);
236 
237     /* bit18 is reserved but has to be set to 1 */
238     ctrl |= 1 << 18;
239 
240     byteorder = lcdc_byteorder(layer->byteorder);
241     format = lcdc_pixel_format(layer->pixel_format);
242     ctrl = (ctrl & ~(LCDC_LAYER_LAYCTRL_PIXFORMAT_MASK
243                 | LCDC_LAYER_LAYCTRL_AB_MODE_MASK
244                 | LCDC_LAYER_LAYCTRL_LOCALPHA_OP_MASK
245                 | LCDC_LAYER_LAYCTRL_INALPHA_OP_MASK
246                 | LCDC_LAYER_LAYCTRL_YUV_FORMAT_MASK))
247         | LCDC_LAYER_LAYCTRL_PACK_DIR_SET(byteorder)
248         | LCDC_LAYER_LAYCTRL_PIXFORMAT_SET(format)
249         | LCDC_LAYER_LAYCTRL_AB_MODE_SET(layer->alphablend.mode)
250         | LCDC_LAYER_LAYCTRL_LOCALPHA_OP_SET(layer->alphablend.src_alpha_op)
251         | LCDC_LAYER_LAYCTRL_INALPHA_OP_SET(layer->alphablend.dst_alpha_op)
252         | LCDC_LAYER_LAYCTRL_YUV_FORMAT_SET(layer->yuv);
253 
254     if (enable_layer) {
255         ctrl |= LCDC_LAYER_LAYCTRL_EN_MASK;
256     }
257     ptr->LAYER[layer_index].LAYCTRL = ctrl | LCDC_LAYER_LAYCTRL_SHADOW_LOAD_EN_MASK;
258     return status_success;
259 }
260 
lcdc_turn_off_display(LCDC_Type * ptr)261 void lcdc_turn_off_display(LCDC_Type *ptr)
262 {
263     if (ptr->CTRL & LCDC_CTRL_DISP_ON_MASK) {
264         ptr->INT_EN = 0;
265 
266         /* 1. wait for current frame end */
267         ptr->ST = 0xFFFFFFFF;
268         while ((ptr->ST & LCDC_ST_VS_BLANK_MASK) == 0) {
269         }
270 
271         /* 2. issue display off */
272         ptr->ST = 0xFFFFFFFF;
273         lcdc_software_reset(ptr);
274         ptr->CTRL &= ~LCDC_CTRL_DISP_ON_MASK;
275         while ((ptr->ST & LCDC_ST_VS_BLANK_MASK) == 0) {
276         }
277     }
278     return;
279 }
280 
lcdc_turn_on_display(LCDC_Type * ptr)281 void lcdc_turn_on_display(LCDC_Type *ptr)
282 {
283     if (!(ptr->CTRL & LCDC_CTRL_DISP_ON_MASK)) {
284         ptr->CTRL |= LCDC_CTRL_DISP_ON_MASK;
285     }
286 }
287 
lcdc_layer_update_pixel_format(LCDC_Type * ptr,uint8_t layer_index,uint8_t pixel_format)288 void lcdc_layer_update_pixel_format(LCDC_Type *ptr, uint8_t layer_index,
289                                     uint8_t pixel_format)
290 {
291     uint32_t pitch;
292     uint32_t width = (ptr->LAYER[layer_index].LAYSIZE & LCDC_LAYER_LAYSIZE_WIDTH_MASK)
293                     >> LCDC_LAYER_LAYSIZE_WIDTH_SHIFT;
294     pitch = display_get_pitch_length_in_byte(pixel_format, width);
295     ptr->LAYER[layer_index].LINECFG = (ptr->LAYER[layer_index].LINECFG & ~LCDC_LAYER_LINECFG_PITCH_MASK)
296         | LCDC_LAYER_LINECFG_PITCH_SET(pitch);
297 }
298