• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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