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