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