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