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
75 switch (pixel_format) {
76 case display_pixel_format_yuv422:
77 layer->csc_config.enable = true;
78 layer->csc_config.ycbcr_mode = false;
79 layer->csc_config.yuv2rgb_coef.c0 = 0x100;
80 layer->csc_config.yuv2rgb_coef.uv_offset = 0;
81 layer->csc_config.yuv2rgb_coef.y_offset = 0;
82 layer->csc_config.yuv2rgb_coef.c1 = 0x123;
83 layer->csc_config.yuv2rgb_coef.c2 = 0x76B;
84 layer->csc_config.yuv2rgb_coef.c3 = 0x79C;
85 layer->csc_config.yuv2rgb_coef.c4 = 0x208;
86 break;
87 case display_pixel_format_ycbcr422:
88 layer->csc_config.enable = true;
89 layer->csc_config.ycbcr_mode = true;
90 layer->csc_config.yuv2rgb_coef.c0 = 0x12A;
91 layer->csc_config.yuv2rgb_coef.uv_offset = 0x180;
92 layer->csc_config.yuv2rgb_coef.y_offset = 0x1F0;
93 layer->csc_config.yuv2rgb_coef.c1 = 0x198;
94 layer->csc_config.yuv2rgb_coef.c2 = 0x730;
95 layer->csc_config.yuv2rgb_coef.c3 = 0x79C;
96 layer->csc_config.yuv2rgb_coef.c4 = 0x204;
97 break;
98 default:
99 layer->csc_config.enable = false;
100 layer->csc_config.ycbcr_mode = false;
101 layer->csc_config.yuv2rgb_coef.c0 = 0;
102 layer->csc_config.yuv2rgb_coef.uv_offset = 0;
103 layer->csc_config.yuv2rgb_coef.y_offset = 0;
104 layer->csc_config.yuv2rgb_coef.c1 = 0;
105 layer->csc_config.yuv2rgb_coef.c2 = 0;
106 layer->csc_config.yuv2rgb_coef.c3 = 0;
107 layer->csc_config.yuv2rgb_coef.c4 = 0;
108 break;
109 }
110 }
111
lcdc_get_default_config(LCDC_Type * ptr,lcdc_config_t * config)112 void lcdc_get_default_config(LCDC_Type *ptr, lcdc_config_t *config)
113 {
114 (void) ptr;
115 config->resolution_x = 480;
116 config->resolution_y = 272;
117 config->hsync.front_porch_pulse = 40;
118 config->hsync.back_porch_pulse = 50;
119 config->hsync.pulse_width = 30;
120 config->vsync.front_porch_pulse = 20;
121 config->vsync.back_porch_pulse = 20;
122 config->vsync.pulse_width = 10;
123 config->background.u = 0x0;
124
125 config->control.display_mode = lcdc_display_mode_normal;
126 config->control.line_pattern = lcdc_line_pattern_rgb;
127 config->control.invert_pixel_clock = false;
128 config->control.invert_pixel_data = false;
129 config->control.invert_href = false;
130 config->control.invert_vsync = false;
131 config->control.invert_hsync = false;
132 }
133
lcdc_reset_register_values(LCDC_Type * ptr)134 void lcdc_reset_register_values(LCDC_Type *ptr)
135 {
136 uint8_t i = 0;
137
138 lcdc_turn_off_display(ptr);
139
140 ptr->DISP_WN_SIZE = 0;
141 ptr->INT_EN = 0;
142 ptr->ST = 0xFFFFFFFFU;
143 ptr->DMA_ST = 0xFFFFFFFFU;
144 ptr->VSYNC_PARA = 0x00C01803U;
145 ptr->HSYNC_PARA = 0x00C01803U;
146
147 for (i = 0; i < LCDC_SOC_MAX_LAYER_COUNT; i++) {
148 ptr->LAYER[i].LAYCTRL = 0;
149 ptr->LAYER[i].ALPHAS = 0;
150 ptr->LAYER[i].LAYSIZE = 0;
151 ptr->LAYER[i].LAYPOS = 0;
152 ptr->LAYER[i].START0 = 0;
153 ptr->LAYER[i].LINECFG = 0;
154 ptr->LAYER[i].BG_CL = 0;
155 }
156
157 for (i = 0; i < LCDC_SOC_MAX_CSC_LAYER_COUNT; i++) {
158 ptr->LAYER[i].CSC_COEF0 = 0;
159 ptr->LAYER[i].CSC_COEF1 = 0;
160 ptr->LAYER[i].CSC_COEF2 = 0;
161 }
162 }
163
lcdc_init(LCDC_Type * ptr,lcdc_config_t * config)164 void lcdc_init(LCDC_Type *ptr, lcdc_config_t *config)
165 {
166 lcdc_reset_register_values(ptr);
167
168 ptr->DISP_WN_SIZE = LCDC_DISP_WN_SIZE_X_SET(config->resolution_x) |
169 LCDC_DISP_WN_SIZE_Y_SET(config->resolution_y);
170 ptr->HSYNC_PARA =
171 LCDC_HSYNC_PARA_FP_SET(config->hsync.front_porch_pulse)
172 | LCDC_HSYNC_PARA_BP_SET(config->hsync.back_porch_pulse)
173 | LCDC_HSYNC_PARA_PW_SET(config->hsync.pulse_width);
174 ptr->BGND_CL = LCDC_BGND_CL_B_SET(config->background.b)
175 | LCDC_BGND_CL_G_SET(config->background.g)
176 | LCDC_BGND_CL_R_SET(config->background.r);
177 ptr->VSYNC_PARA =
178 LCDC_VSYNC_PARA_FP_SET(config->vsync.front_porch_pulse)
179 | LCDC_VSYNC_PARA_BP_SET(config->vsync.back_porch_pulse)
180 | LCDC_VSYNC_PARA_PW_SET(config->vsync.pulse_width);
181 ptr->TXFIFO = LCDC_TXFIFO_THRSH_SET(LCDC_FIFO_THRESHOLD);
182 ptr->CTRL = LCDC_CTRL_DISP_MODE_SET(config->control.display_mode)
183 | LCDC_CTRL_LINE_PATTERN_SET(config->control.line_pattern)
184 | LCDC_CTRL_INV_PXDATA_SET(config->control.invert_pixel_data)
185 | LCDC_CTRL_INV_PXCLK_SET(config->control.invert_pixel_clock)
186 | LCDC_CTRL_INV_HREF_SET(config->control.invert_href)
187 | LCDC_CTRL_INV_VSYNC_SET(config->control.invert_vsync)
188 | LCDC_CTRL_INV_HSYNC_SET(config->control.invert_hsync);
189 }
190
lcdc_config_layer(LCDC_Type * ptr,uint8_t layer_index,lcdc_layer_config_t * layer,bool enable_layer)191 hpm_stat_t lcdc_config_layer(LCDC_Type *ptr,
192 uint8_t layer_index,
193 lcdc_layer_config_t *layer,
194 bool enable_layer)
195 {
196 uint8_t byteorder;
197 uint32_t pitch;
198 uint32_t format;
199 uint32_t ctrl = ptr->LAYER[layer_index].LAYCTRL;
200
201 if ((!LCDC_SOC_LAYER_SUPPORTS_CSC(layer_index) && layer->csc_config.enable)
202 || (!LCDC_SOC_LAYER_SUPPORTS_YUV(layer_index)
203 && (display_pixel_format_is_yuv_format(layer->pixel_format)))) {
204 return status_lcdc_layer_not_supported;
205 }
206
207 ptr->LAYER[layer_index].LAYSIZE =
208 LCDC_LAYER_LAYSIZE_HEIGHT_SET(layer->height)
209 | LCDC_LAYER_LAYSIZE_WIDTH_SET(layer->width);
210 ptr->LAYER[layer_index].LAYPOS =
211 LCDC_LAYER_LAYPOS_X_SET(layer->position_x)
212 | LCDC_LAYER_LAYPOS_Y_SET(layer->position_y);
213 ptr->LAYER[layer_index].START0 = LCDC_LAYER_START0_ADDR0_SET((uint32_t)layer->buffer);
214 ptr->LAYER[layer_index].ALPHAS = LCDC_LAYER_ALPHAS_LOCD_SET(layer->alphablend.src_alpha)
215 | LCDC_LAYER_ALPHAS_IND_SET(layer->alphablend.dst_alpha);
216
217 pitch = display_get_pitch_length_in_byte(layer->pixel_format, layer->width);
218 ptr->LAYER[layer_index].LINECFG = LCDC_LAYER_LINECFG_MPT_SIZE_SET(layer->max_bytes)
219 | LCDC_LAYER_LINECFG_MAX_OT_SET(layer->max_ot)
220 | LCDC_LAYER_LINECFG_PITCH_SET(pitch);
221 ptr->LAYER[layer_index].BG_CL = LCDC_LAYER_BG_CL_ARGB_SET(layer->background.u);
222
223 ptr->LAYER[layer_index].CSC_COEF0 =
224 LCDC_LAYER_CSC_COEF0_ENABLE_SET(layer->csc_config.enable)
225 | LCDC_LAYER_CSC_COEF0_YCBCR_MODE_SET(layer->csc_config.ycbcr_mode)
226 | LCDC_LAYER_CSC_COEF0_C0_SET(layer->csc_config.yuv2rgb_coef.c0)
227 | LCDC_LAYER_CSC_COEF0_UV_OFFSET_SET(layer->csc_config.yuv2rgb_coef.uv_offset)
228 | LCDC_LAYER_CSC_COEF0_Y_OFFSET_SET(layer->csc_config.yuv2rgb_coef.y_offset);
229 ptr->LAYER[layer_index].CSC_COEF1 =
230 LCDC_LAYER_CSC_COEF1_C1_SET(layer->csc_config.yuv2rgb_coef.c1)
231 | LCDC_LAYER_CSC_COEF1_C4_SET(layer->csc_config.yuv2rgb_coef.c4);
232 ptr->LAYER[layer_index].CSC_COEF2 =
233 LCDC_LAYER_CSC_COEF2_C2_SET(layer->csc_config.yuv2rgb_coef.c2)
234 | LCDC_LAYER_CSC_COEF2_C3_SET(layer->csc_config.yuv2rgb_coef.c3);
235
236 /* bit18 is reserved but has to be set to 1 */
237 ctrl |= 1 << 18;
238
239 byteorder = lcdc_byteorder(layer->byteorder);
240 format = lcdc_pixel_format(layer->pixel_format);
241 ctrl = (ctrl & ~(LCDC_LAYER_LAYCTRL_PIXFORMAT_MASK
242 | LCDC_LAYER_LAYCTRL_AB_MODE_MASK
243 | LCDC_LAYER_LAYCTRL_LOCALPHA_OP_MASK
244 | LCDC_LAYER_LAYCTRL_INALPHA_OP_MASK
245 | LCDC_LAYER_LAYCTRL_YUV_FORMAT_MASK))
246 | LCDC_LAYER_LAYCTRL_PACK_DIR_SET(byteorder)
247 | LCDC_LAYER_LAYCTRL_PIXFORMAT_SET(format)
248 | LCDC_LAYER_LAYCTRL_AB_MODE_SET(layer->alphablend.mode)
249 | LCDC_LAYER_LAYCTRL_LOCALPHA_OP_SET(layer->alphablend.src_alpha_op)
250 | LCDC_LAYER_LAYCTRL_INALPHA_OP_SET(layer->alphablend.dst_alpha_op)
251 | LCDC_LAYER_LAYCTRL_YUV_FORMAT_SET(layer->yuv);
252
253 if (enable_layer) {
254 ctrl |= LCDC_LAYER_LAYCTRL_EN_MASK;
255 }
256 ptr->LAYER[layer_index].LAYCTRL = ctrl | LCDC_LAYER_LAYCTRL_SHADOW_LOAD_EN_MASK;
257 return status_success;
258 }
259
lcdc_turn_off_display(LCDC_Type * ptr)260 void lcdc_turn_off_display(LCDC_Type *ptr)
261 {
262 if (ptr->CTRL & LCDC_CTRL_DISP_ON_MASK) {
263 ptr->INT_EN = 0;
264
265 /* 1. wait for current frame end */
266 ptr->ST = 0xFFFFFFFF;
267 while ((ptr->ST & LCDC_ST_VS_BLANK_MASK) == 0) {
268 }
269
270 /* 2. issue display off */
271 ptr->ST = 0xFFFFFFFF;
272 lcdc_software_reset(ptr);
273 ptr->CTRL &= ~LCDC_CTRL_DISP_ON_MASK;
274 while ((ptr->ST & LCDC_ST_VS_BLANK_MASK) == 0) {
275 }
276 }
277 return;
278 }
279
lcdc_turn_on_display(LCDC_Type * ptr)280 void lcdc_turn_on_display(LCDC_Type *ptr)
281 {
282 if (!(ptr->CTRL & LCDC_CTRL_DISP_ON_MASK)) {
283 ptr->CTRL |= LCDC_CTRL_DISP_ON_MASK;
284 }
285 }
286
lcdc_layer_update_pixel_format(LCDC_Type * ptr,uint8_t layer_index,uint8_t pixel_format)287 void lcdc_layer_update_pixel_format(LCDC_Type *ptr, uint8_t layer_index,
288 uint8_t pixel_format)
289 {
290 uint32_t pitch;
291 uint32_t width = (ptr->LAYER[layer_index].LAYSIZE & LCDC_LAYER_LAYSIZE_WIDTH_MASK)
292 >> LCDC_LAYER_LAYSIZE_WIDTH_SHIFT;
293 pitch = display_get_pitch_length_in_byte(pixel_format, width);
294 ptr->LAYER[layer_index].LINECFG = (ptr->LAYER[layer_index].LINECFG & ~LCDC_LAYER_LINECFG_PITCH_MASK)
295 | LCDC_LAYER_LINECFG_PITCH_SET(pitch);
296 }
297