1 /**
2  * @file lv_gpu_stm32_dma2d.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_gpu_stm32_dma2d.h"
10 #include "../../core/lv_refr.h"
11 
12 #if LV_USE_GPU_STM32_DMA2D
13 
14 #include LV_GPU_DMA2D_CMSIS_INCLUDE
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 
20 #if LV_COLOR_16_SWAP
21     // TODO: F7 has red blue swap bit in control register for all layers and output
22     #error "Can't use DMA2D with LV_COLOR_16_SWAP 1"
23 #endif
24 
25 #if LV_COLOR_DEPTH == 8
26     #error "Can't use DMA2D with LV_COLOR_DEPTH == 8"
27 #endif
28 
29 #if LV_COLOR_DEPTH == 16
30     #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565
31 #elif LV_COLOR_DEPTH == 32
32     #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888
33 #else
34     /*Can't use GPU with other formats*/
35 #endif
36 
37 /**********************
38  *      TYPEDEFS
39  **********************/
40 
41 /**********************
42  *  STATIC PROTOTYPES
43  **********************/
44 
45 static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area,
46                                            lv_color_t color);
47 
48 
49 static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
50                                           const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa);
51 
52 static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw, const lv_draw_img_dsc_t * dsc,
53                                             const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format);
54 
55 
56 static void invalidate_cache(void);
57 
58 /**********************
59  *  STATIC VARIABLES
60  **********************/
61 
62 /**********************
63  *      MACROS
64  **********************/
65 
66 /**********************
67  *   GLOBAL FUNCTIONS
68  **********************/
69 
70 /**
71  * Turn on the peripheral and set output color mode, this only needs to be done once
72  */
lv_draw_stm32_dma2d_init(void)73 void lv_draw_stm32_dma2d_init(void)
74 {
75     /*Enable DMA2D clock*/
76 #if defined(STM32F4) || defined(STM32F7)
77     RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
78 #elif defined(STM32H7)
79     RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN;
80 #else
81 # warning "LVGL can't enable the clock of DMA2D"
82 #endif
83 
84     /*Wait for hardware access to complete*/
85     __asm volatile("DSB\n");
86 
87     /*Delay after setting peripheral clock*/
88     volatile uint32_t temp = RCC->AHB1ENR;
89     LV_UNUSED(temp);
90 
91     /*set output colour mode*/
92     DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT;
93 }
94 
95 
lv_draw_stm32_dma2d_ctx_init(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)96 void lv_draw_stm32_dma2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
97 {
98 
99     lv_draw_sw_init_ctx(drv, draw_ctx);
100 
101     lv_draw_stm32_dma2d_ctx_t * dma2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
102 
103     dma2d_draw_ctx->blend = lv_draw_stm32_dma2d_blend;
104     //    dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded;
105     dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb;
106 
107 }
108 
lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)109 void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
110 {
111     LV_UNUSED(drv);
112     LV_UNUSED(draw_ctx);
113 }
114 
115 
lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)116 void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
117 {
118     lv_area_t blend_area;
119     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
120 
121     bool done = false;
122 
123     if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) {
124         lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
125 
126         lv_color_t * dest_buf = draw_ctx->buf;
127         dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
128 
129         const lv_color_t * src_buf = dsc->src_buf;
130         if(src_buf) {
131             lv_draw_sw_blend_basic(draw_ctx, dsc);
132             lv_coord_t src_stride;
133             src_stride = lv_area_get_width(dsc->blend_area);
134             src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 -  dsc->blend_area->x1);
135             lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
136             lv_draw_stm32_dma2d_blend_map(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa);
137             done = true;
138         }
139         else if(dsc->opa >= LV_OPA_MAX) {
140             lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
141             lv_draw_stm32_dma2d_blend_fill(dest_buf, dest_stride, &blend_area, dsc->color);
142             done = true;
143         }
144     }
145 
146     if(!done) lv_draw_sw_blend_basic(draw_ctx, dsc);
147 }
148 
149 
lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx,const lv_draw_img_dsc_t * dsc,const lv_area_t * coords,const uint8_t * map_p,lv_img_cf_t color_format)150 static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
151                                             const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format)
152 {
153     /*TODO basic ARGB8888 image can be handles here*/
154 
155     lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, color_format);
156 }
157 
lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf,lv_coord_t dest_stride,const lv_area_t * fill_area,lv_color_t color)158 static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area,
159                                            lv_color_t color)
160 {
161     /*Simply fill an area*/
162     int32_t area_w = lv_area_get_width(fill_area);
163     int32_t area_h = lv_area_get_height(fill_area);
164     invalidate_cache();
165 
166     DMA2D->CR = 0x30000;
167     DMA2D->OMAR = (uint32_t)dest_buf;
168     /*as input color mode is same as output we don't need to convert here do we?*/
169     DMA2D->OCOLR = color.full;
170     DMA2D->OOR = dest_stride - area_w;
171     DMA2D->NLR = (area_w << DMA2D_NLR_PL_Pos) | (area_h << DMA2D_NLR_NL_Pos);
172 
173     /*start transfer*/
174     DMA2D->CR |= DMA2D_CR_START_Msk;
175 
176 }
177 
178 
lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_coord_t src_stride,lv_opa_t opa)179 static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
180                                           const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa)
181 {
182 
183     /*Simple copy*/
184     int32_t dest_w = lv_area_get_width(dest_area);
185     int32_t dest_h = lv_area_get_height(dest_area);
186 
187     invalidate_cache();
188     if(opa >= LV_OPA_MAX) {
189         DMA2D->CR = 0;
190         /*copy output colour mode, this register controls both input and output colour format*/
191         DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT;
192         DMA2D->FGMAR = (uint32_t)src_buf;
193         DMA2D->FGOR = src_stride - dest_w;
194         DMA2D->OMAR = (uint32_t)dest_buf;
195         DMA2D->OOR = dest_stride - dest_w;
196         DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos);
197 
198         /*start transfer*/
199         DMA2D->CR |= DMA2D_CR_START_Msk;
200     }
201     else {
202         DMA2D->CR = 0x20000;
203 
204         DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT;
205         DMA2D->BGMAR = (uint32_t)dest_buf;
206         DMA2D->BGOR = dest_stride - dest_w;
207 
208         DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT
209                          /*alpha mode 2, replace with foreground * alpha value*/
210                          | (2 << DMA2D_FGPFCCR_AM_Pos)
211                          /*alpha value*/
212                          | (opa << DMA2D_FGPFCCR_ALPHA_Pos);
213         DMA2D->FGMAR = (uint32_t)src_buf;
214         DMA2D->FGOR = src_stride - dest_w;
215 
216         DMA2D->OMAR = (uint32_t)src_buf;
217         DMA2D->OOR = src_stride - dest_w;
218         DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos);
219 
220         /*start transfer*/
221         DMA2D->CR |= DMA2D_CR_START_Msk;
222     }
223 }
224 
lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx)225 void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx)
226 {
227     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
228     if(disp->driver && disp->driver->wait_cb) {
229         while(DMA2D->CR & DMA2D_CR_START_Msk) {
230             disp->driver->wait_cb(disp->driver);
231         }
232     }
233     else {
234         while(DMA2D->CR & DMA2D_CR_START_Msk);
235     }
236     lv_draw_sw_wait_for_finish(draw_ctx);
237 
238 }
239 
240 /**********************
241  *   STATIC FUNCTIONS
242  **********************/
243 
invalidate_cache(void)244 static void invalidate_cache(void)
245 {
246     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
247     if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver);
248     else {
249 #if __CORTEX_M >= 0x07
250         if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk)
251             SCB_CleanInvalidateDCache();
252 #endif
253     }
254 }
255 
256 #endif
257