aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
diff options
context:
space:
mode:
authorJoel Bodenmann <joel@seriouslyembedded.com>2015-07-09 00:43:04 +0200
committerJoel Bodenmann <joel@seriouslyembedded.com>2015-07-09 00:43:04 +0200
commitc58dabc9c9aaa26e1d273e62c8e7508a0a3f7690 (patch)
tree8ab5ae5bef809ded4426c5173121ee3297bb8726 /drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
parent926c8e507b7611e5bf182942872f770b22a5c7bd (diff)
downloaduGFX-c58dabc9c9aaa26e1d273e62c8e7508a0a3f7690.tar.gz
uGFX-c58dabc9c9aaa26e1d273e62c8e7508a0a3f7690.tar.bz2
uGFX-c58dabc9c9aaa26e1d273e62c8e7508a0a3f7690.zip
Renaming driver to STM32LTDC as this will be a generic one
Diffstat (limited to 'drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c')
-rw-r--r--drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c365
1 files changed, 365 insertions, 0 deletions
diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
new file mode 100644
index 00000000..118b6874
--- /dev/null
+++ b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
@@ -0,0 +1,365 @@
+/*
+ * 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
+
+#if defined(GDISP_SCREEN_HEIGHT)
+ #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
+ #undef GISP_SCREEN_HEIGHT
+#endif
+#if defined(GDISP_SCREEN_WIDTH)
+ #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
+ #undef GDISP_SCREEN_WIDTH
+#endif
+
+#define GDISP_DRIVER_VMT GDISPVMT_STM32LTDC
+#include "drivers/gdisp/STM32LTDC/gdisp_lld_config.h"
+#include "src/gdisp/gdisp_driver.h"
+
+#include "stm32_ltdc.h"
+
+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;
+
+#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 }
+
+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
+ uint8_t syncflags; // Sync flags
+ uint32_t bgcolor; // Clear screen color RGB888
+
+ ltdcLayerConfig bglayer; // Background layer config
+ ltdcLayerConfig fglayer; // Foreground layer config
+} ltdcConfig;
+
+#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_RGB888
+ #define LTDC_PIXELBYTES 3
+ #define LTDC_PIXELBITS 24
+#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) * driverCfg.bglayer.pitch + (x) * LTDC_PIXELBYTES)
+#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)((uint8_t *)driverCfg.bglayer.frame+pos))
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+static void LTDC_Reload(void)
+{
+ LTDC->SRCR |= LTDC_SRCR_IMR;
+
+ while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) {
+ gfxYield();
+ }
+}
+
+static void LTDC_LayerInit(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 hardware module.*/
+ RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST;
+ RCC->APB2RSTR = 0;
+
+ /* Enable the LTDC clock.*/
+ RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (1 << 16); /* /4 */
+
+ // Enable the module
+ 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_LayerInit(LTDC_Layer1, &driverCfg.bglayer);
+
+ // Load the foreground layer
+ LTDC_LayerInit(LTDC_Layer2, &driverCfg.fglayer);
+
+ // Interrupt handling
+ //nvicEnableVector(STM32_LTDC_EV_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_EV_IRQ_PRIORITY));
+ //nvicEnableVector(STM32_LTDC_ER_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_ER_IRQ_PRIORITY));
+ // 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;
+ //if (!(g->priv = gfxAlloc(sizeof(fbPriv))))
+ // gfxHalt("GDISP Framebuffer: Failed to allocate private memory");
+
+ // Init the board
+ init_board(g);
+ //((fbPriv *)g->priv)->fbi.cfg = init_board(g);
+
+ // Initialise the LTDC controller
+ LTDC_Init();
+
+ // Initialise DMA2D
+ //dma2dStart(&DMA2DD1, &dma2d_cfg);
+ //dma2d_test();
+
+ // Finish Init the board
+ post_init_board(g);
+
+ // Turn on the back-light
+ set_backlight(g, GDISP_INITIAL_BACKLIGHT);
+
+ // Initialise the GDISP structure
+ g->g.Width = driverCfg.bglayer.width;
+ g->g.Height = driverCfg.bglayer.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
+
+ PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
+}
+
+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
+
+ color = PIXEL_ADDR(g, pos)[0];
+
+ return gdispNative2Color(color);
+}
+
+#if GDISP_NEED_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay* g)
+ {
+ switch(g->p.x) {
+ case GDISP_CONTROL_POWER:
+ if (g->g.Powermode == (powermode_t)g->p.ptr)
+ return;
+ switch((powermode_t)g->p.ptr) {
+ case powerOff: case powerOn: case powerSleep: case powerDeepSleep:
+ // TODO
+ break;
+ default:
+ return;
+ }
+ g->g.Powermode = (powermode_t)g->p.ptr;
+ return;
+
+ 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;
+
+ case GDISP_CONTROL_CONTRAST:
+ if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
+ // TODO
+ g->g.Contrast = (unsigned)g->p.ptr;
+ return;
+ }
+ }
+#endif
+
+#endif /* GFX_USE_GDISP */