2303 lines
63 KiB
C
2303 lines
63 KiB
C
/******************************************************************************
|
|
* arch/arm/src/stm32/stm32_dma2d.c
|
|
*
|
|
* Copyright (C) 2014-2015 Marco Krahl. All rights reserved.
|
|
* Author: Marco Krahl <ocram.lhark@gmail.com>
|
|
*
|
|
* References:
|
|
* STM32F429 Technical Reference Manual
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
* Included Files
|
|
******************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
#include <semaphore.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/video/fb.h>
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include <arch/chip/dma2d.h>
|
|
#include <arch/board/board.h>
|
|
|
|
#include "up_arch.h"
|
|
#include "up_internal.h"
|
|
#include "stm32.h"
|
|
#include "chip/stm32_ltdc.h"
|
|
#include "chip/stm32_dma2d.h"
|
|
#include "chip/stm32_ccm.h"
|
|
#include "stm32_dma2d.h"
|
|
|
|
/******************************************************************************
|
|
* Pre-processor Definitions
|
|
******************************************************************************/
|
|
|
|
/* output, foreground and background layer */
|
|
|
|
#define DMA2D_NLAYERS 3
|
|
|
|
/* DMA2D PFC value definitions */
|
|
|
|
#define DMA2D_PF_ARGB8888 0
|
|
#define DMA2D_PF_RGB888 1
|
|
#define DMA2D_PF_RGB565 2
|
|
#define DMA2D_PF_ARGB1555 3
|
|
#define DMA2D_PF_ARGB14444 4
|
|
#define DMA2D_PF_L8 5
|
|
#define DMA2D_PF_AL44 6
|
|
#define DMA2D_PF_AL88 7
|
|
#define DMA2D_PF_L4 8
|
|
#define DMA2D_PF_A8 9
|
|
#define DMA2D_PF_A4 10
|
|
|
|
/* DMA2D blender control */
|
|
|
|
#define STM32_DMA2D_CR_MODE_BLIT DMA2D_CR_MODE(0)
|
|
#define STM32_DMA2D_CR_MODE_BLITPFC DMA2D_CR_MODE(1)
|
|
#define STM32_DMA2D_CR_MODE_BLEND DMA2D_CR_MODE(2)
|
|
#define STM32_DMA2D_CR_MODE_COLOR DMA2D_CR_MODE(3)
|
|
#define STM32_DMA2D_CR_MODE_CLEAR STM32_DMA2D_CR_MODE_COLOR
|
|
|
|
/* DMA2D PFC alpha mode */
|
|
|
|
#define STM32_DMA2D_PFCCR_AM_NONE 0
|
|
#define STM32_DMA2D_PFCCR_AM_CONST 1
|
|
#define STM32_DMA2D_PFCCR_AM_PIXEL 10
|
|
|
|
/* Only 8 bit per pixel overal supported */
|
|
|
|
#define DMA2D_PF_BYPP(n) ((n) / 8)
|
|
|
|
#define DMA2D_CLUT_SIZE STM32_LTDC_NCLUT - 1
|
|
|
|
/* Layer argb cmap conversion */
|
|
|
|
#define DMA2D_CLUT_ALPHA(n) ((uint32_t)(n) << 24)
|
|
#define DMA2D_CLUT_RED(n) ((uint32_t)(n) << 16)
|
|
#define DMA2D_CLUT_GREEN(n) ((uint32_t)(n) << 8)
|
|
#define DMA2D_CLUT_BLUE(n) ((uint32_t)(n) << 0)
|
|
|
|
#define DMA2D_CMAP_ALPHA(n) ((uint32_t)(n) >> 24)
|
|
#define DMA2D_CMAP_RED(n) ((uint32_t)(n) >> 16)
|
|
#define DMA2D_CMAP_GREEN(n) ((uint32_t)(n) >> 8)
|
|
#define DMA2D_CMAP_BLUE(n) ((uint32_t)(n) >> 0)
|
|
|
|
/* Define shadow layer for ltdc interface */
|
|
|
|
#ifdef CONFIG_STM32_LTDC_INTERFACE
|
|
# ifdef CONFIG_STM32_LTDC_L2
|
|
# define DMA2D_SHADOW_LAYER 2
|
|
# define DMA2D_SHADOW_LAYER_L1 0
|
|
# define DMA2D_SHADOW_LAYER_L2 1
|
|
# else
|
|
# define DMA2D_SHADOW_LAYER 1
|
|
# define DMA2D_SHADOW_LAYER_L1 0
|
|
# endif
|
|
# define DMA2D_LAYER_NSIZE CONFIG_STM32_DMA2D_NLAYERS + DMA2D_SHADOW_LAYER
|
|
#else
|
|
# define DMA2D_LAYER_NSIZE CONFIG_STM32_DMA2D_NLAYERS
|
|
# define DMA2D_SHADOW_LAYER 0
|
|
#endif
|
|
|
|
/* Debug option */
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_REGDEBUG
|
|
# define regdbg dbg
|
|
# define regvdbg vdbg
|
|
#else
|
|
# define regdbg(x...)
|
|
# define regvdbg(x...)
|
|
#endif
|
|
|
|
/* check clut support */
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
# ifndef CONFIG_FB_CMAP
|
|
# error "Enable cmap to support the configured layer formats!"
|
|
# endif
|
|
#endif
|
|
|
|
/* check ccm heap allocation */
|
|
|
|
#ifndef CONFIG_STM32_CCMEXCLUDE
|
|
# error "Enable CONFIG_STM32_CCMEXCLUDE from the heap allocation"
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Private Types
|
|
******************************************************************************/
|
|
|
|
/* DMA2D General layer information */
|
|
|
|
struct stm32_dma2d_s
|
|
{
|
|
struct dma2d_layer_s dma2d; /* public dma2d interface */
|
|
|
|
/* Fixed settings */
|
|
|
|
int lid; /* Layer identifier */
|
|
struct fb_videoinfo_s vinfo; /* Layer videoinfo */
|
|
struct fb_planeinfo_s pinfo; /* Layer planeinfo */
|
|
|
|
/* Blending */
|
|
|
|
uint32_t blendmode; /* the interface blendmode */
|
|
uint8_t alpha; /* the alpha value */
|
|
|
|
/* Coloring */
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
uint32_t *clut; /* Color lookup table */
|
|
#endif
|
|
|
|
/* Operation */
|
|
uint8_t fmt; /* the controller pixel format */
|
|
sem_t *lock; /* Ensure mutually exclusive access */
|
|
};
|
|
|
|
#ifdef CONFIG_STM32_LTDC_INTERFACE
|
|
|
|
/* This structures provides the DMA2D layer for each LTDC layer */
|
|
|
|
struct stm32_ltdc_dma2d_s
|
|
{
|
|
struct stm32_dma2d_s dma2ddev;
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
FAR struct ltdc_layer_s *ltdc;
|
|
#endif
|
|
};
|
|
|
|
struct stm32_ltdc_layer_s
|
|
{
|
|
/* Layer state */
|
|
|
|
struct stm32_ltdc_dma2d_s layer[DMA2D_SHADOW_LAYER];
|
|
};
|
|
#endif
|
|
|
|
/* Interrupt handling */
|
|
|
|
struct stm32_interrupt_s
|
|
{
|
|
bool wait; /* Informs that the task is waiting for the irq */
|
|
bool handled; /* Informs that an irq was handled */
|
|
int irq; /* irq number */
|
|
sem_t *sem; /* Semaphore for waiting for irq */
|
|
};
|
|
|
|
/* This enumeration foreground and background layer supported by the dma2d
|
|
* controller
|
|
*/
|
|
|
|
enum stm32_layer_e
|
|
{
|
|
DMA2D_LAYER_LFORE = 0, /* Foreground Layer */
|
|
DMA2D_LAYER_LBACK, /* Background Layer */
|
|
DMA2D_LAYER_LOUT, /* Output Layer */
|
|
};
|
|
|
|
/* DMA2D memory address register */
|
|
|
|
static const uintptr_t stm32_mar_layer_t[DMA2D_NLAYERS] =
|
|
{
|
|
STM32_DMA2D_FGMAR,
|
|
STM32_DMA2D_BGMAR,
|
|
STM32_DMA2D_OMAR
|
|
};
|
|
|
|
/* DMA2D offset register */
|
|
|
|
static const uintptr_t stm32_or_layer_t[DMA2D_NLAYERS] =
|
|
{
|
|
STM32_DMA2D_FGOR,
|
|
STM32_DMA2D_BGOR,
|
|
STM32_DMA2D_OOR
|
|
};
|
|
|
|
/* DMA2D pfc control register */
|
|
|
|
static const uintptr_t stm32_pfccr_layer_t[DMA2D_NLAYERS] =
|
|
{
|
|
STM32_DMA2D_FGPFCCR,
|
|
STM32_DMA2D_BGPFCCR,
|
|
STM32_DMA2D_OPFCCR
|
|
};
|
|
|
|
/* DMA2D color register */
|
|
|
|
static const uintptr_t stm32_color_layer_t[DMA2D_NLAYERS] =
|
|
{
|
|
STM32_DMA2D_FGCOLR,
|
|
STM32_DMA2D_BGCOLR,
|
|
STM32_DMA2D_OCOLR
|
|
};
|
|
|
|
/* DMA2D clut memory address register */
|
|
|
|
static const uintptr_t stm32_cmar_layer_t[DMA2D_NLAYERS - 1] =
|
|
{
|
|
STM32_DMA2D_FGCMAR,
|
|
STM32_DMA2D_BGCMAR
|
|
};
|
|
|
|
/******************************************************************************
|
|
* Private Function Prototypes
|
|
******************************************************************************/
|
|
|
|
/* Private functions */
|
|
|
|
static int stm32_dma2d_pixelformat(uint8_t fmt, uint8_t *fmtmap);
|
|
static int stm32_dma2d_bpp(uint8_t fmt, uint8_t *bpp);
|
|
static void stm32_dma2d_control(uint32_t setbits, uint32_t clrbits);
|
|
static int stm32_dma2dirq(int irq, void *context);
|
|
static int stm32_dma2d_waitforirq(void);
|
|
static int stm32_dma2d_start(void);
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
static int stm32_dma2d_loadclut(uintptr_t reg);
|
|
#endif
|
|
static uint32_t stm32_dma2d_memaddress(FAR const struct stm32_dma2d_s *layer,
|
|
fb_coord_t xpos, fb_coord_t ypos);
|
|
static fb_coord_t stm32_dma2d_lineoffset(FAR const struct stm32_dma2d_s *layer,
|
|
FAR const struct ltdc_area_s *area);
|
|
|
|
static int stm32_dma2d_lfreelid(void);
|
|
static FAR struct stm32_dma2d_s * stm32_dma2d_lalloc(void);
|
|
static void stm32_dma2d_lfree(FAR struct stm32_dma2d_s *layer);
|
|
static void stm32_dma2d_llayerscleanup(void);
|
|
static bool stm32_dma2d_lvalidate(FAR const struct stm32_dma2d_s *layer);
|
|
static bool stm32_dma2d_lvalidatesize(FAR const struct stm32_dma2d_s *layer,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
FAR const struct ltdc_area_s *area);
|
|
static void stm32_dma2d_linit(FAR struct stm32_dma2d_s *layer,
|
|
int lid, uint8_t fmt);
|
|
|
|
static void stm32_dma2d_lfifo(FAR const struct stm32_dma2d_s *layer, int lid,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
FAR const struct ltdc_area_s *area);
|
|
static void stm32_dma2d_lcolor(FAR const struct stm32_dma2d_s *layer,
|
|
int lid, uint32_t color);
|
|
static void stm32_dma2d_llnr(FAR struct stm32_dma2d_s *layer,
|
|
FAR const struct ltdc_area_s *area);
|
|
static int stm32_dma2d_loutpfc(FAR const struct stm32_dma2d_s *layer);
|
|
static void stm32_dma2d_lpfc(FAR const struct stm32_dma2d_s *layer,
|
|
int lid, uint32_t blendmode);
|
|
/* Public functions */
|
|
|
|
static int stm32_dma2dgetvideoinfo(FAR struct dma2d_layer_s *layer,
|
|
FAR struct fb_videoinfo_s *vinfo);
|
|
static int stm32_dma2dgetplaneinfo(FAR struct dma2d_layer_s *layer, int planeno,
|
|
FAR struct fb_planeinfo_s *pinfo);
|
|
static int stm32_dma2dgetlid(FAR struct dma2d_layer_s *layer, int *lid);
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
static int stm32_dma2dsetclut(FAR struct dma2d_layer_s *layer,
|
|
const FAR struct fb_cmap_s *cmap);
|
|
static int stm32_dma2dgetclut(FAR struct dma2d_layer_s *layer,
|
|
FAR struct fb_cmap_s *cmap);
|
|
#endif
|
|
static int stm32_dma2dsetalpha(FAR struct dma2d_layer_s *layer, uint8_t alpha);
|
|
static int stm32_dma2dgetalpha(FAR struct dma2d_layer_s *layer, uint8_t *alpha);
|
|
static int stm32_dma2dsetblendmode(FAR struct dma2d_layer_s *layer,
|
|
uint32_t mode);
|
|
static int stm32_dma2dgetblendmode(FAR struct dma2d_layer_s *layer,
|
|
uint32_t *mode);
|
|
static int stm32_dma2dblit(FAR struct dma2d_layer_s *dest,
|
|
fb_coord_t destxpos, fb_coord_t destypos,
|
|
FAR const struct dma2d_layer_s *src,
|
|
FAR const struct ltdc_area_s *srcarea);
|
|
static int stm32_dma2dblend(FAR struct dma2d_layer_s *dest,
|
|
fb_coord_t destxpos, fb_coord_t destypos,
|
|
FAR const struct dma2d_layer_s *fore,
|
|
fb_coord_t forexpos, fb_coord_t foreypos,
|
|
FAR const struct dma2d_layer_s *back,
|
|
FAR const struct ltdc_area_s *backarea);
|
|
static int stm32_dma2dfillarea(FAR struct dma2d_layer_s *layer,
|
|
FAR const struct ltdc_area_s *area, uint32_t color);
|
|
|
|
/******************************************************************************
|
|
* Private Data
|
|
******************************************************************************/
|
|
|
|
/* Remember the layer references for alloc/deallocation */
|
|
|
|
static struct stm32_dma2d_s *g_layers[DMA2D_LAYER_NSIZE];
|
|
|
|
/* The DMA2D semaphore that enforces mutually exclusive access */
|
|
|
|
static sem_t g_lock;
|
|
|
|
#ifdef CONFIG_STM32_LTDC_INTERFACE
|
|
/* This structure provides the DMA2D layer for each LTDC layer */
|
|
|
|
static struct stm32_ltdc_layer_s g_ltdc_layer;
|
|
#endif
|
|
|
|
/* The initalized state of the driver */
|
|
|
|
static bool g_initialized;
|
|
|
|
/* Semaphore for interrupt handling */
|
|
|
|
static sem_t g_semirq;
|
|
|
|
/* This structure provides irq handling */
|
|
|
|
static struct stm32_interrupt_s g_interrupt =
|
|
{
|
|
.wait = false,
|
|
.handled = true,
|
|
.irq = STM32_IRQ_DMA2D,
|
|
.sem = &g_semirq
|
|
};
|
|
|
|
/******************************************************************************
|
|
* Public Data
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
* Private Functions
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_control
|
|
*
|
|
* Description:
|
|
* Change the DMA2D control register
|
|
*
|
|
* Parameter:
|
|
* setbits - The bits to set
|
|
* clrbits - The bits to clear
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_dma2d_control(uint32_t setbits, uint32_t clrbits)
|
|
{
|
|
uint32_t cr;
|
|
|
|
gvdbg("setbits=%08x, clrbits=%08x\n", setbits, clrbits);
|
|
|
|
cr = getreg32(STM32_DMA2D_CR);
|
|
cr &= ~clrbits;
|
|
cr |= setbits;
|
|
putreg32(cr, STM32_DMA2D_CR);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_dma2dirq
|
|
*
|
|
* Description:
|
|
* DMA2D interrupt handler
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2dirq(int irq, void *context)
|
|
{
|
|
uint32_t regval = getreg32(STM32_DMA2D_ISR);
|
|
FAR struct stm32_interrupt_s *priv = &g_interrupt;
|
|
|
|
regvdbg("irq = %d, regval = %08x\n", irq, regval);
|
|
|
|
if (regval & DMA2D_ISR_TCIF)
|
|
{
|
|
/* Transfer complete interrupt */
|
|
|
|
/* Clear the interrupt status register */
|
|
|
|
putreg32(DMA2D_IFCR_CTCIF, STM32_DMA2D_IFCR);
|
|
}
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
else if (regval & DMA2D_ISR_CTCIF)
|
|
{
|
|
/* CLUT transfer complete interrupt */
|
|
|
|
/* Clear the interrupt status register */
|
|
|
|
putreg32(DMA2D_IFCR_CCTCIF, STM32_DMA2D_IFCR);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* Unknown irq, should not occur */
|
|
|
|
return OK;
|
|
}
|
|
|
|
/* Update the handled flag */
|
|
|
|
priv->handled = true;
|
|
|
|
/* Unlock the semaphore if locked */
|
|
|
|
if (priv->wait)
|
|
{
|
|
|
|
int ret = sem_post(priv->sem);
|
|
|
|
if (ret != OK)
|
|
{
|
|
dbg("sem_post() failed\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_waitforirq
|
|
*
|
|
* Description:
|
|
* Helper waits until the dma2d irq occurs. That means that an ongoing clut
|
|
* loading or dma transfer was completed.
|
|
* Note! The caller must use this function within irqsave state.
|
|
*
|
|
* Return:
|
|
* On success OK otherwise ERROR
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2d_waitforirq(void)
|
|
{
|
|
FAR struct stm32_interrupt_s *priv = &g_interrupt;
|
|
|
|
/* Only waits if last enabled interrupt is currently not handled */
|
|
|
|
if (!priv->handled)
|
|
{
|
|
int ret;
|
|
|
|
/* Inform the irq handler the task is able to wait for the irq */
|
|
|
|
priv->wait = true;
|
|
|
|
ret = sem_wait(priv->sem);
|
|
|
|
/* irq or an error occurs, reset the wait flag */
|
|
|
|
priv->wait = false;
|
|
|
|
if (ret != OK)
|
|
{
|
|
dbg("sem_wait() failed\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_loadclut
|
|
*
|
|
* Description:
|
|
* Starts clut loading but doesn't wait until loading is complete!
|
|
*
|
|
* Parameter:
|
|
* pfcreg - PFC control Register
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2d_loadclut(uintptr_t pfcreg)
|
|
{
|
|
int ret;
|
|
uint32_t regval;
|
|
irqstate_t flags;
|
|
|
|
flags = irqsave();
|
|
|
|
ret = stm32_dma2d_waitforirq();
|
|
if (ret == OK)
|
|
{
|
|
FAR struct stm32_interrupt_s *priv = &g_interrupt;
|
|
|
|
/* Reset the handled flag */
|
|
|
|
priv->handled = false;
|
|
|
|
/* Start clut loading */
|
|
|
|
regval = getreg32(pfcreg);
|
|
regval |= DMA2D_xGPFCCR_START;
|
|
regvdbg("set regval=%08x\n", regval);
|
|
putreg32(regval, pfcreg);
|
|
regvdbg("configured regval=%08x\n", getreg32(pfcreg));
|
|
}
|
|
|
|
irqrestore(flags);
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_start
|
|
*
|
|
* Description:
|
|
* Starts the dma transfer and waits until completed.
|
|
*
|
|
* Parameter:
|
|
* reg - Register to set the start
|
|
* startflag - The related flag to start the dma transfer
|
|
* irqflag - The interrupt enable flag in the DMA2D_CR register
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2d_start(void)
|
|
{
|
|
int ret;
|
|
irqstate_t flags;
|
|
|
|
flags = irqsave();
|
|
|
|
ret = stm32_dma2d_waitforirq();
|
|
if (ret == OK)
|
|
{
|
|
FAR struct stm32_interrupt_s *priv = &g_interrupt;
|
|
|
|
/* Reset the handled flag */
|
|
|
|
priv->handled = false;
|
|
|
|
/* Start clut loading */
|
|
|
|
stm32_dma2d_control(DMA2D_CR_START, 0);
|
|
|
|
/* wait until transfer is complete */
|
|
|
|
ret = stm32_dma2d_waitforirq();
|
|
}
|
|
|
|
irqrestore(flags);
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_memaddress
|
|
*
|
|
* Description:
|
|
* Helper to calculate the layer memory address
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
* Return:
|
|
* memory address
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static uint32_t stm32_dma2d_memaddress(FAR const struct stm32_dma2d_s *layer,
|
|
fb_coord_t xpos, fb_coord_t ypos)
|
|
{
|
|
FAR const struct fb_planeinfo_s *pinfo = &layer->pinfo;
|
|
uint32_t offset;
|
|
|
|
offset = xpos * DMA2D_PF_BYPP(layer->pinfo.bpp) + layer->pinfo.stride * ypos;
|
|
|
|
gvdbg("%p\n", ((uint32_t) pinfo->fbmem) + offset);
|
|
return ((uint32_t) pinfo->fbmem) + offset;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lineoffset
|
|
*
|
|
* Description:
|
|
* Helper to calculate the layer line offset
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
* Return:
|
|
* line offset
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static fb_coord_t stm32_dma2d_lineoffset(FAR const struct stm32_dma2d_s *layer,
|
|
FAR const struct ltdc_area_s *area)
|
|
{
|
|
/* offset at the end of each line in the context to the area layer */
|
|
|
|
gvdbg("%d\n", layer->vinfo.xres - area->xres);
|
|
return layer->vinfo.xres - area->xres;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_pixelformat
|
|
*
|
|
* Description:
|
|
* Helper to map to dma2d controller pixel format
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
* fmt - Reference to the location to store the pixel format
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static int stm32_dma2d_pixelformat(uint8_t fmt, uint8_t *fmtmap)
|
|
{
|
|
gvdbg("fmt=%d, fmtmap=%p\n", fmt, fmtmap);
|
|
|
|
/* Map to the controller known format
|
|
*
|
|
* Not supported by NuttX:
|
|
* ARGB8888
|
|
* ARGB1555
|
|
* ARGB4444
|
|
* AL44
|
|
* AL88
|
|
* L8 (non output layer only)
|
|
* L4
|
|
* A8
|
|
* A4
|
|
*/
|
|
|
|
switch(fmt)
|
|
{
|
|
#ifdef CONFIG_STM32_DMA2D_RGB565
|
|
case FB_FMT_RGB16_565:
|
|
*fmtmap = DMA2D_PF_RGB565;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_DMA2D_RGB888
|
|
case FB_FMT_RGB24:
|
|
*fmtmap = DMA2D_PF_RGB888;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
case FB_FMT_RGB8:
|
|
*fmtmap = DMA2D_PF_L8;
|
|
break;
|
|
#endif
|
|
default:
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_bpp
|
|
*
|
|
* Description:
|
|
* Helper to get the bits per pixel
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
* bpp - Reference to the location to store the pixel format
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static int stm32_dma2d_bpp(uint8_t fmt, uint8_t *bpp)
|
|
{
|
|
gvdbg("fmt=%d, bpp=%p\n", fmt, bpp);
|
|
|
|
switch(fmt)
|
|
{
|
|
#ifdef CONFIG_STM32_DMA2D_RGB565
|
|
case FB_FMT_RGB16_565:
|
|
*bpp = 16;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_DMA2D_RGB888
|
|
case FB_FMT_RGB24:
|
|
*bpp = 24;
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
case FB_FMT_RGB8:
|
|
*bpp = 8;
|
|
break;
|
|
#endif
|
|
default:
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lfreelid
|
|
*
|
|
* Description:
|
|
* Get a free layer id
|
|
*
|
|
* Return:
|
|
* The number of the free layer
|
|
* -1 if no free layer is available
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2d_lfreelid(void)
|
|
{
|
|
int n;
|
|
|
|
for (n = DMA2D_SHADOW_LAYER; n < DMA2D_LAYER_NSIZE; n++)
|
|
{
|
|
if (g_layers[n] == NULL)
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lalloc
|
|
*
|
|
* Description:
|
|
* Allocate a new layer structure
|
|
*
|
|
* Return:
|
|
* A new allocated layer structure or NULL on error.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static FAR struct stm32_dma2d_s * stm32_dma2d_lalloc(void)
|
|
{
|
|
FAR struct stm32_dma2d_s *layer;
|
|
|
|
#ifdef HAVE_CCM_HEAP
|
|
/* First try to allocate from the ccm heap */
|
|
|
|
layer = ccm_malloc(sizeof(struct stm32_dma2d_s));
|
|
|
|
if (!layer)
|
|
{
|
|
/* Use default allocator */
|
|
|
|
layer = kmm_malloc(sizeof(struct stm32_dma2d_s));
|
|
}
|
|
#else
|
|
layer = kmm_malloc(sizeof(struct stm32_dma2d_s));
|
|
#endif
|
|
|
|
return layer;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lfree
|
|
*
|
|
* Description:
|
|
* Deallocate the dynamic allocated layer structure
|
|
*
|
|
* Input Parameters:
|
|
* A previous allocated layer structure
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void stm32_dma2d_lfree(FAR struct stm32_dma2d_s *layer)
|
|
{
|
|
if (layer)
|
|
{
|
|
#ifdef HAVE_CCM_HEAP
|
|
if (((uint32_t)layer & 0xf0000000) == 0x10000000)
|
|
{
|
|
ccm_free(layer);
|
|
}
|
|
else
|
|
{
|
|
kmm_free(layer);
|
|
}
|
|
#else
|
|
kmm_free(layer);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_llayerscleanup
|
|
*
|
|
* Description:
|
|
* Cleanup all allocated layers
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void stm32_dma2d_llayerscleanup(void)
|
|
{
|
|
int n;
|
|
|
|
/* Do not uninitialize the ltdc related dma2d layer */
|
|
|
|
for (n = DMA2D_SHADOW_LAYER; n < DMA2D_LAYER_NSIZE; n++)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = g_layers[n];
|
|
if (priv)
|
|
{
|
|
kmm_free(priv->pinfo.fbmem);
|
|
stm32_dma2d_lfree(priv);
|
|
g_layers[n] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lvalidate
|
|
*
|
|
* Description:
|
|
* Helper to validate if the layer is valid
|
|
*
|
|
* Return:
|
|
* true if validates otherwise false
|
|
*
|
|
******************************************************************************/
|
|
|
|
static inline bool stm32_dma2d_lvalidate(FAR const struct stm32_dma2d_s *layer)
|
|
{
|
|
return layer && layer->lid < DMA2D_LAYER_NSIZE;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_dma2d_lvalidatesize
|
|
*
|
|
* Description:
|
|
* Helper to check if area is outside the whole layer.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer control structure
|
|
* xpos - The x position inside the whole layer
|
|
* ypos - The y position inside the whole layer
|
|
* area - the area inside the whole layer
|
|
*
|
|
* Return:
|
|
* true if area is inside the whole layer otherwise false
|
|
*
|
|
****************************************************************************/
|
|
|
|
static bool stm32_dma2d_lvalidatesize(FAR const struct stm32_dma2d_s *layer,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
FAR const struct ltdc_area_s *area)
|
|
{
|
|
return stm32_dma2d_lvalidate(layer) &&
|
|
((layer->vinfo.xres - xpos) * (layer->vinfo.yres - ypos) >=
|
|
area->xres * area->yres);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_linit
|
|
*
|
|
* Description:
|
|
* Initialize the internal layer structure
|
|
*
|
|
* Parameter:
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void stm32_dma2d_linit(FAR struct stm32_dma2d_s *layer,
|
|
int lid, uint8_t fmt)
|
|
{
|
|
FAR struct dma2d_layer_s *priv = &layer->dma2d;
|
|
|
|
gvdbg("layer=%p, lid=%d, fmt=%02x\n", layer, lid, fmt);
|
|
|
|
/* initialize the layer interface */
|
|
|
|
priv->getvideoinfo = stm32_dma2dgetvideoinfo;
|
|
priv->getplaneinfo = stm32_dma2dgetplaneinfo;
|
|
priv->getlid = stm32_dma2dgetlid;
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
priv->setclut = stm32_dma2dsetclut;
|
|
priv->getclut = stm32_dma2dgetclut;
|
|
#endif
|
|
priv->setalpha = stm32_dma2dsetalpha;
|
|
priv->getalpha = stm32_dma2dgetalpha;
|
|
priv->setblendmode = stm32_dma2dsetblendmode;
|
|
priv->getblendmode = stm32_dma2dgetblendmode;
|
|
priv->blit = stm32_dma2dblit;
|
|
priv->blend = stm32_dma2dblend;
|
|
priv->fillarea = stm32_dma2dfillarea;
|
|
|
|
/* Initialize the layer structure */
|
|
|
|
layer->lid = lid;
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
layer->clut = 0;
|
|
#endif
|
|
layer->blendmode = DMA2D_BLEND_NONE;
|
|
layer->alpha = 255;
|
|
layer->fmt = fmt;
|
|
layer->lock = &g_lock;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lfifo
|
|
*
|
|
* Description:
|
|
* Set the fifo for the foreground, background and output layer
|
|
* Configures the memory address register
|
|
* Configures the line offset register
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_dma2d_lfifo(FAR const struct stm32_dma2d_s *layer, int lid,
|
|
fb_coord_t xpos, fb_coord_t ypos,
|
|
FAR const struct ltdc_area_s *area)
|
|
{
|
|
gvdbg("layer=%p, lid=%d, xpos=%d, ypos=%d, area=%p\n",
|
|
layer, lid, xpos, ypos, area);
|
|
|
|
putreg32(stm32_dma2d_memaddress(layer, xpos, ypos), stm32_mar_layer_t[lid]);
|
|
putreg32(stm32_dma2d_lineoffset(layer, area), stm32_or_layer_t[lid]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lcolor
|
|
*
|
|
* Description:
|
|
* Set the color for the layer
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_dma2d_lcolor(FAR const struct stm32_dma2d_s *layer,
|
|
int lid, uint32_t color)
|
|
{
|
|
gvdbg("layer=%p, lid=%d, color=%08x\n", layer, lid, color);
|
|
putreg32(color, stm32_color_layer_t[lid]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_llnr
|
|
*
|
|
* Description:
|
|
* Set the number of line register
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
* area - Reference to the area to copy
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_dma2d_llnr(FAR struct stm32_dma2d_s *layer,
|
|
FAR const struct ltdc_area_s *area)
|
|
{
|
|
uint32_t nlrreg;
|
|
|
|
gvdbg("pixel per line: %d, number of lines: %d\n", area->xres, area->yres);
|
|
|
|
nlrreg = getreg32(STM32_DMA2D_NLR);
|
|
nlrreg = (DMA2D_NLR_PL(area->xres)|DMA2D_NLR_NL(area->yres));
|
|
putreg32(nlrreg, STM32_DMA2D_NLR);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_loutpfc
|
|
*
|
|
* Description:
|
|
* Set the output PFC control register
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2d_loutpfc(FAR const struct stm32_dma2d_s *layer)
|
|
{
|
|
gvdbg("layer=%p\n", layer);
|
|
|
|
/* CLUT format isn't supported by the dma2d controller */
|
|
|
|
if (layer->fmt == DMA2D_PF_L8)
|
|
{
|
|
/* Destination layer doesn't support CLUT output */
|
|
|
|
gdbg("ERROR: Returning ENOSYS, "
|
|
"output to layer with CLUT format not supported.\n");
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/* Set the mapped pixel format of source layer */
|
|
|
|
putreg32(DMA2D_OPFCCR_CM(layer->fmt), STM32_DMA2D_OPFCCR);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2d_lpfc
|
|
*
|
|
* Description:
|
|
* Configure foreground and background layer PFC control register
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the common layer state structure
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void stm32_dma2d_lpfc(FAR const struct stm32_dma2d_s *layer,
|
|
int lid, uint32_t blendmode)
|
|
{
|
|
uint32_t pfccrreg;
|
|
|
|
gvdbg("layer=%p, lid=%d, blendmode=%08x\n", layer, lid, blendmode);
|
|
|
|
/* Set color format */
|
|
|
|
pfccrreg = DMA2D_xGPFCCR_CM(layer->fmt);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
if (layer->fmt == DMA2D_PF_L8)
|
|
{
|
|
/* Load CLUT automatically */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_START;
|
|
|
|
/* Set the CLUT color mode */
|
|
|
|
#ifndef CONFIG_FB_TRANSPARENCY
|
|
pfccrreg |= DMA2D_xGPFCCR_CCM;
|
|
#endif
|
|
|
|
/* Set CLUT size */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_CS(DMA2D_CLUT_SIZE);
|
|
|
|
/* Set the CLUT memory address */
|
|
|
|
putreg32((uint32_t) layer->clut, stm32_cmar_layer_t[lid]);
|
|
|
|
/* Start async clut loading */
|
|
|
|
stm32_dma2d_loadclut(stm32_pfccr_layer_t[lid]);
|
|
}
|
|
#endif
|
|
|
|
if (blendmode & DMA2D_BLEND_NONE)
|
|
{
|
|
/* No blend operation */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_AM(STM32_DMA2D_PFCCR_AM_NONE);
|
|
}
|
|
else
|
|
{
|
|
/* Set alpha value */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_ALPHA(layer->alpha);
|
|
|
|
/* Set alpha mode */
|
|
|
|
if (layer->blendmode & DMA2D_BLEND_ALPHA)
|
|
{
|
|
/* Blend with constant alpha */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_AM(STM32_DMA2D_PFCCR_AM_CONST);
|
|
}
|
|
else if (layer->blendmode & DMA2D_BLEND_PIXELALPHA)
|
|
{
|
|
/* Blend with pixel alpha value */
|
|
|
|
pfccrreg |= DMA2D_xGPFCCR_AM(STM32_DMA2D_PFCCR_AM_PIXEL);
|
|
}
|
|
}
|
|
|
|
putreg32(pfccrreg, stm32_pfccr_layer_t[lid]);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Public Functions
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dgetvideoinfo
|
|
*
|
|
* Description:
|
|
* Get video information about the layer
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer control structure
|
|
* vinfo - Reference to the video info structure
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dgetvideoinfo(FAR struct dma2d_layer_s *layer,
|
|
FAR struct fb_videoinfo_s *vinfo)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, vinfo=%p\n", layer, vinfo);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && vinfo)
|
|
{
|
|
sem_wait(priv->lock);
|
|
memcpy(vinfo, &priv->vinfo, sizeof(struct fb_videoinfo_s));
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dgetplaneinfo
|
|
*
|
|
* Description:
|
|
* Get plane information about the layer
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer control structure
|
|
* planeno - Number of the plane
|
|
* pinfo - Reference to the plane info structure
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dgetplaneinfo(FAR struct dma2d_layer_s *layer, int planeno,
|
|
FAR struct fb_planeinfo_s *pinfo)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, planeno=%d, pinfo=%p\n", layer, planeno, pinfo);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && pinfo && planeno == 0)
|
|
{
|
|
sem_wait(priv->lock);
|
|
memcpy(pinfo, &priv->pinfo, sizeof(struct fb_planeinfo_s));
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dgetlid
|
|
*
|
|
* Description:
|
|
* Get a specific layer identifier.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* lid - Reference to store the layer id
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dgetlid(FAR struct dma2d_layer_s *layer, int *lid)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, lid=%p\n", layer, lid);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && lid)
|
|
{
|
|
sem_wait(priv->lock);
|
|
*lid = priv->lid;
|
|
sem_post(priv->lock);
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dsetclut
|
|
*
|
|
* Description:
|
|
* Configure layer clut (color lookup table).
|
|
* Non clut is defined during initializing.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* cmap - color lookup table with up the 256 entries
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dsetclut(FAR struct dma2d_layer_s *layer,
|
|
const FAR struct fb_cmap_s *cmap)
|
|
{
|
|
int ret;
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, cmap=%p\n", layer, cmap);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && cmap)
|
|
{
|
|
sem_wait(priv->lock);
|
|
|
|
#ifdef CONFIG_STM32_LTDC_INTERFACE
|
|
if (priv->lid < DMA2D_SHADOW_LAYER)
|
|
{
|
|
/* Update the shared color lookup table.
|
|
*
|
|
* Background:
|
|
*
|
|
* We share the same memory region of the clut table with the LTDC
|
|
* driver. (see stm32_dma2dinitltdc). This is important because any
|
|
* changes to the framebuffer and color lookup table by the ltdc
|
|
* related dma2d layer should also effects to the ltdc visibility,
|
|
* except operation settings, alpha and blendmode.
|
|
*
|
|
* But we can not only update the clut memory region. The LTDC driver
|
|
* also must update they own LTDC clut register to make the changes
|
|
* visible. Using the LTDC interface to update the clut table will
|
|
* also update the clut table of the related dma2d layer.
|
|
*/
|
|
|
|
FAR struct ltdc_layer_s *ltdc =
|
|
g_ltdc_layer.layer[DMA2D_SHADOW_LAYER_L1].ltdc;
|
|
|
|
ret = ltdc->setclut(ltdc, cmap);
|
|
|
|
sem_post(priv->lock);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
if (priv->fmt != DMA2D_PF_L8)
|
|
{
|
|
gdbg("Error: CLUT is not supported for the pixel format: %d\n",
|
|
priv->vinfo.fmt);
|
|
ret = -EINVAL;
|
|
}
|
|
else if (cmap->first >= STM32_DMA2D_NCLUT)
|
|
{
|
|
gdbg("Error: only %d color table entries supported\n",
|
|
STM32_DMA2D_NCLUT);
|
|
ret = -EINVAL;
|
|
}
|
|
else
|
|
{
|
|
uint32_t *clut;
|
|
int n;
|
|
|
|
clut = priv->clut;
|
|
|
|
for (n = cmap->first; n < cmap->len && n < STM32_DMA2D_NCLUT; n++)
|
|
{
|
|
/* Update the layer clut entry */
|
|
|
|
#ifndef CONFIG_FB_TRANSPARENCY
|
|
uint8_t *clut888 = (uint8_t*)clut;
|
|
uint16_t offset = 3 * n;
|
|
|
|
clut888[offset] = cmap->blue[n];
|
|
clut888[offset + 1] = cmap->green[n];
|
|
clut888[offset + 2] = cmap->red[n];
|
|
|
|
regvdbg("n=%d, red=%02x, green=%02x, blue=%02x\n", n,
|
|
clut888[offset], clut888[offset + 1],
|
|
clut888[offset + 2]);
|
|
#else
|
|
clut[n] = (uint32_t)DMA2D_CLUT_RED(cmap->transp[n]) |
|
|
(uint32_t)DMA2D_CLUT_GREEN(cmap->red[n]) |
|
|
(uint32_t)DMA2D_CLUT_GREEN(cmap->green[n]) |
|
|
(uint32_t)DMA2D_CLUT_BLUE(cmap->blue[n]);
|
|
|
|
regvdbg("n=%d, alpha=%02x, red=%02x, green=%02x, blue=%02x\n", n,
|
|
DMA2D_CLUT_ALPHA(cmap->alpha[n]),
|
|
DMA2D_CLUT_RED(cmap->red[n]),
|
|
DMA2D_CLUT_GREEN(cmap->green[n]),
|
|
DMA2D_CLUT_BLUE(cmap->blue[n]));
|
|
#endif
|
|
}
|
|
|
|
|
|
ret = OK;
|
|
}
|
|
|
|
sem_post(priv->lock);
|
|
return ret;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dgetclut
|
|
*
|
|
* Description:
|
|
* Get configured layer clut (color lookup table).
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* cmap - Reference to valid color lookup table accept up the 256 color
|
|
* entries
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dgetclut(FAR struct dma2d_layer_s *layer,
|
|
FAR struct fb_cmap_s *cmap)
|
|
{
|
|
int ret;
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, cmap=%p\n", layer, cmap);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && cmap)
|
|
{
|
|
sem_wait(priv->lock);
|
|
|
|
if (priv->fmt != DMA2D_PF_L8)
|
|
{
|
|
gdbg("Error: CLUT is not supported for the pixel format: %d\n",
|
|
priv->vinfo.fmt);
|
|
ret = -EINVAL;
|
|
}
|
|
else if (cmap->first >= STM32_DMA2D_NCLUT)
|
|
{
|
|
gdbg("Error: only %d color table entries supported\n",
|
|
STM32_DMA2D_NCLUT);
|
|
ret = -EINVAL;
|
|
}
|
|
else
|
|
{
|
|
/* Copy from the layer clut */
|
|
|
|
uint32_t *clut;
|
|
int n;
|
|
|
|
clut = priv->clut;
|
|
|
|
for (n = cmap->first; n < cmap->len && n < STM32_DMA2D_NCLUT; n++)
|
|
{
|
|
#ifndef CONFIG_FB_TRANSPARENCY
|
|
uint8_t *clut888 = (uint8_t*)clut;
|
|
uint16_t offset = 3 * n;
|
|
|
|
cmap->blue[n] = clut888[offset];
|
|
cmap->green[n] = clut888[offset + 1];
|
|
cmap->red[n] = clut888[offset + 2];
|
|
|
|
regvdbg("n=%d, red=%02x, green=%02x, blue=%02x\n", n,
|
|
clut888[offset], clut888[offset + 1],
|
|
clut888[offset + 2]);
|
|
#else
|
|
cmap->transp[n] = (uint8_t)DMA2D_CMAP_ALPHA(clut[n]);
|
|
cmap->red[n] = (uint8_t)DMA2D_CMAP_RED(clut[n]);
|
|
cmap->green[n] = (uint8_t)DMA2D_CMAP_GREEN(clut[n]);
|
|
cmap->blue[n] = (uint8_t)DMA2D_CMAP_BLUE(clut[n]);
|
|
|
|
regvdbg("n=%d, alpha=%02x, red=%02x, green=%02x, blue=%02x\n", n,
|
|
DMA2D_CMAP_ALPHA(clut[n]), DMA2D_CMAP_RED(clut[n]),
|
|
DMA2D_CMAP_GREEN(clut[n]), DMA2D_CMAP_BLUE(clut[n]));
|
|
#endif
|
|
}
|
|
|
|
ret = OK;
|
|
}
|
|
|
|
sem_post(priv->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dsetalpha
|
|
*
|
|
* Description:
|
|
* Configure layer alpha value factor into blend operation.
|
|
* During the layer blend operation the source alpha value is multiplied
|
|
* with this alpha value. If the source color format doesn't support alpha
|
|
* channel (e.g. non ARGB8888) this alpha value will be used as constant
|
|
* alpha value for blend operation.
|
|
* Default value during initializing: 0xff
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* alpha - Alpha value
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dsetalpha(FAR struct dma2d_layer_s *layer, uint8_t alpha)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, alpha=%02x\n", layer, alpha);
|
|
|
|
if (stm32_dma2d_lvalidate(priv))
|
|
{
|
|
sem_wait(priv->lock);
|
|
priv->alpha = alpha;
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dgetalpha
|
|
*
|
|
* Description:
|
|
* Get configured layer alpha value factor for blend operation.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* alpha - Reference to store the alpha value
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static int stm32_dma2dgetalpha(FAR struct dma2d_layer_s *layer, uint8_t *alpha)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, alpha=%p\n", layer, alpha);
|
|
|
|
if (stm32_dma2d_lvalidate(priv))
|
|
{
|
|
sem_wait(priv->lock);
|
|
*alpha = priv->alpha;
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dsetblendmode
|
|
*
|
|
* Description:
|
|
* Configure blend mode of the layer.
|
|
* Default mode during initializing: DMA2D_BLEND_NONE
|
|
* Blendmode is active after next update.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* mode - Blend mode (see DMA2D_BLEND_*)
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
* Procedure information:
|
|
* DMA2D_BLEND_NONE:
|
|
* Informs the driver to disable all blend operation for the given layer.
|
|
* That means the layer is opaque.
|
|
*
|
|
* DMA2D_BLEND_ALPHA:
|
|
* Informs the driver to enable alpha blending for the given layer.
|
|
*
|
|
* DMA2D_BLEND_PIXELALPHA:
|
|
* Informs the driver to use the pixel alpha value of the layer instead
|
|
* the constant alpha value. This is only useful for ARGB8888
|
|
* color format.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static int stm32_dma2dsetblendmode(FAR struct dma2d_layer_s *layer,
|
|
uint32_t mode)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, mode=%08x\n", layer, mode);
|
|
|
|
if (stm32_dma2d_lvalidate(priv))
|
|
{
|
|
sem_wait(priv->lock);
|
|
priv->blendmode = mode;
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_getblendmode
|
|
*
|
|
* Description:
|
|
* Get configured blend mode of the layer.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* mode - Reference to store the blend mode
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static int stm32_dma2dgetblendmode(FAR struct dma2d_layer_s *layer,
|
|
uint32_t *mode)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, mode=%p\n", layer, mode);
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && mode)
|
|
{
|
|
sem_wait(priv->lock);
|
|
*mode = priv->blendmode;
|
|
sem_post(priv->lock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dblit
|
|
*
|
|
* Description:
|
|
* Copy selected area from a source layer to selected position of the
|
|
* destination layer.
|
|
*
|
|
* Parameter:
|
|
* dest - Valid reference to the destination layer
|
|
* destxpos - Valid selected x position of the destination layer
|
|
* destypos - Valid selected y position of the destination layer
|
|
* src - Valid reference to the source layer
|
|
* srcarea - Valid reference to the selected area of the source layer
|
|
*
|
|
* Return:
|
|
* OK - On success
|
|
* -EINVAL - If one of the parameter invalid or if the size of the selected
|
|
* source area outside the visible area of the destination layer.
|
|
* (The visible area usually represents the display size)
|
|
* -ECANCELED - Operation cancelled, something goes wrong.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2dblit(FAR struct dma2d_layer_s *dest,
|
|
fb_coord_t destxpos, fb_coord_t destypos,
|
|
FAR const struct dma2d_layer_s *src,
|
|
FAR const struct ltdc_area_s *srcarea)
|
|
{
|
|
uint32_t mode;
|
|
int ret;
|
|
FAR struct stm32_dma2d_s * destlayer = (FAR struct stm32_dma2d_s *)dest;
|
|
FAR struct stm32_dma2d_s * srclayer = (FAR struct stm32_dma2d_s *)src;
|
|
|
|
gvdbg("dest=%p, destxpos=%d, destypos=%d, src=%p, srcarea=%p\n",
|
|
dest, destxpos, destypos, src, srcarea);
|
|
|
|
if (stm32_dma2d_lvalidatesize(destlayer, destxpos, destypos, srcarea) &&
|
|
stm32_dma2d_lvalidatesize(srclayer, srcarea->xpos,
|
|
srcarea->ypos, srcarea))
|
|
{
|
|
sem_wait(destlayer->lock);
|
|
|
|
/* Set output pfc */
|
|
|
|
ret = stm32_dma2d_loutpfc(destlayer);
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Set foreground pfc */
|
|
|
|
stm32_dma2d_lpfc(srclayer, DMA2D_LAYER_LFORE, DMA2D_BLEND_NONE);
|
|
|
|
/* Set foreground fifo */
|
|
|
|
stm32_dma2d_lfifo(srclayer, DMA2D_LAYER_LFORE,
|
|
srcarea->xpos, srcarea->ypos, srcarea);
|
|
|
|
/* Set output fifo */
|
|
|
|
stm32_dma2d_lfifo(destlayer, DMA2D_LAYER_LOUT,
|
|
destxpos, destypos, srcarea);
|
|
|
|
/* Set number of lines and pixel per line */
|
|
|
|
stm32_dma2d_llnr(destlayer, srcarea);
|
|
|
|
/* Set dma2d mode for blit operation */
|
|
|
|
if (destlayer->fmt == srclayer->fmt)
|
|
{
|
|
/* Blit without pfc */
|
|
|
|
mode = STM32_DMA2D_CR_MODE_BLIT;
|
|
}
|
|
else
|
|
{
|
|
/* Blit with pfc */
|
|
|
|
mode = STM32_DMA2D_CR_MODE_BLITPFC;
|
|
}
|
|
|
|
stm32_dma2d_control(mode, STM32_DMA2D_CR_MODE_CLEAR);
|
|
|
|
/* Start DMA2D and wait until completed */
|
|
|
|
ret = stm32_dma2d_start();
|
|
|
|
if (ret != OK)
|
|
{
|
|
ret = -ECANCELED;
|
|
gdbg("ERROR: Returning ECANCELED\n");
|
|
}
|
|
}
|
|
|
|
sem_post(destlayer->lock);
|
|
}
|
|
else
|
|
{
|
|
ret = -EINVAL;
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_dma2dblend
|
|
*
|
|
* Description:
|
|
* Blends the selected area from a background layer with selected position
|
|
* of the foreground layer. Copies the result to the selected position of
|
|
* the destination layer. Note! The content of the foreground and background
|
|
* layer keeps unchanged as long destination layer is unequal to the
|
|
* foreground and background layer.
|
|
*
|
|
* Parameter:
|
|
* dest - Reference to the destination layer
|
|
* fore - Reference to the foreground layer
|
|
* forexpos - Selected x target position of the foreground layer
|
|
* foreypos - Selected y target position of the foreground layer
|
|
* back - Reference to the background layer
|
|
* backarea - Reference to the selected area of the background layer
|
|
*
|
|
* Return:
|
|
* OK - On success
|
|
* -EINVAL - If one of the parameter invalid or if the size of the selected
|
|
* source area outside the visible area of the destination layer.
|
|
* (The visible area usually represents the display size)
|
|
* -ECANCELED - Operation cancelled, something goes wrong.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2dblend(FAR struct dma2d_layer_s *dest,
|
|
fb_coord_t destxpos, fb_coord_t destypos,
|
|
FAR const struct dma2d_layer_s *fore,
|
|
fb_coord_t forexpos, fb_coord_t foreypos,
|
|
FAR const struct dma2d_layer_s *back,
|
|
FAR const struct ltdc_area_s *backarea)
|
|
{
|
|
int ret;
|
|
FAR struct stm32_dma2d_s * destlayer = (FAR struct stm32_dma2d_s *)dest;
|
|
FAR struct stm32_dma2d_s * forelayer = (FAR struct stm32_dma2d_s *)fore;
|
|
FAR struct stm32_dma2d_s * backlayer = (FAR struct stm32_dma2d_s *)back;
|
|
|
|
gvdbg("dest=%p, destxpos=%d, destypos=%d, "
|
|
"fore=%p, forexpos=%d, foreypos=%d, "
|
|
"back=%p, backarea=%p\n",
|
|
dest, destxpos, destypos, fore, forexpos, foreypos, back, backarea);
|
|
|
|
if (stm32_dma2d_lvalidatesize(destlayer, destxpos, destypos, backarea) &&
|
|
stm32_dma2d_lvalidatesize(forelayer, forexpos, foreypos, backarea) &&
|
|
stm32_dma2d_lvalidatesize(backlayer, backarea->xpos,
|
|
backarea->ypos, backarea))
|
|
{
|
|
|
|
sem_wait(destlayer->lock);
|
|
|
|
/* Set output pfc */
|
|
|
|
ret = stm32_dma2d_loutpfc(destlayer);
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Set background pfc */
|
|
|
|
stm32_dma2d_lpfc(backlayer, DMA2D_LAYER_LBACK, backlayer->blendmode);
|
|
|
|
/* Set foreground pfc */
|
|
|
|
stm32_dma2d_lpfc(forelayer, DMA2D_LAYER_LFORE, forelayer->blendmode);
|
|
|
|
/* Set background fifo */
|
|
|
|
stm32_dma2d_lfifo(backlayer, DMA2D_LAYER_LBACK,
|
|
backarea->xpos, backarea->ypos, backarea);
|
|
|
|
/* Set foreground fifo */
|
|
|
|
stm32_dma2d_lfifo(forelayer, DMA2D_LAYER_LFORE,
|
|
forexpos, foreypos, backarea);
|
|
|
|
/* Set output fifo */
|
|
|
|
stm32_dma2d_lfifo(destlayer, DMA2D_LAYER_LOUT,
|
|
destxpos, destypos, backarea);
|
|
|
|
/* Set number of lines and pixel per line */
|
|
|
|
stm32_dma2d_llnr(destlayer, backarea);
|
|
|
|
/* Set watermark */
|
|
|
|
/* Enable DMA2D blender */
|
|
|
|
stm32_dma2d_control(STM32_DMA2D_CR_MODE_BLEND,
|
|
STM32_DMA2D_CR_MODE_CLEAR);
|
|
|
|
/* Start DMA2D and wait until completed */
|
|
|
|
ret = stm32_dma2d_start();
|
|
|
|
if (ret != OK)
|
|
{
|
|
ret = -ECANCELED;
|
|
gdbg("ERROR: Returning ECANCELED\n");
|
|
}
|
|
}
|
|
|
|
sem_post(destlayer->lock);
|
|
}
|
|
else
|
|
{
|
|
ret = -EINVAL;
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stm32_dma2dfillarea
|
|
*
|
|
* Description:
|
|
* Fill the selected area of the whole layer with a specific color.
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer structure
|
|
* area - Reference to the valid area structure select the area
|
|
* color - Color to fill the selected area. Color must be formatted
|
|
* according to the layer pixel format.
|
|
*
|
|
* Return:
|
|
* OK - On success
|
|
* -EINVAL - If one of the parameter invalid or if the size of the selected
|
|
* area outside the visible area of the layer.
|
|
* -ECANCELED - Operation cancelled, something goes wrong.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stm32_dma2dfillarea(FAR struct dma2d_layer_s *layer,
|
|
FAR const struct ltdc_area_s *area,
|
|
uint32_t color)
|
|
{
|
|
int ret;
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
gvdbg("layer=%p, area=%p, color=%08x\n", layer, area, color);
|
|
|
|
if (stm32_dma2d_lvalidatesize(priv, area->xpos, area->ypos, area))
|
|
{
|
|
|
|
sem_wait(priv->lock);
|
|
|
|
/* Set output pfc */
|
|
|
|
ret = stm32_dma2d_loutpfc(priv);
|
|
|
|
if (ret == OK)
|
|
{
|
|
/* Set output fifo */
|
|
|
|
stm32_dma2d_lfifo(priv, DMA2D_LAYER_LOUT,
|
|
area->xpos, area->ypos, area);
|
|
|
|
/* Set the output color register */
|
|
|
|
stm32_dma2d_lcolor(priv, DMA2D_LAYER_LOUT, color);
|
|
|
|
/* Set number of lines and pixel per line */
|
|
|
|
stm32_dma2d_llnr(priv, area);
|
|
|
|
/* Set register to memory transfer */
|
|
|
|
stm32_dma2d_control(STM32_DMA2D_CR_MODE_COLOR,
|
|
STM32_DMA2D_CR_MODE_CLEAR);
|
|
|
|
/* Start DMA2D and wait until completed */
|
|
|
|
ret = stm32_dma2d_start();
|
|
|
|
if (ret != OK)
|
|
{
|
|
ret = -ECANCELED;
|
|
gdbg("ERROR: Returning ECANCELED\n");
|
|
}
|
|
}
|
|
|
|
sem_post(priv->lock);
|
|
}
|
|
else
|
|
{
|
|
ret = -EINVAL;
|
|
gdbg("ERROR: Returning EINVAL\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Name: up_dma2dgetlayer
|
|
*
|
|
* Description:
|
|
* Get a dma2d layer structure by the layer identifier
|
|
*
|
|
* Parameter:
|
|
* lid - Layer identifier
|
|
*
|
|
* Return:
|
|
* Reference to the dma2d layer control structure on success or Null if no
|
|
* related exist.
|
|
*
|
|
******************************************************************************/
|
|
|
|
FAR struct dma2d_layer_s * up_dma2dgetlayer(int lid)
|
|
{
|
|
if (lid < DMA2D_LAYER_NSIZE)
|
|
{
|
|
FAR struct stm32_dma2d_s *priv;
|
|
sem_wait(&g_lock);
|
|
priv = g_layers[lid];
|
|
sem_post(&g_lock);
|
|
|
|
return &priv->dma2d;
|
|
}
|
|
|
|
gdbg("ERROR: EINVAL, Unknown layer identifier\n");
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: up_dma2dcreatelayer
|
|
*
|
|
* Description:
|
|
* Create a new dma2d layer object to interact with the dma2d controller
|
|
*
|
|
* Parameter:
|
|
* width - Layer width
|
|
* height - Layer height
|
|
* fmt - Pixel format of the layer
|
|
*
|
|
* Return:
|
|
* On success - A valid dma2d layer reference
|
|
* On error - NULL and errno is set to
|
|
* -EINVAL if one of the parameter is invalid
|
|
* -ENOMEM if no memory available or exceeds
|
|
* CONFIG_STM32_DMA2D_NLAYERS
|
|
*
|
|
******************************************************************************/
|
|
|
|
FAR struct dma2d_layer_s *up_dma2dcreatelayer(fb_coord_t width,
|
|
fb_coord_t height,
|
|
uint8_t fmt)
|
|
{
|
|
int ret;
|
|
int lid;
|
|
uint8_t fmtmap;
|
|
uint8_t bpp = 0;
|
|
FAR struct stm32_dma2d_s *layer = NULL;
|
|
|
|
gvdbg("width=%d, height=%d, fmt=%02x \n", width, height, fmt);
|
|
|
|
/* Validate if pixel format supported */
|
|
|
|
ret = stm32_dma2d_pixelformat(fmt, &fmtmap);
|
|
|
|
if (ret != OK)
|
|
{
|
|
errno = ret;
|
|
return NULL;
|
|
}
|
|
|
|
ret = stm32_dma2d_bpp(fmt, &bpp);
|
|
|
|
sem_wait(&g_lock);
|
|
|
|
/* Get a free layer identifier */
|
|
|
|
lid = stm32_dma2d_lfreelid();
|
|
|
|
if (lid >= 0)
|
|
{
|
|
layer = stm32_dma2d_lalloc();
|
|
|
|
if (layer)
|
|
{
|
|
uint32_t fblen;
|
|
void *fbmem;
|
|
fb_coord_t stride;
|
|
|
|
/* Stride calculation for the supported formats */
|
|
|
|
stride = width * bpp / 8;
|
|
|
|
/* Calculate buffer size */
|
|
|
|
fblen = stride * height;
|
|
|
|
/* Allocate 32-bit aligned memory for the layer buffer. As reported in
|
|
* mm_memalign 8-byte alignment is guaranteed by normal malloc calls.
|
|
* We have also ensure memory is allocated from the SRAM1/2/3 block.
|
|
* The CCM block is only accessible through the D-BUS but not by
|
|
* the AHB-BUS. Ensure that CONFIG_STM32_CCMEXCLUDE is set!
|
|
*/
|
|
|
|
fbmem = kmm_zalloc(fblen);
|
|
|
|
if (fbmem)
|
|
{
|
|
FAR struct fb_videoinfo_s *vinfo = &layer->vinfo;
|
|
FAR struct fb_planeinfo_s *pinfo = &layer->pinfo;
|
|
|
|
/* Initialize dma2d structure */
|
|
|
|
stm32_dma2d_linit(layer, lid, fmtmap);
|
|
|
|
/* Initialize the videoinfo structure */
|
|
|
|
vinfo->fmt = fmt;
|
|
vinfo->xres = width;
|
|
vinfo->yres = height;
|
|
vinfo->nplanes = 1;
|
|
|
|
/* Initialize the planeinfo structure */
|
|
|
|
pinfo->fbmem = fbmem;
|
|
pinfo->fblen = fblen;
|
|
pinfo->stride = stride;
|
|
pinfo->bpp = bpp;
|
|
|
|
/* Bind the layer to the identifier */
|
|
|
|
g_layers[lid] = layer;
|
|
}
|
|
else
|
|
{
|
|
/* free the layer struture */
|
|
|
|
kmm_free(layer);
|
|
gdbg("ERROR: ENOMEM, Unable to allocate layer buffer\n");
|
|
errno = ENOMEM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gdbg("ERROR: ENOMEM, unable to allocate layer structure\n");
|
|
errno = ENOMEM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gdbg("ERROR: EINVAL, no free layer available\n");
|
|
errno = EINVAL;
|
|
}
|
|
|
|
sem_post(&g_lock);
|
|
return (FAR struct dma2d_layer_s *)layer;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: up_dma2dremovelayer
|
|
*
|
|
* Description:
|
|
* Remove and deallocate the dma2d layer
|
|
*
|
|
* Parameter:
|
|
* layer - Reference to the layer to remove
|
|
*
|
|
* Return:
|
|
* On success - OK
|
|
* On error - -EINVAL
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int up_dma2dremovelayer(FAR struct dma2d_layer_s *layer)
|
|
{
|
|
int ret = -EINVAL;
|
|
FAR struct stm32_dma2d_s *priv = (FAR struct stm32_dma2d_s *)layer;
|
|
|
|
/* Check if the layer is valid and unlike a ltdc related layer */
|
|
|
|
if (stm32_dma2d_lvalidate(priv) && priv->lid >= DMA2D_SHADOW_LAYER)
|
|
{
|
|
sem_wait(priv->lock);
|
|
|
|
/* Check also if the layer id is valid to the layer reference */
|
|
|
|
if (priv == g_layers[priv->lid])
|
|
{
|
|
int lid = priv->lid;
|
|
|
|
kmm_free(priv->pinfo.fbmem);
|
|
stm32_dma2d_lfree(priv);
|
|
|
|
g_layers[lid] = NULL;
|
|
ret = OK;
|
|
}
|
|
|
|
sem_post(priv->lock);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: up_dma2dinitialize
|
|
*
|
|
* Description:
|
|
* Initialize the dma2d controller
|
|
*
|
|
* Return:
|
|
* OK - On success
|
|
* An error if initializing failed.
|
|
*
|
|
******************************************************************************/
|
|
|
|
int up_dma2dinitialize(void)
|
|
{
|
|
dbg("Initialize DMA2D driver\n");
|
|
|
|
if (g_initialized == false)
|
|
{
|
|
/* Abort current dma2d data transfer */
|
|
|
|
up_dma2duninitialize();
|
|
|
|
/* Enable dma2d is done in rcc_enableahb1, see
|
|
* arch/arm/src/stm32/stm32f40xxx_rcc.c
|
|
*/
|
|
|
|
/* Initialize the DMA2D semaphore that enforces mutually exclusive access
|
|
* to the driver
|
|
*/
|
|
|
|
sem_init(&g_lock, 0, 1);
|
|
|
|
/* Initialize the semaphore for interrupt handling */
|
|
|
|
sem_init(g_interrupt.sem, 0, 0);
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
/* Enable dma2d transfer and clut loading interrupts only */
|
|
|
|
stm32_dma2d_control(DMA2D_CR_TCIE|DMA2D_CR_CTCIE, DMA2D_CR_TEIE|
|
|
DMA2D_CR_TWIE|DMA2D_CR_CAEIE||DMA2D_CR_CEIE);
|
|
#else
|
|
/* Enable dma transfer interrupt only */
|
|
|
|
stm32_dma2d_control(DMA2D_CR_TCIE, DMA2D_CR_TEIE|DMA2D_CR_TWIE|
|
|
DMA2D_CR_CAEIE|DMA2D_CR_CTCIE|DMA2D_CR_CEIE);
|
|
#endif
|
|
|
|
/* Attach DMA2D interrupt vector */
|
|
|
|
(void)irq_attach(g_interrupt.irq, stm32_dma2dirq);
|
|
|
|
/* Enable the IRQ at the NVIC */
|
|
|
|
up_enable_irq(g_interrupt.irq);
|
|
|
|
/* Initialize the dma2d layer for ltdc binding */
|
|
|
|
#ifdef DMA2D_SHADOW_LAYER_L1
|
|
g_layers[DMA2D_SHADOW_LAYER_L1] =
|
|
&g_ltdc_layer.layer[DMA2D_SHADOW_LAYER_L1].dma2ddev;
|
|
#endif
|
|
#ifdef DMA2D_SHADOW_LAYER_L2
|
|
g_layers[DMA2D_SHADOW_LAYER_L2] =
|
|
&g_ltdc_layer.layer[DMA2D_SHADOW_LAYER_L2].dma2ddev;
|
|
#endif
|
|
/* Set initialized state */
|
|
|
|
g_initialized = true;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Name: up_dma2duninitialize
|
|
*
|
|
* Description:
|
|
* Uninitialize the dma2d controller
|
|
*
|
|
******************************************************************************/
|
|
|
|
void up_dma2duninitialize(void)
|
|
{
|
|
/* Disable DMA2D interrupts */
|
|
|
|
up_disable_irq(g_interrupt.irq);
|
|
irq_detach(g_interrupt.irq);
|
|
|
|
/* Cleanup all layers */
|
|
|
|
stm32_dma2d_llayerscleanup();
|
|
|
|
/* Abort current dma2d transfer */
|
|
|
|
stm32_dma2d_control(DMA2D_CR_ABORT, 0);
|
|
|
|
/* Set initialized state */
|
|
|
|
g_initialized = false;
|
|
}
|
|
|
|
#ifdef CONFIG_STM32_LTDC_INTERFACE
|
|
/******************************************************************************
|
|
* Name: stm32_dma2dinitltdc
|
|
*
|
|
* Description:
|
|
* Get a reference to the dma2d layer coupled with the ltdc layer.
|
|
* It not intends to use this by user space applications.
|
|
* It resolves the following requirements:
|
|
* 1. Share the color lookup table
|
|
* 2. Share the planeinfo information
|
|
* 3. Share the videoinfo information
|
|
*
|
|
* Parameter:
|
|
* layer - a valid reference to the low level ltdc layer structure
|
|
* clut - a pointer to a valid memory region to hold 256 clut colors
|
|
*
|
|
* Return:
|
|
* On success - A valid dma2d layer reference
|
|
* On error - NULL and errno is set to
|
|
* -EINVAL if one of the parameter is invalid
|
|
*
|
|
******************************************************************************/
|
|
|
|
FAR struct dma2d_layer_s * stm32_dma2dinitltdc(FAR struct stm32_ltdc_s *layer)
|
|
{
|
|
int ret;
|
|
uint8_t fmt = 0;
|
|
FAR struct stm32_ltdc_dma2d_s *priv;
|
|
|
|
gvdbg("layer=%p\n", layer);
|
|
DEBUGASSERT(layer && layer->lid >= 0 && layer->lid < DMA2D_SHADOW_LAYER);
|
|
|
|
ret = stm32_dma2d_pixelformat(layer->vinfo.fmt, &fmt);
|
|
|
|
if (ret != OK)
|
|
{
|
|
dbg("Returning -EINVAL, unsupported pixel format: %d\n",
|
|
layer->vinfo.fmt);
|
|
errno = -EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
priv = &g_ltdc_layer.layer[layer->lid];
|
|
|
|
stm32_dma2d_linit(&priv->dma2ddev, layer->lid, fmt);
|
|
|
|
memcpy(&priv->dma2ddev.vinfo, &layer->vinfo, sizeof(struct fb_videoinfo_s));
|
|
memcpy(&priv->dma2ddev.pinfo, &layer->pinfo, sizeof(struct fb_planeinfo_s));
|
|
|
|
#ifdef CONFIG_STM32_DMA2D_L8
|
|
/* Verifies that the ltdc layer has a clut. This ensures that DMA2D driver can
|
|
* support clut format but the LTDC driver does not and vice versa.
|
|
*/
|
|
|
|
if (layer->vinfo.fmt == FB_FMT_RGB8)
|
|
{
|
|
priv->dma2ddev.clut = layer->clut;
|
|
priv->ltdc = stm32_ltdcgetlayer(layer->lid);
|
|
DEBUGASSERT(priv->ltdc != NULL);
|
|
}
|
|
#endif
|
|
|
|
return &priv->dma2ddev.dma2d;
|
|
}
|
|
#endif /* CONFIG_STM32_LTDC_INTERFACE */
|