aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJoel Bodenmann <joel@embedded.pro>2017-10-29 18:11:00 +0100
committerJoel Bodenmann <joel@embedded.pro>2017-10-29 18:11:00 +0100
commita4f203fbe2865d0e20533681934c58e651a26a81 (patch)
treea93618e81739bd6b53df6f6fb1014791dbde2894 /drivers
parenta5c1e29d21d740360e7a15617f51b542c8947988 (diff)
downloaduGFX-a4f203fbe2865d0e20533681934c58e651a26a81.tar.gz
uGFX-a4f203fbe2865d0e20533681934c58e651a26a81.tar.bz2
uGFX-a4f203fbe2865d0e20533681934c58e651a26a81.zip
Preventing __DSB() redeclaration in STM32LTDC driver
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c1186
1 files changed, 593 insertions, 593 deletions
diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
index d49c3f09..4e232999 100644
--- a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
+++ b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
@@ -1,593 +1,593 @@
-/*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
-
-#include "gfx.h"
-
-#if GFX_USE_GDISP
-
-#define GDISP_DRIVER_VMT GDISPVMT_STM32LTDC
-#include "gdisp_lld_config.h"
-#include "../../../src/gdisp/gdisp_driver.h"
-
-#if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT)
- #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
- #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
- #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
- COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.")
- #endif
- #undef GDISP_SCREEN_WIDTH
- #undef GDISP_SCREEN_HEIGHT
-#endif
-
-#ifndef LTDC_USE_DMA2D
- #define LTDC_USE_DMA2D FALSE
-#endif
-#ifndef LTDC_NO_CLOCK_INIT
- #define LTDC_NO_CLOCK_INIT FALSE
-#endif
-#ifndef LTDC_DMA_CACHE_FLUSH
- #define LTDC_DMA_CACHE_FLUSH FALSE
-#endif
-
-#include "stm32_ltdc.h"
-
-#if LTDC_USE_DMA2D
- #include "stm32_dma2d.h"
-
- #if defined(STM32F7) || defined(STM32F746xx)
- #undef LTDC_DMA_CACHE_FLUSH
- #define LTDC_DMA_CACHE_FLUSH TRUE
- #endif
-#endif
-
-
-typedef struct ltdcLayerConfig {
- // Frame
- LLDCOLOR_TYPE* frame; // Frame buffer address
- coord_t width, height; // Frame size in pixels
- coord_t pitch; // Line pitch, in bytes
- uint16_t fmt; // Pixel format in LTDC format
-
- // Window
- coord_t x, y; // Start pixel position of the virtual layer
- coord_t cx, cy; // Size of the virtual layer
-
- uint32_t defcolor; // Default color, ARGB8888
- uint32_t keycolor; // Color key, RGB888
- uint32_t blending; // Blending factors
- const uint32_t* palette; // The palette, RGB888 (can be NULL)
- uint16_t palettelen; // Palette length
- uint8_t alpha; // Constant alpha factor
- uint8_t layerflags; // Layer configuration
-} ltdcLayerConfig;
-
-typedef struct ltdcConfig {
- coord_t width, height; // Screen size
- coord_t hsync, vsync; // Horizontal and Vertical sync pixels
- coord_t hbackporch, vbackporch; // Horizontal and Vertical back porch pixels
- coord_t hfrontporch, vfrontporch; // Horizontal and Vertical front porch pixels
- uint32_t syncflags; // Sync flags
- uint32_t bgcolor; // Clear screen color RGB888
-
- ltdcLayerConfig bglayer; // Background layer config
- ltdcLayerConfig fglayer; // Foreground layer config
-} ltdcConfig;
-
-#define LTDC_UNUSED_LAYER_CONFIG { 0, 1, 1, 1, LTDC_FMT_L8, 0, 0, 1, 1, 0x000000, 0x000000, LTDC_BLEND_FIX1_FIX2, 0, 0, 0, 0 }
-
-#if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
- #define LTDC_PIXELFORMAT LTDC_FMT_RGB565
- #define LTDC_PIXELBYTES 2
- #define LTDC_PIXELBITS 16
-#elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- #define LTDC_PIXELFORMAT LTDC_FMT_ARGB8888
- #define LTDC_PIXELBYTES 4
- #define LTDC_PIXELBITS 32
-#else
- #error "GDISP: STM32LTDC - unsupported pixel format"
-#endif
-
-#include "board_STM32LTDC.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#ifndef GDISP_INITIAL_CONTRAST
- #define GDISP_INITIAL_CONTRAST 50
-#endif
-#ifndef GDISP_INITIAL_BACKLIGHT
- #define GDISP_INITIAL_BACKLIGHT 100
-#endif
-
-/*===========================================================================*/
-/* Driver local routines. */
-/*===========================================================================*/
-
-#define PIXIL_POS(g, x, y) ((y) * ((ltdcLayerConfig *)g->priv)->pitch + (x) * LTDC_PIXELBYTES)
-#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)((uint8_t *)((ltdcLayerConfig *)g->priv)->frame+pos))
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-static const ltdcLayerConfig layerOff = LTDC_UNUSED_LAYER_CONFIG;
-
-static void _ltdc_reload(void) {
- LTDC->SRCR |= LTDC_SRCR_IMR;
- while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR))
- gfxYield();
-}
-
-static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg) {
- static const uint8_t fmt2Bpp[] = {
- 4, /* LTDC_FMT_ARGB8888 */
- 3, /* LTDC_FMT_RGB888 */
- 2, /* LTDC_FMT_RGB565 */
- 2, /* LTDC_FMT_ARGB1555 */
- 2, /* LTDC_FMT_ARGB4444 */
- 1, /* LTDC_FMT_L8 */
- 1, /* LTDC_FMT_AL44 */
- 2 /* LTDC_FMT_AL88 */
- };
- uint32_t start, stop;
-
- // Set the framebuffer dimensions and format
- pLayReg->PFCR = (pLayReg->PFCR & ~LTDC_LxPFCR_PF) | ((uint32_t)pCfg->fmt & LTDC_LxPFCR_PF);
- pLayReg->CFBAR = (uint32_t)pCfg->frame & LTDC_LxCFBAR_CFBADD;
- pLayReg->CFBLR = ((((uint32_t)pCfg->pitch << 16) & LTDC_LxCFBLR_CFBP) | (((uint32_t)fmt2Bpp[pCfg->fmt] * pCfg->width + 3) & LTDC_LxCFBLR_CFBLL));
- pLayReg->CFBLNR = (uint32_t)pCfg->height & LTDC_LxCFBLNR_CFBLNBR;
-
- // Set the display window boundaries
- start = (uint32_t)pCfg->x + driverCfg.hsync + driverCfg.hbackporch;
- stop = start + pCfg->cx - 1;
- pLayReg->WHPCR = ((start << 0) & LTDC_LxWHPCR_WHSTPOS) | ((stop << 16) & LTDC_LxWHPCR_WHSPPOS);
- start = (uint32_t)pCfg->y + driverCfg.vsync + driverCfg.vbackporch;
- stop = start + pCfg->cy - 1;
- pLayReg->WVPCR = ((start << 0) & LTDC_LxWVPCR_WVSTPOS) | ((stop << 16) & LTDC_LxWVPCR_WVSPPOS);
-
- // Set colors
- pLayReg->DCCR = pCfg->defcolor;
- pLayReg->CKCR = (pLayReg->CKCR & ~0x00FFFFFF) | (pCfg->keycolor & 0x00FFFFFF);
- pLayReg->CACR = (pLayReg->CACR & ~LTDC_LxCACR_CONSTA) | ((uint32_t)pCfg->alpha & LTDC_LxCACR_CONSTA);
- pLayReg->BFCR = (pLayReg->BFCR & ~(LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)) | ((uint32_t)pCfg->blending & (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2));
- for (start = 0; start < pCfg->palettelen; start++)
- pLayReg->CLUTWR = ((uint32_t)start << 24) | (pCfg->palette[start] & 0x00FFFFFF);
-
- // Final flags
- pLayReg->CR = (pLayReg->CR & ~LTDC_LEF_MASK) | ((uint32_t)pCfg->layerflags & LTDC_LEF_MASK);
-}
-
-static void _ltdc_init(void) {
- // Set up the display scanning
- uint32_t hacc, vacc;
-
- // Reset the LTDC peripheral
- RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST;
- RCC->APB2RSTR = 0;
-
- // Enable the LTDC clock
- #if !LTDC_NO_CLOCK_INIT
- #if defined(STM32F469xx)
- RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR);
- #elif defined(STM32F4) || defined(STM32F429_439xx) || defined(STM32F429xx)
- RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (1 << 16);
- #elif defined(STM32F7) || defined(STM32F746xx)
- RCC->DCKCFGR1 = (RCC->DCKCFGR1 & ~RCC_DCKCFGR1_PLLSAIDIVR) | (1 << 16);
- #else
- #error STM32LTDC driver not implemented for your platform
- #endif
- #endif
-
- // Enable the peripheral
- RCC->APB2ENR |= RCC_APB2ENR_LTDCEN;
-
- // Turn off the controller and its interrupts
- LTDC->GCR = 0;
- LTDC->IER = 0;
- _ltdc_reload();
-
- // Set synchronization params
- hacc = driverCfg.hsync - 1;
- vacc = driverCfg.vsync - 1;
- LTDC->SSCR = ((hacc << 16) & LTDC_SSCR_HSW) | ((vacc << 0) & LTDC_SSCR_VSH);
-
- // Set accumulated back porch params
- hacc += driverCfg.hbackporch;
- vacc += driverCfg.vbackporch;
- LTDC->BPCR = ((hacc << 16) & LTDC_BPCR_AHBP) | ((vacc << 0) & LTDC_BPCR_AVBP);
-
- // Set accumulated active params
- hacc += driverCfg.width;
- vacc += driverCfg.height;
- LTDC->AWCR = ((hacc << 16) & LTDC_AWCR_AAW) | ((vacc << 0) & LTDC_AWCR_AAH);
-
- // Set accumulated total params
- hacc += driverCfg.hfrontporch;
- vacc += driverCfg.vfrontporch;
- LTDC->TWCR = ((hacc << 16) & LTDC_TWCR_TOTALW) | ((vacc << 0) & LTDC_TWCR_TOTALH);
-
- // Set signal polarities and other flags
- LTDC->GCR = driverCfg.syncflags & (LTDC_EF_MASK & ~LTDC_EF_ENABLE);
-
- // Set background color
- LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (driverCfg.bgcolor & 0x00FFFFFF);
-
- // Load the background layer
- _ltdc_layer_init(LTDC_Layer1, &driverCfg.bglayer);
-
- // Load the foreground layer
- _ltdc_layer_init(LTDC_Layer2, &layerOff);
-
- // Interrupt handling
- // Possible flags - LTDC_IER_RRIE, LTDC_IER_LIE, LTDC_IER_FUIE, LTDC_IER_TERRIE etc
- LTDC->IER = 0;
-
- // Set everything going
- _ltdc_reload();
- LTDC->GCR |= LTDC_GCR_LTDCEN;
- _ltdc_reload();
-}
-
-LLDSPEC bool_t gdisp_lld_init(GDisplay* g) {
- // Initialize the private structure
- g->priv = 0;
- g->board = 0;
-
- switch(g->controllerdisplay) {
- case 0: // Display 0 is the background layer
- // Init the board
- init_board(g);
-
- // Initialise the LTDC controller
- _ltdc_init();
-
- // Initialise DMA2D
- #if LTDC_USE_DMA2D
- dma2d_init();
- #endif
-
- if (!(driverCfg.bglayer.layerflags & LTDC_LEF_ENABLE))
- return FALSE;
-
- g->priv = (void *)&driverCfg.bglayer;
-
- // Finish Init the board
- post_init_board(g);
-
- // Turn on the back-light
- set_backlight(g, GDISP_INITIAL_BACKLIGHT);
-
- break;
-
- case 1: // Display 1 is the foreground layer
-
- if (!(driverCfg.fglayer.layerflags & LTDC_LEF_ENABLE))
- return FALSE;
-
- // Load the foreground layer
- _ltdc_layer_init(LTDC_Layer2, &driverCfg.fglayer);
- _ltdc_reload();
-
- g->priv = (void *)&driverCfg.fglayer;
-
- // Finish Init the board
- post_init_board(g);
-
- break;
-
- default: // There is only 1 LTDC in the CPU and only the 2 layers in the LTDC.
- return FALSE;
- }
-
- // Initialise the GDISP structure
- g->g.Width = ((ltdcLayerConfig *)g->priv)->width;
- g->g.Height = ((ltdcLayerConfig *)g->priv)->height;
- g->g.Orientation = GDISP_ROTATE_0;
- g->g.Powermode = powerOn;
- g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
- g->g.Contrast = GDISP_INITIAL_CONTRAST;
-
- return TRUE;
-}
-
-LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) {
- unsigned pos;
-
- #if GDISP_NEED_CONTROL
- switch(g->g.Orientation) {
- case GDISP_ROTATE_0:
- default:
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- break;
- case GDISP_ROTATE_90:
- pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
- break;
- case GDISP_ROTATE_180:
- pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
- break;
- case GDISP_ROTATE_270:
- pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
- break;
- }
- #else
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- #endif
-
- #if LTDC_USE_DMA2D
- while(DMA2D->CR & DMA2D_CR_START);
- #endif
-
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- // As we don't support ARGB pixel types in uGFX yet we will
- // use RGB with an inverted alpha value for compatibility
- // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
- PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color) ^ 0xFF000000;
- #else
- PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
- #endif
-}
-
-LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) {
- unsigned pos;
- LLDCOLOR_TYPE color;
-
- #if GDISP_NEED_CONTROL
- switch(g->g.Orientation) {
- case GDISP_ROTATE_0:
- default:
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- break;
- case GDISP_ROTATE_90:
- pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
- break;
- case GDISP_ROTATE_180:
- pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
- break;
- case GDISP_ROTATE_270:
- pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
- break;
- }
- #else
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- #endif
-
- #if LTDC_USE_DMA2D
- while(DMA2D->CR & DMA2D_CR_START);
- #endif
-
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- // As we don't support ARGB pixel types in uGFX yet we will
- // use RGB with an inverted alpha value for compatibility
- // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
- color = PIXEL_ADDR(g, pos)[0] ^ 0xFF000000;
- #else
- color = PIXEL_ADDR(g, pos)[0];
- #endif
-
- return gdispNative2Color(color);
-}
-
-#if GDISP_NEED_CONTROL
- LLDSPEC void gdisp_lld_control(GDisplay* g) {
- switch(g->p.x) {
- case GDISP_CONTROL_ORIENTATION:
- if (g->g.Orientation == (orientation_t)g->p.ptr)
- return;
- switch((orientation_t)g->p.ptr) {
- case GDISP_ROTATE_0:
- case GDISP_ROTATE_180:
- if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) {
- coord_t tmp;
-
- tmp = g->g.Width;
- g->g.Width = g->g.Height;
- g->g.Height = tmp;
- }
- break;
- case GDISP_ROTATE_90:
- case GDISP_ROTATE_270:
- if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) {
- coord_t tmp;
-
- tmp = g->g.Width;
- g->g.Width = g->g.Height;
- g->g.Height = tmp;
- }
- break;
- default:
- return;
- }
- g->g.Orientation = (orientation_t)g->p.ptr;
- return;
-
- case GDISP_CONTROL_BACKLIGHT:
- if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
- set_backlight(g, (unsigned)g->p.ptr);
- g->g.Backlight = (unsigned)g->p.ptr;
- return;
- }
- }
-#endif
-
-#if LTDC_USE_DMA2D
- #if LTDC_DMA_CACHE_FLUSH
- #if defined(__CC_ARM)
- #define __DSB() __dsb(0xF)
- #else // GCC like
- #define __DSB() __ASM volatile ("dsb 0xF":::"memory")
- #endif
- #endif
-
-
- static void dma2d_init(void) {
- // Enable DMA2D clock
- RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
-
- // Output color format
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
- DMA2D->OPFCCR = OPFCCR_RGB565;
- #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- DMA2D->OPFCCR = OPFCCR_ARGB8888;
- #endif
-
- // Foreground color format
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
- DMA2D->FGPFCCR = FGPFCCR_CM_RGB565;
- #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- DMA2D->FGPFCCR = FGPFCCR_CM_ARGB8888;
- #endif
- }
-
- // Uses p.x,p.y p.cx,p.cy p.color
- LLDSPEC void gdisp_lld_fill_area(GDisplay* g)
- {
- uint32_t pos;
- uint32_t lineadd;
- uint32_t shape;
-
- #if GDISP_NEED_CONTROL
- switch(g->g.Orientation) {
- case GDISP_ROTATE_0:
- default:
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- lineadd = g->g.Width - g->p.cx;
- shape = (g->p.cx << 16) | (g->p.cy);
- break;
- case GDISP_ROTATE_90:
- pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-g->p.cx);
- lineadd = g->g.Height - g->p.cy;
- shape = (g->p.cy << 16) | (g->p.cx);
- break;
- case GDISP_ROTATE_180:
- pos = PIXIL_POS(g, g->g.Width-g->p.x-g->p.cx, g->g.Height-g->p.y-g->p.cy);
- lineadd = g->g.Width - g->p.cx;
- shape = (g->p.cx << 16) | (g->p.cy);
- break;
- case GDISP_ROTATE_270:
- pos = PIXIL_POS(g, g->g.Height-g->p.y-g->p.cy, g->p.x);
- lineadd = g->g.Height - g->p.cy;
- shape = (g->p.cy << 16) | (g->p.cx);
- break;
- }
- #else
- pos = PIXIL_POS(g, g->p.x, g->p.y);
- lineadd = g->g.Width - g->p.cx;
- shape = (g->p.cx << 16) | (g->p.cy);
- #endif
-
- #if LTDC_DMA_CACHE_FLUSH
- {
- // This is slightly less than optimal as we flush the whole line in the source and destination image
- // instead of just the cx portion but this saves us having to iterate over each line.
- uint32_t f, e;
-
- // Data memory barrier
- __DSB();
-
- // Flush then invalidate the destination area
- e = pos + (g->p.cy > 1 ? ((uint32_t)((ltdcLayerConfig *)g->priv)->pitch*(shape & 0xFFFF)) : ((shape>>16)*LTDC_PIXELBYTES));
- for(f=(pos & ~31); f < e; f += 32) {
- SCB->DCCIMVAC = f;
- SCB->DCIMVAC = f;
- }
-
- // Data memory barrier
- __DSB();
- }
- #endif
-
- // Wait until DMA2D is ready
- while(DMA2D->CR & DMA2D_CR_START);
-
- // Start the DMA2D
- DMA2D->OMAR = (uint32_t)PIXEL_ADDR(g, pos);
- DMA2D->OOR = lineadd;
- DMA2D->NLR = shape;
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
- // As we don't support ARGB pixel types in uGFX yet we will
- // use RGB with an inverted alpha value for compatibility
- // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
- DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color)) ^ 0xFF000000;
- #else
- DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color));
- #endif
- ;
- DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START;
- }
-
- /* Oops - the DMA2D only supports GDISP_ROTATE_0.
- *
- * Where the width is 1 we can trick it for other orientations.
- * That is worthwhile as a width of 1 is common. For other
- * situations we need to fall back to pixel pushing.
- *
- * Additionally, although DMA2D can translate color formats
- * it can only do it for a small range of formats. For any
- * other formats we also need to fall back to pixel pushing.
- *
- * As the code to actually do all that for other than the
- * simplest case (orientation == GDISP_ROTATE_0 and
- * GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT) is very complex
- * we will always pixel push for now. In practice that is OK as
- * access to the framebuffer is fast - probably faster than DMA2D.
- * It just uses more CPU.
- */
- #if GDISP_HARDWARE_BITFILLS
- // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer)
- LLDSPEC void gdisp_lld_blit_area(GDisplay* g) {
- uint32_t srcstart, dststart;
-
- srcstart = LTDC_PIXELBYTES * ((uint32_t)g->p.x2 * g->p.y1 * + g->p.x1) + (uint32_t)g->p.ptr;
- dststart = (uint32_t)PIXEL_ADDR(g, PIXIL_POS(g, g->p.x, g->p.y));
-
- #if LTDC_DMA_CACHE_FLUSH
- {
- // This is slightly less than optimal as we flush the whole line in the source and destination image
- // instead of just the cx portion but this saves us having to iterate over each line.
- uint32_t f, e;
-
- // Data memory barrier
- __DSB();
-
- // Flush the source area
- e = srcstart + (g->p.cy > 1 ? ((uint32_t)g->p.x2*g->p.cy) : (uint32_t)g->p.cx)*LTDC_PIXELBYTES;
- for(f=(srcstart & ~31); f < e; f += 32)
- SCB->DCCIMVAC = f;
-
- // Flush then invalidate the destination area
- e = dststart + (g->p.cy > 1 ? ((uint32_t)((ltdcLayerConfig *)g->priv)->pitch*g->p.cy) : ((uint32_t)g->p.cx*LTDC_PIXELBYTES));
- for(f=(dststart & ~31); f < e; f += 32) {
- SCB->DCCIMVAC = f;
- SCB->DCIMVAC = f;
- }
-
- // Data memory barrier
- __DSB();
- }
- #endif
-
- // Wait until DMA2D is ready
- while(DMA2D->CR & DMA2D_CR_START);
-
- // Source setup
- DMA2D->FGMAR = srcstart;
- DMA2D->FGOR = g->p.x2 - g->p.cx;
-
- // Output setup
- DMA2D->OMAR = dststart;
- DMA2D->OOR = g->g.Width - g->p.cx;
- DMA2D->NLR = (g->p.cx << 16) | (g->p.cy);
-
- // Set MODE to M2M and Start the process
- DMA2D->CR = DMA2D_CR_MODE_M2M | DMA2D_CR_START;
- }
- #endif
-
-#endif /* LTDC_USE_DMA2D */
-
-#endif /* GFX_USE_GDISP */
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#define GDISP_DRIVER_VMT GDISPVMT_STM32LTDC
+#include "gdisp_lld_config.h"
+#include "../../../src/gdisp/gdisp_driver.h"
+
+#if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT)
+ #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
+ #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
+ #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
+ COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.")
+ #endif
+ #undef GDISP_SCREEN_WIDTH
+ #undef GDISP_SCREEN_HEIGHT
+#endif
+
+#ifndef LTDC_USE_DMA2D
+ #define LTDC_USE_DMA2D FALSE
+#endif
+#ifndef LTDC_NO_CLOCK_INIT
+ #define LTDC_NO_CLOCK_INIT FALSE
+#endif
+#ifndef LTDC_DMA_CACHE_FLUSH
+ #define LTDC_DMA_CACHE_FLUSH FALSE
+#endif
+
+#include "stm32_ltdc.h"
+
+#if LTDC_USE_DMA2D
+ #include "stm32_dma2d.h"
+
+ #if defined(STM32F7) || defined(STM32F746xx)
+ #undef LTDC_DMA_CACHE_FLUSH
+ #define LTDC_DMA_CACHE_FLUSH TRUE
+ #endif
+#endif
+
+
+typedef struct ltdcLayerConfig {
+ // Frame
+ LLDCOLOR_TYPE* frame; // Frame buffer address
+ coord_t width, height; // Frame size in pixels
+ coord_t pitch; // Line pitch, in bytes
+ uint16_t fmt; // Pixel format in LTDC format
+
+ // Window
+ coord_t x, y; // Start pixel position of the virtual layer
+ coord_t cx, cy; // Size of the virtual layer
+
+ uint32_t defcolor; // Default color, ARGB8888
+ uint32_t keycolor; // Color key, RGB888
+ uint32_t blending; // Blending factors
+ const uint32_t* palette; // The palette, RGB888 (can be NULL)
+ uint16_t palettelen; // Palette length
+ uint8_t alpha; // Constant alpha factor
+ uint8_t layerflags; // Layer configuration
+} ltdcLayerConfig;
+
+typedef struct ltdcConfig {
+ coord_t width, height; // Screen size
+ coord_t hsync, vsync; // Horizontal and Vertical sync pixels
+ coord_t hbackporch, vbackporch; // Horizontal and Vertical back porch pixels
+ coord_t hfrontporch, vfrontporch; // Horizontal and Vertical front porch pixels
+ uint32_t syncflags; // Sync flags
+ uint32_t bgcolor; // Clear screen color RGB888
+
+ ltdcLayerConfig bglayer; // Background layer config
+ ltdcLayerConfig fglayer; // Foreground layer config
+} ltdcConfig;
+
+#define LTDC_UNUSED_LAYER_CONFIG { 0, 1, 1, 1, LTDC_FMT_L8, 0, 0, 1, 1, 0x000000, 0x000000, LTDC_BLEND_FIX1_FIX2, 0, 0, 0, 0 }
+
+#if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
+ #define LTDC_PIXELFORMAT LTDC_FMT_RGB565
+ #define LTDC_PIXELBYTES 2
+ #define LTDC_PIXELBITS 16
+#elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ #define LTDC_PIXELFORMAT LTDC_FMT_ARGB8888
+ #define LTDC_PIXELBYTES 4
+ #define LTDC_PIXELBITS 32
+#else
+ #error "GDISP: STM32LTDC - unsupported pixel format"
+#endif
+
+#include "board_STM32LTDC.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#ifndef GDISP_INITIAL_CONTRAST
+ #define GDISP_INITIAL_CONTRAST 50
+#endif
+#ifndef GDISP_INITIAL_BACKLIGHT
+ #define GDISP_INITIAL_BACKLIGHT 100
+#endif
+
+/*===========================================================================*/
+/* Driver local routines. */
+/*===========================================================================*/
+
+#define PIXIL_POS(g, x, y) ((y) * ((ltdcLayerConfig *)g->priv)->pitch + (x) * LTDC_PIXELBYTES)
+#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)((uint8_t *)((ltdcLayerConfig *)g->priv)->frame+pos))
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+static const ltdcLayerConfig layerOff = LTDC_UNUSED_LAYER_CONFIG;
+
+static void _ltdc_reload(void) {
+ LTDC->SRCR |= LTDC_SRCR_IMR;
+ while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR))
+ gfxYield();
+}
+
+static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg) {
+ static const uint8_t fmt2Bpp[] = {
+ 4, /* LTDC_FMT_ARGB8888 */
+ 3, /* LTDC_FMT_RGB888 */
+ 2, /* LTDC_FMT_RGB565 */
+ 2, /* LTDC_FMT_ARGB1555 */
+ 2, /* LTDC_FMT_ARGB4444 */
+ 1, /* LTDC_FMT_L8 */
+ 1, /* LTDC_FMT_AL44 */
+ 2 /* LTDC_FMT_AL88 */
+ };
+ uint32_t start, stop;
+
+ // Set the framebuffer dimensions and format
+ pLayReg->PFCR = (pLayReg->PFCR & ~LTDC_LxPFCR_PF) | ((uint32_t)pCfg->fmt & LTDC_LxPFCR_PF);
+ pLayReg->CFBAR = (uint32_t)pCfg->frame & LTDC_LxCFBAR_CFBADD;
+ pLayReg->CFBLR = ((((uint32_t)pCfg->pitch << 16) & LTDC_LxCFBLR_CFBP) | (((uint32_t)fmt2Bpp[pCfg->fmt] * pCfg->width + 3) & LTDC_LxCFBLR_CFBLL));
+ pLayReg->CFBLNR = (uint32_t)pCfg->height & LTDC_LxCFBLNR_CFBLNBR;
+
+ // Set the display window boundaries
+ start = (uint32_t)pCfg->x + driverCfg.hsync + driverCfg.hbackporch;
+ stop = start + pCfg->cx - 1;
+ pLayReg->WHPCR = ((start << 0) & LTDC_LxWHPCR_WHSTPOS) | ((stop << 16) & LTDC_LxWHPCR_WHSPPOS);
+ start = (uint32_t)pCfg->y + driverCfg.vsync + driverCfg.vbackporch;
+ stop = start + pCfg->cy - 1;
+ pLayReg->WVPCR = ((start << 0) & LTDC_LxWVPCR_WVSTPOS) | ((stop << 16) & LTDC_LxWVPCR_WVSPPOS);
+
+ // Set colors
+ pLayReg->DCCR = pCfg->defcolor;
+ pLayReg->CKCR = (pLayReg->CKCR & ~0x00FFFFFF) | (pCfg->keycolor & 0x00FFFFFF);
+ pLayReg->CACR = (pLayReg->CACR & ~LTDC_LxCACR_CONSTA) | ((uint32_t)pCfg->alpha & LTDC_LxCACR_CONSTA);
+ pLayReg->BFCR = (pLayReg->BFCR & ~(LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)) | ((uint32_t)pCfg->blending & (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2));
+ for (start = 0; start < pCfg->palettelen; start++)
+ pLayReg->CLUTWR = ((uint32_t)start << 24) | (pCfg->palette[start] & 0x00FFFFFF);
+
+ // Final flags
+ pLayReg->CR = (pLayReg->CR & ~LTDC_LEF_MASK) | ((uint32_t)pCfg->layerflags & LTDC_LEF_MASK);
+}
+
+static void _ltdc_init(void) {
+ // Set up the display scanning
+ uint32_t hacc, vacc;
+
+ // Reset the LTDC peripheral
+ RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST;
+ RCC->APB2RSTR = 0;
+
+ // Enable the LTDC clock
+ #if !LTDC_NO_CLOCK_INIT
+ #if defined(STM32F469xx)
+ RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR);
+ #elif defined(STM32F4) || defined(STM32F429_439xx) || defined(STM32F429xx)
+ RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (1 << 16);
+ #elif defined(STM32F7) || defined(STM32F746xx)
+ RCC->DCKCFGR1 = (RCC->DCKCFGR1 & ~RCC_DCKCFGR1_PLLSAIDIVR) | (1 << 16);
+ #else
+ #error STM32LTDC driver not implemented for your platform
+ #endif
+ #endif
+
+ // Enable the peripheral
+ RCC->APB2ENR |= RCC_APB2ENR_LTDCEN;
+
+ // Turn off the controller and its interrupts
+ LTDC->GCR = 0;
+ LTDC->IER = 0;
+ _ltdc_reload();
+
+ // Set synchronization params
+ hacc = driverCfg.hsync - 1;
+ vacc = driverCfg.vsync - 1;
+ LTDC->SSCR = ((hacc << 16) & LTDC_SSCR_HSW) | ((vacc << 0) & LTDC_SSCR_VSH);
+
+ // Set accumulated back porch params
+ hacc += driverCfg.hbackporch;
+ vacc += driverCfg.vbackporch;
+ LTDC->BPCR = ((hacc << 16) & LTDC_BPCR_AHBP) | ((vacc << 0) & LTDC_BPCR_AVBP);
+
+ // Set accumulated active params
+ hacc += driverCfg.width;
+ vacc += driverCfg.height;
+ LTDC->AWCR = ((hacc << 16) & LTDC_AWCR_AAW) | ((vacc << 0) & LTDC_AWCR_AAH);
+
+ // Set accumulated total params
+ hacc += driverCfg.hfrontporch;
+ vacc += driverCfg.vfrontporch;
+ LTDC->TWCR = ((hacc << 16) & LTDC_TWCR_TOTALW) | ((vacc << 0) & LTDC_TWCR_TOTALH);
+
+ // Set signal polarities and other flags
+ LTDC->GCR = driverCfg.syncflags & (LTDC_EF_MASK & ~LTDC_EF_ENABLE);
+
+ // Set background color
+ LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (driverCfg.bgcolor & 0x00FFFFFF);
+
+ // Load the background layer
+ _ltdc_layer_init(LTDC_Layer1, &driverCfg.bglayer);
+
+ // Load the foreground layer
+ _ltdc_layer_init(LTDC_Layer2, &layerOff);
+
+ // Interrupt handling
+ // Possible flags - LTDC_IER_RRIE, LTDC_IER_LIE, LTDC_IER_FUIE, LTDC_IER_TERRIE etc
+ LTDC->IER = 0;
+
+ // Set everything going
+ _ltdc_reload();
+ LTDC->GCR |= LTDC_GCR_LTDCEN;
+ _ltdc_reload();
+}
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay* g) {
+ // Initialize the private structure
+ g->priv = 0;
+ g->board = 0;
+
+ switch(g->controllerdisplay) {
+ case 0: // Display 0 is the background layer
+ // Init the board
+ init_board(g);
+
+ // Initialise the LTDC controller
+ _ltdc_init();
+
+ // Initialise DMA2D
+ #if LTDC_USE_DMA2D
+ dma2d_init();
+ #endif
+
+ if (!(driverCfg.bglayer.layerflags & LTDC_LEF_ENABLE))
+ return FALSE;
+
+ g->priv = (void *)&driverCfg.bglayer;
+
+ // Finish Init the board
+ post_init_board(g);
+
+ // Turn on the back-light
+ set_backlight(g, GDISP_INITIAL_BACKLIGHT);
+
+ break;
+
+ case 1: // Display 1 is the foreground layer
+
+ if (!(driverCfg.fglayer.layerflags & LTDC_LEF_ENABLE))
+ return FALSE;
+
+ // Load the foreground layer
+ _ltdc_layer_init(LTDC_Layer2, &driverCfg.fglayer);
+ _ltdc_reload();
+
+ g->priv = (void *)&driverCfg.fglayer;
+
+ // Finish Init the board
+ post_init_board(g);
+
+ break;
+
+ default: // There is only 1 LTDC in the CPU and only the 2 layers in the LTDC.
+ return FALSE;
+ }
+
+ // Initialise the GDISP structure
+ g->g.Width = ((ltdcLayerConfig *)g->priv)->width;
+ g->g.Height = ((ltdcLayerConfig *)g->priv)->height;
+ g->g.Orientation = GDISP_ROTATE_0;
+ g->g.Powermode = powerOn;
+ g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
+ g->g.Contrast = GDISP_INITIAL_CONTRAST;
+
+ return TRUE;
+}
+
+LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) {
+ unsigned pos;
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ default:
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ break;
+ case GDISP_ROTATE_90:
+ pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
+ break;
+ case GDISP_ROTATE_180:
+ pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
+ break;
+ case GDISP_ROTATE_270:
+ pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
+ break;
+ }
+ #else
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ #endif
+
+ #if LTDC_USE_DMA2D
+ while(DMA2D->CR & DMA2D_CR_START);
+ #endif
+
+ #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ // As we don't support ARGB pixel types in uGFX yet we will
+ // use RGB with an inverted alpha value for compatibility
+ // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
+ PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color) ^ 0xFF000000;
+ #else
+ PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
+ #endif
+}
+
+LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) {
+ unsigned pos;
+ LLDCOLOR_TYPE color;
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ default:
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ break;
+ case GDISP_ROTATE_90:
+ pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
+ break;
+ case GDISP_ROTATE_180:
+ pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
+ break;
+ case GDISP_ROTATE_270:
+ pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
+ break;
+ }
+ #else
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ #endif
+
+ #if LTDC_USE_DMA2D
+ while(DMA2D->CR & DMA2D_CR_START);
+ #endif
+
+ #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ // As we don't support ARGB pixel types in uGFX yet we will
+ // use RGB with an inverted alpha value for compatibility
+ // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
+ color = PIXEL_ADDR(g, pos)[0] ^ 0xFF000000;
+ #else
+ color = PIXEL_ADDR(g, pos)[0];
+ #endif
+
+ return gdispNative2Color(color);
+}
+
+#if GDISP_NEED_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay* g) {
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) {
+ coord_t tmp;
+
+ tmp = g->g.Width;
+ g->g.Width = g->g.Height;
+ g->g.Height = tmp;
+ }
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) {
+ coord_t tmp;
+
+ tmp = g->g.Width;
+ g->g.Width = g->g.Height;
+ g->g.Height = tmp;
+ }
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ return;
+
+ case GDISP_CONTROL_BACKLIGHT:
+ if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
+ set_backlight(g, (unsigned)g->p.ptr);
+ g->g.Backlight = (unsigned)g->p.ptr;
+ return;
+ }
+ }
+#endif
+
+#if LTDC_USE_DMA2D
+ #if LTDC_DMA_CACHE_FLUSH
+ #if defined(__CC_ARM)
+ #define __ugfxDSB() __dsb(0xF)
+ #else // GCC like
+ #define __ugfxDSB() __ASM volatile ("dsb 0xF":::"memory")
+ #endif
+ #endif
+
+
+ static void dma2d_init(void) {
+ // Enable DMA2D clock
+ RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
+
+ // Output color format
+ #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
+ DMA2D->OPFCCR = OPFCCR_RGB565;
+ #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ DMA2D->OPFCCR = OPFCCR_ARGB8888;
+ #endif
+
+ // Foreground color format
+ #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565
+ DMA2D->FGPFCCR = FGPFCCR_CM_RGB565;
+ #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ DMA2D->FGPFCCR = FGPFCCR_CM_ARGB8888;
+ #endif
+ }
+
+ // Uses p.x,p.y p.cx,p.cy p.color
+ LLDSPEC void gdisp_lld_fill_area(GDisplay* g)
+ {
+ uint32_t pos;
+ uint32_t lineadd;
+ uint32_t shape;
+
+ #if GDISP_NEED_CONTROL
+ switch(g->g.Orientation) {
+ case GDISP_ROTATE_0:
+ default:
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
+ break;
+ case GDISP_ROTATE_90:
+ pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-g->p.cx);
+ lineadd = g->g.Height - g->p.cy;
+ shape = (g->p.cy << 16) | (g->p.cx);
+ break;
+ case GDISP_ROTATE_180:
+ pos = PIXIL_POS(g, g->g.Width-g->p.x-g->p.cx, g->g.Height-g->p.y-g->p.cy);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
+ break;
+ case GDISP_ROTATE_270:
+ pos = PIXIL_POS(g, g->g.Height-g->p.y-g->p.cy, g->p.x);
+ lineadd = g->g.Height - g->p.cy;
+ shape = (g->p.cy << 16) | (g->p.cx);
+ break;
+ }
+ #else
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
+ #endif
+
+ #if LTDC_DMA_CACHE_FLUSH
+ {
+ // This is slightly less than optimal as we flush the whole line in the source and destination image
+ // instead of just the cx portion but this saves us having to iterate over each line.
+ uint32_t f, e;
+
+ // Data memory barrier
+ __ugfxDSB();
+
+ // Flush then invalidate the destination area
+ e = pos + (g->p.cy > 1 ? ((uint32_t)((ltdcLayerConfig *)g->priv)->pitch*(shape & 0xFFFF)) : ((shape>>16)*LTDC_PIXELBYTES));
+ for(f=(pos & ~31); f < e; f += 32) {
+ SCB->DCCIMVAC = f;
+ SCB->DCIMVAC = f;
+ }
+
+ // Data memory barrier
+ __ugfxDSB();
+ }
+ #endif
+
+ // Wait until DMA2D is ready
+ while(DMA2D->CR & DMA2D_CR_START);
+
+ // Start the DMA2D
+ DMA2D->OMAR = (uint32_t)PIXEL_ADDR(g, pos);
+ DMA2D->OOR = lineadd;
+ DMA2D->NLR = shape;
+ #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888
+ // As we don't support ARGB pixel types in uGFX yet we will
+ // use RGB with an inverted alpha value for compatibility
+ // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white
+ DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color)) ^ 0xFF000000;
+ #else
+ DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color));
+ #endif
+ ;
+ DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START;
+ }
+
+ /* Oops - the DMA2D only supports GDISP_ROTATE_0.
+ *
+ * Where the width is 1 we can trick it for other orientations.
+ * That is worthwhile as a width of 1 is common. For other
+ * situations we need to fall back to pixel pushing.
+ *
+ * Additionally, although DMA2D can translate color formats
+ * it can only do it for a small range of formats. For any
+ * other formats we also need to fall back to pixel pushing.
+ *
+ * As the code to actually do all that for other than the
+ * simplest case (orientation == GDISP_ROTATE_0 and
+ * GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT) is very complex
+ * we will always pixel push for now. In practice that is OK as
+ * access to the framebuffer is fast - probably faster than DMA2D.
+ * It just uses more CPU.
+ */
+ #if GDISP_HARDWARE_BITFILLS
+ // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer)
+ LLDSPEC void gdisp_lld_blit_area(GDisplay* g) {
+ uint32_t srcstart, dststart;
+
+ srcstart = LTDC_PIXELBYTES * ((uint32_t)g->p.x2 * g->p.y1 * + g->p.x1) + (uint32_t)g->p.ptr;
+ dststart = (uint32_t)PIXEL_ADDR(g, PIXIL_POS(g, g->p.x, g->p.y));
+
+ #if LTDC_DMA_CACHE_FLUSH
+ {
+ // This is slightly less than optimal as we flush the whole line in the source and destination image
+ // instead of just the cx portion but this saves us having to iterate over each line.
+ uint32_t f, e;
+
+ // Data memory barrier
+ __ugfxDSB();
+
+ // Flush the source area
+ e = srcstart + (g->p.cy > 1 ? ((uint32_t)g->p.x2*g->p.cy) : (uint32_t)g->p.cx)*LTDC_PIXELBYTES;
+ for(f=(srcstart & ~31); f < e; f += 32)
+ SCB->DCCIMVAC = f;
+
+ // Flush then invalidate the destination area
+ e = dststart + (g->p.cy > 1 ? ((uint32_t)((ltdcLayerConfig *)g->priv)->pitch*g->p.cy) : ((uint32_t)g->p.cx*LTDC_PIXELBYTES));
+ for(f=(dststart & ~31); f < e; f += 32) {
+ SCB->DCCIMVAC = f;
+ SCB->DCIMVAC = f;
+ }
+
+ // Data memory barrier
+ __ugfxDSB();
+ }
+ #endif
+
+ // Wait until DMA2D is ready
+ while(DMA2D->CR & DMA2D_CR_START);
+
+ // Source setup
+ DMA2D->FGMAR = srcstart;
+ DMA2D->FGOR = g->p.x2 - g->p.cx;
+
+ // Output setup
+ DMA2D->OMAR = dststart;
+ DMA2D->OOR = g->g.Width - g->p.cx;
+ DMA2D->NLR = (g->p.cx << 16) | (g->p.cy);
+
+ // Set MODE to M2M and Start the process
+ DMA2D->CR = DMA2D_CR_MODE_M2M | DMA2D_CR_START;
+ }
+ #endif
+
+#endif /* LTDC_USE_DMA2D */
+
+#endif /* GFX_USE_GDISP */