1 /**
2 * @file lv_renesas_glcdc.c
3 *
4 */
5
6 /*********************
7 *PLATFORM ABSTRACTION
8 *********************/
9
10 #ifdef _RENESAS_RA_
11 #define USE_FREE_RTOS (BSP_CFG_RTOS == 2)
12 #else // RX with SMC code generation
13 #ifndef _RENESAS_RX_
14 #define _RENESAS_RX_ 1
15 #endif
16 #define USE_FREE_RTOS 1
17 #define DISPLAY_HSIZE_INPUT0 LCD_CH0_IN_GR2_HSIZE
18 #define DISPLAY_VSIZE_INPUT0 LCD_CH0_IN_GR2_VSIZE
19 #endif /*_RENESAS_RA_*/
20
21 /*********************
22 * INCLUDES
23 *********************/
24 #include "lv_renesas_glcdc.h"
25
26 #if LV_USE_RENESAS_GLCDC
27
28 #ifdef _RENESAS_RA_
29 #include "LVGL_thread.h"
30 #else /* RX */
31 #include "hal_data.h"
32 #include "platform.h"
33 #include "r_glcdc_rx_if.h"
34 #include "r_glcdc_rx_pinset.h"
35 #endif /*_RENESAS_RA_*/
36
37 #include <stdbool.h>
38 #include "../../../display/lv_display_private.h"
39 #include "../../../draw/sw/lv_draw_sw.h"
40
41 /*********************
42 * DEFINES
43 *********************/
44 #define BYTES_PER_PIXEL 2
45
46 /**********************
47 * TYPEDEFS
48 **********************/
49
50 /**********************
51 * STATIC PROTOTYPES
52 **********************/
53 static lv_display_t * glcdc_create(void * buf1, void * buf2, uint32_t buf_size, lv_display_render_mode_t render_mode);
54 static void glcdc_init(void);
55 static void give_vsync_sem_and_yield(void);
56 static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
57 static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map);
58 static void flush_wait_direct(lv_display_t * display);
59 static void flush_wait_partial(lv_display_t * display);
60
61 #ifdef _RENESAS_RX_
62 static void enable_dave2d_drw_interrupt(void);
63 #endif /*_RENESAS_RX_*/
64
65 /**********************
66 * STATIC VARIABLES
67 **********************/
68
69 #ifdef _RENESAS_RX_
70 static uint8_t fb_background[2][LCD_CH0_IN_GR2_HSIZE * LCD_CH0_IN_GR2_VSIZE * BYTES_PER_PIXEL]__attribute__((
71 section(".framebuffer"), aligned(64), used));
72 static SemaphoreHandle_t _SemaphoreVsync = NULL;
73 static glcdc_cfg_t g_config;
74 static glcdc_runtime_cfg_t g_layer_change;
75
76 /* A global variable that Dave 2D driver relies on. (Being auto generated on RA platforms)*/
77 display_t g_display0_cfg;
78 #endif /*_RENESAS_RX_*/
79
80 static void * rotation_buffer = NULL;
81 static uint32_t partial_buffer_size = 0;
82
83 /**********************
84 * MACROS
85 **********************/
86
87 /**********************
88 * GLOBAL FUNCTIONS
89 **********************/
90
lv_renesas_glcdc_direct_create(void)91 lv_display_t * lv_renesas_glcdc_direct_create(void)
92 {
93 return glcdc_create(&fb_background[0][0], &fb_background[1][0], sizeof(fb_background[0]),
94 LV_DISPLAY_RENDER_MODE_DIRECT);
95 }
96
lv_renesas_glcdc_partial_create(void * buf1,void * buf2,size_t buf_size)97 lv_display_t * lv_renesas_glcdc_partial_create(void * buf1, void * buf2, size_t buf_size)
98 {
99 partial_buffer_size = buf_size;
100 return glcdc_create(buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
101 }
102
103 /*This function is declared in and being used by FSP generated code modules*/
104 #ifdef _RENESAS_RA_
glcdc_callback(display_callback_args_t * p_args)105 void glcdc_callback(display_callback_args_t * p_args)
106 {
107 if(DISPLAY_EVENT_LINE_DETECTION == p_args->event) {
108 give_vsync_sem_and_yield();
109 }
110 else if(DISPLAY_EVENT_GR1_UNDERFLOW == p_args->event) {
111 __BKPT(0); /*Layer 1 Underrun*/
112 }
113 else if(DISPLAY_EVENT_GR2_UNDERFLOW == p_args->event) {
114 __BKPT(0); /*Layer 2 Underrun*/
115 }
116 else { /*DISPLAY_EVENT_FRAME_END*/
117 __BKPT(0);
118 }
119 }
120 #else /* RX */
glcdc_callback(glcdc_callback_args_t * p_args)121 void glcdc_callback(glcdc_callback_args_t * p_args)
122 {
123 if(GLCDC_EVENT_LINE_DETECTION == p_args->event) {
124 give_vsync_sem_and_yield();
125 }
126 else if(GLCDC_EVENT_GR1_UNDERFLOW == p_args->event) {
127 while(1); /*Layer 1 Underrun*/
128 }
129 else if(GLCDC_EVENT_GR2_UNDERFLOW == p_args->event) {
130 while(1); /*Layer 2 Underrun*/
131 }
132 else {/*DISPLAY_EVENT_FRAME_END*/
133 while(1);
134 }
135 }
136 #endif /*_RENESAS_RA_*/
137
138 /**********************
139 * STATIC FUNCTIONS
140 **********************/
141
glcdc_create(void * buf1,void * buf2,uint32_t buf_size,lv_display_render_mode_t render_mode)142 static lv_display_t * glcdc_create(void * buf1, void * buf2, uint32_t buf_size, lv_display_render_mode_t render_mode)
143 {
144 #ifdef _RENESAS_RA_
145 glcdc_init();
146 #else
147 g_display0_cfg.input->format = LCD_CH0_IN_GR2_FORMAT;
148 _SemaphoreVsync = xSemaphoreCreateBinary();
149
150 glcdc_init();
151 enable_dave2d_drw_interrupt();
152 #endif /*_RENESAS_RA_*/
153
154 lv_display_t * display = lv_display_create(DISPLAY_HSIZE_INPUT0, DISPLAY_VSIZE_INPUT0);
155
156 if(render_mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
157 lv_display_set_flush_cb(display, flush_direct);
158 lv_display_set_flush_wait_cb(display, flush_wait_direct);
159 }
160 else if(render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
161 lv_display_set_flush_cb(display, flush_partial);
162 lv_display_set_flush_wait_cb(display, flush_wait_partial);
163 }
164 else {
165 LV_ASSERT(0);
166 }
167
168 lv_display_set_buffers(display, buf1, buf2, buf_size, render_mode);
169
170 return display;
171 }
172
give_vsync_sem_and_yield(void)173 static void give_vsync_sem_and_yield(void)
174 {
175 #if USE_FREE_RTOS
176 BaseType_t context_switch;
177
178 /*Set Vsync semaphore*/
179 xSemaphoreGiveFromISR(_SemaphoreVsync, &context_switch);
180
181 /*Return to the highest priority available task*/
182 portYIELD_FROM_ISR(context_switch);
183 #else
184 #endif /*USE_FREE_RTOS*/
185 }
186
glcdc_init(void)187 static void glcdc_init(void)
188 {
189 /* Fill the Frame buffer with black colour (0x0000 in RGB565), for a clean start after previous runs */
190 lv_memzero(fb_background, sizeof(fb_background));
191
192 #ifdef _RENESAS_RA_
193 /* Initialize GLCDC driver */
194 uint8_t * p_fb = &fb_background[1][0];
195 fsp_err_t err;
196
197 err = R_GLCDC_Open(&g_display0_ctrl, &g_display0_cfg);
198 if(FSP_SUCCESS != err) {
199 __BKPT(0);
200 }
201
202 err = R_GLCDC_Start(&g_display0_ctrl);
203 if(FSP_SUCCESS != err) {
204 __BKPT(0);
205 }
206
207 do {
208 err =
209 R_GLCDC_BufferChange(&g_display0_ctrl,
210 (uint8_t *) p_fb,
211 (display_frame_layer_t) 0);
212 } while(FSP_ERR_INVALID_UPDATE_TIMING == err);
213 #else /* RX */
214 glcdc_err_t err;
215 glcdc_runtime_cfg_t layer_change;
216
217 R_GLCDC_PinSet();
218
219 err = R_GLCDC_Open(&g_config);
220 if(GLCDC_SUCCESS != err) {
221 while(1);
222 }
223
224 err = R_GLCDC_Control(GLCDC_CMD_START_DISPLAY, &g_config);
225 if(GLCDC_SUCCESS != err) {
226 while(1);
227 }
228
229 g_layer_change.input = g_config.input[GLCDC_FRAME_LAYER_2];
230 g_layer_change.chromakey = g_config.chromakey[GLCDC_FRAME_LAYER_2];
231 g_layer_change.blend = g_config.blend[GLCDC_FRAME_LAYER_2];
232
233 layer_change.input.p_base = (uint32_t *)&fb_background[1][0];
234
235 do {
236 err = R_GLCDC_LayerChange(GLCDC_FRAME_LAYER_2, &g_layer_change);
237 } while(GLCDC_ERR_INVALID_UPDATE_TIMING == err);
238 #endif /*_RENESAS_RA_*/
239 }
240
flush_direct(lv_display_t * display,const lv_area_t * area,uint8_t * px_map)241 static void flush_direct(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
242 {
243 FSP_PARAMETER_NOT_USED(area);
244 /*Display the frame buffer pointed by px_map*/
245
246 if(!lv_display_flush_is_last(display)) return;
247
248 #if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED)
249 /* Invalidate cache - so the HW can access any data written by the CPU */
250 SCB_CleanInvalidateDCache_by_Addr(px_map, sizeof(fb_background[0]));
251 #endif
252
253 #ifdef _RENESAS_RA_
254 R_GLCDC_BufferChange(&g_display0_ctrl,
255 (uint8_t *) px_map,
256 (display_frame_layer_t) 0);
257 #else /* RX */
258 glcdc_err_t err;
259
260 g_layer_change.input.p_base = (uint32_t *)px_map;
261
262 do {
263 err = R_GLCDC_LayerChange(GLCDC_FRAME_LAYER_2, &g_layer_change);
264 } while(GLCDC_ERR_INVALID_UPDATE_TIMING == err);
265 #endif /*_RENESAS_RA_*/
266 }
267
flush_wait_direct(lv_display_t * display)268 static void flush_wait_direct(lv_display_t * display)
269 {
270 if(!lv_display_flush_is_last(display)) return;
271
272 #if USE_FREE_RTOS
273 /*If Vsync semaphore has already been set, clear it then wait to avoid tearing*/
274 if(uxSemaphoreGetCount(_SemaphoreVsync)) {
275 xSemaphoreTake(_SemaphoreVsync, 10);
276 }
277
278 xSemaphoreTake(_SemaphoreVsync, portMAX_DELAY);
279 #endif /*USE_FREE_RTOS*/
280
281 }
282
flush_partial(lv_display_t * display,const lv_area_t * area,uint8_t * px_map)283 static void flush_partial(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
284 {
285 uint16_t * img = (uint16_t *)px_map;
286
287 lv_area_t rotated_area;
288 lv_color_format_t cf = lv_display_get_color_format(display);
289 lv_display_rotation_t rotation = lv_display_get_rotation(display);
290
291 if(rotation != LV_DISPLAY_ROTATION_0) {
292 int32_t w = lv_area_get_width(area);
293 int32_t h = lv_area_get_height(area);
294 uint32_t w_stride = lv_draw_buf_width_to_stride(w, cf);
295 uint32_t h_stride = lv_draw_buf_width_to_stride(h, cf);
296
297 // only allocate if rotation is actually being used
298 if(!rotation_buffer) {
299 rotation_buffer = lv_malloc(partial_buffer_size);
300 LV_ASSERT_MALLOC(rotation_buffer);
301 }
302
303 if(rotation == LV_DISPLAY_ROTATION_180)
304 lv_draw_sw_rotate(img, rotation_buffer, w, h, w_stride, w_stride, rotation, cf);
305 else /* 90 or 270 */
306 lv_draw_sw_rotate(img, rotation_buffer, w, h, w_stride, h_stride, rotation, cf);
307
308 img = rotation_buffer;
309
310 rotated_area = *area;
311 lv_display_rotate_area(display, &rotated_area);
312 area = &rotated_area;
313 }
314
315 int32_t w = lv_area_get_width(area);
316 int32_t h = lv_area_get_height(area);
317
318 uint16_t * fb = (uint16_t *)fb_background[1];
319
320 fb = fb + area->y1 * DISPLAY_HSIZE_INPUT0;
321 fb = fb + area->x1;
322
323 int32_t i;
324 for(i = 0; i < h; i++) {
325 lv_memcpy(fb, img, w * BYTES_PER_PIXEL);
326
327 #if defined(RENESAS_CORTEX_M85) && (BSP_CFG_DCACHE_ENABLED)
328 SCB_CleanInvalidateDCache_by_Addr(fb, w * BYTES_PER_PIXEL);
329 #endif
330 fb += DISPLAY_HSIZE_INPUT0;
331 img += w;
332 }
333 }
334
flush_wait_partial(lv_display_t * display)335 static void flush_wait_partial(lv_display_t * display)
336 {
337 LV_UNUSED(display);
338
339 return;
340 }
341
342 #ifdef _RENESAS_RX_
343 extern void drw_int_isr(void);
344
enable_dave2d_drw_interrupt(void)345 static void enable_dave2d_drw_interrupt(void)
346 {
347 bsp_int_ctrl_t grpal1;
348
349 /* Specify the priority of the group interrupt. */
350 grpal1.ipl = 5;
351
352 /* Use the BSP API to register the interrupt handler for DRW2D. */
353 R_BSP_InterruptWrite(BSP_INT_SRC_AL1_DRW2D_DRW_IRQ, (bsp_int_cb_t)drw_int_isr);
354
355 /* Use the BSP API to enable the group interrupt. */
356 R_BSP_InterruptControl(BSP_INT_SRC_AL1_DRW2D_DRW_IRQ, BSP_INT_CMD_GROUP_INTERRUPT_ENABLE, (void *)&grpal1);
357 }
358 #endif /*_RENESAS_RX_*/
359
360 #endif /*LV_USE_RENESAS_GLCDC*/
361