diff --git a/arch/arm/src/stm32f7/chip/stm32_dma2d.h b/arch/arm/src/stm32f7/chip/stm32_dma2d.h new file mode 100755 index 00000000000..7a44561a1db --- /dev/null +++ b/arch/arm/src/stm32f7/chip/stm32_dma2d.h @@ -0,0 +1,230 @@ +/**************************************************************************** + * arch/arm/src/stm32/chip/stm32_dma2d.h + * + * Copyright (C) 2014-2015 Marco Krahl. All rights reserved. + * Author: Marco Krahl + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_CHIP_STM32_DMA2D_H +#define __ARCH_ARM_SRC_STM32_CHIP_STM32_DMA2D_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip/stm32_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STM32_DMA2D_NCLUT 256 /* Number of entries in the CLUT */ + +/* DMA2D Register Offsets ****************************************************/ + +#define STM32_DMA2D_CR_OFFSET 0x0000 /* DMA2D Control Register */ +#define STM32_DMA2D_ISR_OFFSET 0x0004 /* DMA2D Interrupt Status Register */ +#define STM32_DMA2D_IFCR_OFFSET 0x0008 /* DMA2D Interrupt Flag Clear Register */ +#define STM32_DMA2D_FGMAR_OFFSET 0x000C /* DMA2D Foreground Memory Address Register */ +#define STM32_DMA2D_FGOR_OFFSET 0x0010 /* DMA2D Foreground Offset Register */ +#define STM32_DMA2D_BGMAR_OFFSET 0x0014 /* DMA2D Background Memory Address Register */ +#define STM32_DMA2D_BGOR_OFFSET 0x0018 /* DMA2D Background Offset Register */ +#define STM32_DMA2D_FGPFCCR_OFFSET 0x001C /* DMA2D Foreground PFC Control Register */ +#define STM32_DMA2D_FGCOLR_OFFSET 0x0020 /* DMA2D Foreground Color Register */ +#define STM32_DMA2D_BGPFCCR_OFFSET 0x0024 /* DMA2D Background PFC Control Register */ +#define STM32_DMA2D_BGCOLR_OFFSET 0x0028 /* DMA2D Background Color Register */ +#define STM32_DMA2D_FGCMAR_OFFSET 0x002C /* DMA2D Foreground CLUT Memory Address Register */ +#define STM32_DMA2D_BGCMAR_OFFSET 0x0030 /* DMA2D Background CLUT Memory Address Register */ +#define STM32_DMA2D_OPFCCR_OFFSET 0x0034 /* DMA2D Output PFC Control Register */ +#define STM32_DMA2D_OCOLR_OFFSET 0x0038 /* DMA2D Output Color Register */ +#define STM32_DMA2D_OMAR_OFFSET 0x003C /* DMA2D Output Memory Address Register */ +#define STM32_DMA2D_OOR_OFFSET 0x0040 /* DMA2D Output Offset Register */ +#define STM32_DMA2D_NLR_OFFSET 0x0044 /* DMA2D Number Of Line Register */ +#define STM32_DMA2D_LWR_OFFSET 0x0048 /* DMA2D Line Watermark Register */ +#define STM32_DMA2D_AMTCR_OFFSET 0x004C /* DMA2D AHB Master Time Configuration Register */ + +/* DMA2D Register Addresses **************************************************/ + +#define STM32_DMA2D_CR (STM32_DMA2D_BASE+STM32_DMA2D_CR_OFFSET) +#define STM32_DMA2D_ISR (STM32_DMA2D_BASE+STM32_DMA2D_ISR_OFFSET) +#define STM32_DMA2D_IFCR (STM32_DMA2D_BASE+STM32_DMA2D_IFCR_OFFSET) +#define STM32_DMA2D_FGMAR (STM32_DMA2D_BASE+STM32_DMA2D_FGMAR_OFFSET) +#define STM32_DMA2D_FGOR (STM32_DMA2D_BASE+STM32_DMA2D_FGOR_OFFSET) +#define STM32_DMA2D_BGMAR (STM32_DMA2D_BASE+STM32_DMA2D_BGMAR_OFFSET) +#define STM32_DMA2D_BGOR (STM32_DMA2D_BASE+STM32_DMA2D_BGOR_OFFSET) +#define STM32_DMA2D_FGPFCCR (STM32_DMA2D_BASE+STM32_DMA2D_FGPFCCR_OFFSET) +#define STM32_DMA2D_FGCOLR (STM32_DMA2D_BASE+STM32_DMA2D_FGCOLR_OFFSET) +#define STM32_DMA2D_BGPFCCR (STM32_DMA2D_BASE+STM32_DMA2D_BGPFCCR_OFFSET) +#define STM32_DMA2D_BGCOLR (STM32_DMA2D_BASE+STM32_DMA2D_BGCOLR_OFFSET) +#define STM32_DMA2D_FGCMAR (STM32_DMA2D_BASE+STM32_DMA2D_FGCMAR_OFFSET) +#define STM32_DMA2D_BGCMAR (STM32_DMA2D_BASE+STM32_DMA2D_BGCMAR_OFFSET) +#define STM32_DMA2D_OPFCCR (STM32_DMA2D_BASE+STM32_DMA2D_OPFCCR_OFFSET) +#define STM32_DMA2D_OCOLR (STM32_DMA2D_BASE+STM32_DMA2D_OCOLR_OFFSET) +#define STM32_DMA2D_OMAR (STM32_DMA2D_BASE+STM32_DMA2D_OMAR_OFFSET) +#define STM32_DMA2D_OOR (STM32_DMA2D_BASE+STM32_DMA2D_OOR_OFFSET) +#define STM32_DMA2D_NLR (STM32_DMA2D_BASE+STM32_DMA2D_NLR_OFFSET) +#define STM32_DMA2D_LWR (STM32_DMA2D_BASE+STM32_DMA2D_LWR_OFFSET) + +/* DMA2D Register Bit Definitions ********************************************/ + +/* DMA2D Control Register */ + +#define DMA2D_CR_START (1 << 0) /* Start Bit */ +#define DMA2D_CR_SUSP (1 << 1) /* Suspend Bit */ +#define DMA2D_CR_ABORT (1 << 2) /* Abort Bit */ +#define DMA2D_CR_TEIE (1 << 8) /* Transfer Error Interupt Enable Bit */ +#define DMA2D_CR_TCIE (1 << 9) /* Transfer Complete Interrupt Enable Bit */ +#define DMA2D_CR_TWIE (1 << 10) /* Transfer Watermark Interrupt Enable Bit */ +#define DMA2D_CR_CAEIE (1 << 11) /* CLUT Access Error Interrupt Enable Bit */ +#define DMA2D_CR_CTCIE (1 << 12) /* CLUT Transfer Complete Interrupt Enable Bit */ +#define DMA2D_CR_CEIE (1 << 13) /* Configuration Error Interrupt Enable Bit */ +#define DMA2D_CR_MODE_SHIFT (16) /* Bits 16-17 DMA2D mode Bits */ +#define DMA2D_CR_MODE_MASK (3 << DMA2D_CR_MODE_SHIFT) +#define DMA2D_CR_MODE(n) ((uint32_t)(n) << DMA2D_CR_MODE_SHIFT) + +/* DMA2D Interrupt Status Register */ + +#define DMA2D_ISR_TEIF (1 << 0) /* Transfer error interrupt flag */ +#define DMA2D_ISR_TCIF (1 << 1) /* Transfer Complete Interrupt flag */ +#define DMA2D_ISR_TWIF (1 << 2) /* Transfer Watermark Interrupt flag */ +#define DMA2D_ISR_CAEIF (1 << 3) /* CLUT Access Error Interrupt flag */ +#define DMA2D_ISR_CTCIF (1 << 4) /* CLUT Transfer Complete Interrupt flag */ +#define DMA2D_ISR_CEIF (1 << 5) /* Configuration Error Interrupt flag */ + +/* DMA2D Interrupt Flag Clear Register */ + +#define DMA2D_IFCR_CTEIF (1 << 0) /* Clear Transfer Interrupt Flag */ +#define DMA2D_IFCR_CTCIF (1 << 1) /* Clear Transfer Complete Interrupt Flag */ +#define DMA2D_IFCR_CTWIF (1 << 2) /* Clear Transfer Watermark Interrupt Flag */ +#define DMA2D_IFCR_CAECIF (1 << 3) /* Clear CLUT Access Error Interrupt Flag */ +#define DMA2D_IFCR_CCTCIF (1 << 4) /* Clear CLUT Transfer Complete Interrupt Flag */ +#define DMA2D_IFCR_CCEIF (1 << 5) /* Clear Configuration Error Interrupt Flag */ + +/* DMA2D Foreground Memory Access Register */ + +/* DMA2D Background Memory Access Register */ + +/* DMA2D Foreground/Background Offset Register */ + +#define DMA2D_xGOR_SHIFT (0) /* Bits 0-13 Line Offset */ +#define DMA2D_xGOR_MASK (0x3FFF << DMA2D_xGOR_SHIFT) +#define DMA2D_xGOR(n) ((uint32_t)(n) << DMA2D_xGOR_SHIFT) + +/* DMA2D Foreground/Background PFC Control Register */ + +#define DMA2D_xGPFCCR_CM_SHIFT (0) /* Bits 0-3 Color Mode */ +#define DMA2D_xGPFCCR_CM_MASK (0xF << DMA2D_xGPFCCR_CM_SHIFT) +#define DMA2D_xGPFCCR_CM(n) ((uint32_t)(n) << DMA2D_xGPFCCR_CM_SHIFT) +#define DMA2D_xGPFCCR_CCM (1 << 4) /* CLUT Color Mode */ +#define DMA2D_xGPFCCR_START (1 << 5) /* Start */ +#define DMA2D_xGPFCCR_CS_SHIFT (8) /* Bits 8-15 CLUT Size */ +#define DMA2D_xGPFCCR_CS_MASK (0xFF << DMA2D_xGPFCCR_CS_SHIFT) +#define DMA2D_xGPFCCR_CS(n) ((uint32_t)(n) << DMA2D_xGPFCCR_CS_SHIFT) +#define DMA2D_xGPFCCR_AM_SHIFT (16) /* Bits 16-17 Alpha Mode */ +#define DMA2D_xGPFCCR_AM_MASK (3 << DMA2D_xGPFCCR_AM_SHIFT) +#define DMA2D_xGPFCCR_AM(n) ((uint32_t)(n) << DMA2D_xGPFCCR_AM_SHIFT) +#define DMA2D_xGPFCCR_ALPHA_SHIFT (24) /* Bits 24-31 Alpha Value */ +#define DMA2D_xGPFCCR_ALPHA_MASK (0xFF << DMA2D_xGPFCCR_ALPHA_SHIFT) +#define DMA2D_xGPFCCR_ALPHA(n) ((uint32_t)(n) << DMA2D_xGPFCCR_ALPHA_SHIFT) + +/* DMA2D Foreground/Background Color Register */ + +#define DMA2D_xGCOLR_BLUE_SHIFT (0) /* Bits 0-7 Blue Value */ +#define DMA2D_xGCOLR_BLUE_MASK (0xFF << DMA2D_xGCOLR_BLUE_SHIFT) +#define DMA2D_xGCOLR_BLUE(n) ((uint32_t)(n) << DMA2D_xGCOLR_BLUE_SHIFT) +#define DMA2D_xGCOLR_GREEN_SHIFT (8) /* Bits 8-15 Green Value */ +#define DMA2D_xGCOLR_GREEN_MASK (0xFF << DMA2D_xGCOLR_GREEN_SHIFT) +#define DMA2D_xGCOLR_GREEN(n) ((uint32_t)(n) << DMA2D_xGCOLR_GREEN_SHIFT) +#define DMA2D_xGCOLR_RED_SHIFT (16) /* Bits 16-23 Red Value */ +#define DMA2D_xGCOLR_RED_MASK (0xFF << DMA2D_xGCOLR_RED_SHIFT) +#define DMA2D_xGCOLR_RED(n) ((uint32_t)(n) << DMA2D_xGCOLR_RED_SHIFT) + +/* DMA2D Foreground CLUT Memory Address Register */ + +/* DMA2D Background CLUT Memory Address Register */ + +/* DMA2D Output PFC Control Register */ + +#define DMA2D_OPFCCR_CM_SHIFT (0) /* Bits 0-2 Color Mode */ +#define DMA2D_OPFCCR_CM_MASK (7 << DMA2D_OPFCCR_CM_SHIFT) +#define DMA2D_OPFCCR_CM(n) ((uint32_t)(n) << DMA2D_OPFCCR_CM_SHIFT) + +/* DMA2D Output Color Register */ + +#define DMA2D_OCOLR_BLUE_SHIFT (0) /* Bits 0-7 Blue Value */ +#define DMA2D_OCOLR_BLUE_MASK (0xFF << DMA2D_OCOLR_BLUE_SHIFT) +#define DMA2D_OCOLR_BLUE(n) ((uint32_t)(n) << DMA2D_OCOLR_BLUE_SHIFT) +#define DMA2D_OCOLR_GREEN_SHIFT (8) /* Bits 8-15 Green Value */ +#define DMA2D_OCOLR_GREEN_MASK (0xFF << DMA2D_OCOLR_GREEN_SHIFT) +#define DMA2D_OCOLR_GREEN(n) ((uint32_t)(n) << DMA2D_OCOLR_GREEN_SHIFT) +#define DMA2D_OCOLR_RED_SHIFT (16) /* Bits 16-23 Red Value */ +#define DMA2D_OCOLR_RED_MASK (0xFF << DMA2D_OCOLR_RED_SHIFT) +#define DMA2D_OCOLR_RED(n) ((uint32_t)(n) << DMA2D_OCOLR_RED_SHIFT) +#define DMA2D_OCOLR_ALPHA_SHIFT (24) /* Bits 24-31 Alpha Value */ +#define DMA2D_OCOLR_ALPHA_MASK (0xFF << DMA2D_OCOLR_ALPHA_SHIFT) +#define DMA2D_OCOLR_ALPHA(n) ((uint32_t)(n) << DMA2D_OCOLR_ALPHA_SHIFT) + +/* DMA2D Output Memory Address Register */ + +/* DMA2D Output Offset Register */ + +#define DMA2D_OOR_LO_SHIFT (0) /* Bits 0-13 Line Offset */ +#define DMA2D_OOR_LO_MASK (0x3FFF << DMA2D_OOR_LO_SHIFT) +#define DMA2D_OOR_LO(n) ((uint32_t)(n) << DMA2D_OOR_LO_SHIFT) + +/* DMA2D Number Of Line Register */ + +#define DMA2D_NLR_NL_SHIFT (0) /* Bits 0-15 Number Of Lines */ +#define DMA2D_NLR_NL_MASK (0xFFFF << DMA2D_NLR_NL_SHIFT) +#define DMA2D_NLR_NL(n) ((uint32_t)(n) << DMA2D_NLR_NL_SHIFT) +#define DMA2D_NLR_PL_SHIFT (16) /* Bits 16-29 Pixel per Lines */ +#define DMA2D_NLR_PL_MASK (0x3FFF << DMA2D_NLR_PL_SHIFT) +#define DMA2D_NLR_PL(n) ((uint32_t)(n) << DMA2D_NLR_PL_SHIFT) + +/* DMA2D Line Watermark Register */ + +#define DMA2D_LWR_LW_SHIFT (0) /* Bits 0-15 Line Watermark */ +#define DMA2D_LWR_LW_MASK (0xFFFF << DMA2D_LWR_LW_SHIFT) +#define DMA2D_LWR_LW(n) ((uint32_t)(n) << DMA2D_LWR_LW_SHIFT) + +/* DMA2D AHB Master Timer Configuration Register */ + +#define DMA2D_AMTCR_EN (1 << 0) /* Enable */ +#define DMA2D_AMTCR_DT_SHIFT (0) /* Bits 8-15 Dead Time */ +#define DMA2D_AMTCR_DT_MASK (0xFF << DMA2D_AMTCR_DT_SHIFT) +#define DMA2D_AMTCR_DT(n) ((uint32_t)(n) << DMA2D_AMTCR_DT_SHIFT) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32_DMA2D_H */ diff --git a/arch/arm/src/stm32f7/chip/stm32_ltdc.h b/arch/arm/src/stm32f7/chip/stm32_ltdc.h new file mode 100755 index 00000000000..8ae45ddaa4d --- /dev/null +++ b/arch/arm/src/stm32f7/chip/stm32_ltdc.h @@ -0,0 +1,381 @@ +/************************************************************************************ + * arch/arm/src/stm32/chip/stm32_ltdc.h + * + * Copyright (C) 2013 Ken Pettit. All rights reserved. + * Author: Ken Pettit + * + * 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_CHIP_STM32_LTDC_H +#define __ARCH_ARM_SRC_STM32_CHIP_STM32_LTDC_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include "chip/stm32_memorymap.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#define STM32_LTDC_NCLUT 256 /* Number of entries in the CLUTs */ + +/* LCDC Register Offsets ************************************************************/ + +#define STM32_LTDC_SSCR_OFFSET 0x0008 /* LTDC Synchronization Size Config Register */ +#define STM32_LTDC_BPCR_OFFSET 0x000c /* LTDC Back Porch Configuration Register */ +#define STM32_LTDC_AWCR_OFFSET 0x0010 /* LTDC Active Width Configuration Register */ +#define STM32_LTDC_TWCR_OFFSET 0x0014 /* LTDC Total Width Configuration Register */ +#define STM32_LTDC_GCR_OFFSET 0x0018 /* LTDC Global Control Register */ + /* 0x0020 Reserved */ +#define STM32_LTDC_SRCR_OFFSET 0x0024 /* LTDC Shadow Reload Configuration Register */ + /* 0x0028 Reserved */ +#define STM32_LTDC_BCCR_OFFSET 0x002C /* LTDC Background Color Configuration Register */ + /* 0x0030 Reserved */ +#define STM32_LTDC_IER_OFFSET 0x0034 /* LTDC Interrupt Enable Register */ +#define STM32_LTDC_ISR_OFFSET 0x0038 /* LTDC Interrupt Status Register */ +#define STM32_LTDC_ICR_OFFSET 0x003C /* LTDC Interrupt Clear Register */ +#define STM32_LTDC_LIPCR_OFFSET 0x0040 /* LTDC Line Interrupt Position Config Register */ +#define STM32_LTDC_CPSR_OFFSET 0x0044 /* LTDC Current Position Status Register */ +#define STM32_LTDC_CDSR_OFFSET 0x0048 /* LTDC Current Display Status Register */ + /* 0x004c-0x0080 Reserved */ + +#define STM32_LTDC_L1CR_OFFSET 0x0084 /* LTDC Layer 1 Control Register */ +#define STM32_LTDC_L1WHPCR_OFFSET 0x0088 /* LTDC Layer 1 Window Horiz Pos Config Register */ +#define STM32_LTDC_L1WVPCR_OFFSET 0x008C /* LTDC Layer 1 Window Vert Pos Config Register */ +#define STM32_LTDC_L1CKCR_OFFSET 0x0090 /* LTDC Layer 1 Color Keying Config Register */ +#define STM32_LTDC_L1PFCR_OFFSET 0x0094 /* LTDC Layer 1 Pixel Format Configuration Register */ +#define STM32_LTDC_L1CACR_OFFSET 0x0098 /* LTDC Layer 1 Constant Alpha Config Register */ +#define STM32_LTDC_L1DCCR_OFFSET 0x009C /* LTDC Layer 1 Default Color Config Register */ +#define STM32_LTDC_L1BFCR_OFFSET 0x00A0 /* LTDC Layer 1 Blending Factors Config Register */ + /* 0x00A4-0x00A8 Reserved */ +#define STM32_LTDC_L1CFBAR_OFFSET 0x00AC /* LTDC Layer 1 Color Frame Buffer Address Register */ +#define STM32_LTDC_L1CFBLR_OFFSET 0x00B0 /* LTDC Layer 1 Color Frame Buffer Length Register */ +#define STM32_LTDC_L1CFBLNR_OFFSET 0x00B4 /* LTDC Layer 1 Color Frame Buffer Line Number Register */ + /* 0x00B8-0x00C0 Reserved */ +#define STM32_LTDC_L1CLUTWR_OFFSET 0x00C4 /* LTDC Layer 1 CLUT Write Register */ + /* 0x00C8-0x0100 Reserved */ +#define STM32_LTDC_L2CR_OFFSET 0x0104 /* LTDC Layer 2 Control Register */ +#define STM32_LTDC_L2WHPCR_OFFSET 0x0108 /* LTDC Layer 2 Window Horiz Pos Config Register */ +#define STM32_LTDC_L2WVPCR_OFFSET 0x010C /* LTDC Layer 2 Window Vert Pos Config Register */ +#define STM32_LTDC_L2CKCR_OFFSET 0x0110 /* LTDC Layer 2 Color Keying Config Register */ +#define STM32_LTDC_L2PFCR_OFFSET 0x0114 /* LTDC Layer 2 Pixel Format Configuration Register */ +#define STM32_LTDC_L2CACR_OFFSET 0x0118 /* LTDC Layer 2 Constant Alpha Config Register */ +#define STM32_LTDC_L2DCCR_OFFSET 0x011C /* LTDC Layer 2 Default Color Config Register */ +#define STM32_LTDC_L2BFCR_OFFSET 0x0120 /* LTDC Layer 2 Blending Factors Config Register */ + /* 0x0124-0x0128 Reserved */ +#define STM32_LTDC_L2CFBAR_OFFSET 0x012C /* LTDC Layer 2 Color Frame Buffer Address Register */ +#define STM32_LTDC_L2CFBLR_OFFSET 0x0130 /* LTDC Layer 2 Color Frame Buffer Length Register */ +#define STM32_LTDC_L2CFBLNR_OFFSET 0x0134 /* LTDC Layer 2 Color Frame Buffer Line Number Register */ + /* 0x0138-0x0130 Reserved */ +#define STM32_LTDC_L2CLUTWR_OFFSET 0x0144 /* LTDC Layer 2 CLUT Write Register */ + /* 0x0148-0x03ff Reserved */ + +/* LTDC Register Addresses *********************************************************/ + +#define STM32_LTDC_SSCR (STM32_LTDC_BASE+STM32_LTDC_SSCR_OFFSET) +#define STM32_LTDC_BPCR (STM32_LTDC_BASE+STM32_LTDC_BPCR_OFFSET) +#define STM32_LTDC_AWCR (STM32_LTDC_BASE+STM32_LTDC_AWCR_OFFSET) +#define STM32_LTDC_TWCR (STM32_LTDC_BASE+STM32_LTDC_TWCR_OFFSET) +#define STM32_LTDC_GCR (STM32_LTDC_BASE+STM32_LTDC_GCR_OFFSET) +#define STM32_LTDC_SRCR (STM32_LTDC_BASE+STM32_LTDC_SRCR_OFFSET) +#define STM32_LTDC_BCCR (STM32_LTDC_BASE+STM32_LTDC_BCCR_OFFSET) +#define STM32_LTDC_IER (STM32_LTDC_BASE+STM32_LTDC_IER_OFFSET) +#define STM32_LTDC_ISR (STM32_LTDC_BASE+STM32_LTDC_ISR_OFFSET) +#define STM32_LTDC_ICR (STM32_LTDC_BASE+STM32_LTDC_ICR_OFFSET) +#define STM32_LTDC_LIPCR (STM32_LTDC_BASE+STM32_LTDC_LIPCR_OFFSET) +#define STM32_LTDC_CPSR (STM32_LTDC_BASE+STM32_LTDC_CPSR_OFFSET) +#define STM32_LTDC_CDSR (STM32_LTDC_BASE+STM32_LTDC_CDSR_OFFSET) + +#define STM32_LTDC_L1CR (STM32_LTDC_BASE+STM32_LTDC_L1CR_OFFSET) +#define STM32_LTDC_L1WHPCR (STM32_LTDC_BASE+STM32_LTDC_L1WHPCR_OFFSET) +#define STM32_LTDC_L1WVPCR (STM32_LTDC_BASE+STM32_LTDC_L1WVPCR_OFFSET) +#define STM32_LTDC_L1CKCR (STM32_LTDC_BASE+STM32_LTDC_L1CKCR_OFFSET) +#define STM32_LTDC_L1PFCR (STM32_LTDC_BASE+STM32_LTDC_L1PFCR_OFFSET) +#define STM32_LTDC_L1CACR (STM32_LTDC_BASE+STM32_LTDC_L1CACR_OFFSET) +#define STM32_LTDC_L1DCCR (STM32_LTDC_BASE+STM32_LTDC_L1DCCR_OFFSET) +#define STM32_LTDC_L1BFCR (STM32_LTDC_BASE+STM32_LTDC_L1BFCR_OFFSET) +#define STM32_LTDC_L1CFBAR (STM32_LTDC_BASE+STM32_LTDC_L1CFBAR_OFFSET) +#define STM32_LTDC_L1CFBLR (STM32_LTDC_BASE+STM32_LTDC_L1CFBLR_OFFSET) +#define STM32_LTDC_L1CFBLNR (STM32_LTDC_BASE+STM32_LTDC_L1CFBLNR_OFFSET) +#define STM32_LTDC_L1CLUTWR (STM32_LTDC_BASE+STM32_LTDC_L1CLUTWR_OFFSET) + +#define STM32_LTDC_L2CR (STM32_LTDC_BASE+STM32_LTDC_L2CR_OFFSET) +#define STM32_LTDC_L2WHPCR (STM32_LTDC_BASE+STM32_LTDC_L2WHPCR_OFFSET) +#define STM32_LTDC_L2WVPCR (STM32_LTDC_BASE+STM32_LTDC_L2WVPCR_OFFSET) +#define STM32_LTDC_L2CKCR (STM32_LTDC_BASE+STM32_LTDC_L2CKCR_OFFSET) +#define STM32_LTDC_L2PFCR (STM32_LTDC_BASE+STM32_LTDC_L2PFCR_OFFSET) +#define STM32_LTDC_L2CACR (STM32_LTDC_BASE+STM32_LTDC_L2CACR_OFFSET) +#define STM32_LTDC_L2DCCR (STM32_LTDC_BASE+STM32_LTDC_L2DCCR_OFFSET) +#define STM32_LTDC_L2BFCR (STM32_LTDC_BASE+STM32_LTDC_L2BFCR_OFFSET) +#define STM32_LTDC_L2CFBAR (STM32_LTDC_BASE+STM32_LTDC_L2CFBAR_OFFSET) +#define STM32_LTDC_L2CFBLR (STM32_LTDC_BASE+STM32_LTDC_L2CFBLR_OFFSET) +#define STM32_LTDC_L2CFBLNR (STM32_LTDC_BASE+STM32_LTDC_L2CFBLNR_OFFSET) +#define STM32_LTDC_L2CLUTWR (STM32_LTDC_BASE+STM32_LTDC_L2CLUTWR_OFFSET) + +/* LTDC Register Bit Definitions ***************************************************/ + +/* LTDC Synchronization Size Configuration Register */ + +#define LTDC_SSCR_VSH_SHIFT (0) /* Bits 0-10: Vertical Sync Height (scan lines) */ +#define LTDC_SSCR_VSH_MASK (0x7ff << LTDC_SSCR_VSH_SHIFT) +# define LTDC_SSCR_VSH(n) ((uint32_t)(n) << LTDC_SSCR_VSH_SHIFT) +#define LTDC_SSCR_HSW_SHIFT (16) /* Bits 16-27: Horizontal Sync Width (pixel clocks) */ +#define LTDC_SSCR_HSW_MASK (0xfff << LTDC_SSCR_HSW_SHIFT) +# define LTDC_SSCR_HSW(n) ((uint32_t)(n) << LTDC_SSCR_HSW_SHIFT) + +/* LTDC Back Porch Configuration Register */ + +#define LTDC_BPCR_AVBP_SHIFT (0) /* Bits 0-10: Accumulated Vertical back porch (scan lines) */ +#define LTDC_BPCR_AVBP_MASK (0x7ff << LTDC_BPCR_AVBP_SHIFT) +# define LTDC_BPCR_AVBP(n) ((uint32_t)(n) << LTDC_BPCR_AVBP_SHIFT) +#define LTDC_BPCR_AHBP_SHIFT (16) /* Bits 16-27: Accumulated Horizontal back porch (pixel clocks) */ +#define LTDC_BPCR_AHBP_MASK (0xfff << LTDC_BPCR_AVBP_SHIFT) +# define LTDC_BPCR_AHBP(n) ((uint32_t)(n) << LTDC_BPCR_AHBP_SHIFT) + +/* LTDC Active Width Configuration Register */ + +#define LTDC_AWCR_AAH_SHIFT (0) /* Bits 0-10: Accumulated Active Height (scan lines) */ +#define LTDC_AWCR_AAH_MASK (0x7ff << LTDC_AWCR_AAH_SHIFT) +# define LTDC_AWCR_AAH(n) ((uint32_t)(n) << LTDC_AWCR_AAH_SHIFT) +#define LTDC_AWCR_AAW_SHIFT (16) /* Bits 16-27: Accumulated Active Width (pixel clocks) */ +#define LTDC_AWCR_AAW_MASK (0xfff << LTDC_AWCR_AAW_SHIFT) +# define LTDC_AWCR_AAW(n) ((uint32_t)(n) << LTDC_AWCR_AAW_SHIFT) + +/* LTDC Total Width Configuration Register */ + +#define LTDC_TWCR_TOTALH_SHIFT (0) /* Bits 0-10: Total Height (scan lines) */ +#define LTDC_TWCR_TOTALH_MASK (0x7ff << LTDC_TWCR_TOTALH_SHIFT) +# define LTDC_TWCR_TOTALH(n) ((uint32_t)(n) << LTDC_TWCR_TOTALH_SHIFT) +#define LTDC_TWCR_TOTALW_SHIFT (16) /* Bits 16-27: Total Width (pixel clocks) */ +#define LTDC_TWCR_TOTALW_MASK (0xfff << LTDC_TWCR_TOTALW_SHIFT) +# define LTDC_TWCR_TOTALW(n) ((uint32_t)(n) << LTDC_TWCR_TOTALW_SHIFT) + +/* LTDC Global Control Register */ + +#define LTDC_GCR_LTDCEN (1 << 0) /* Bit 0: LCD-TFT Controller Enable Bit */ +#define LTDC_GCR_DBW_SHIFT (4) /* Bits 4-6: Dither Blue Width */ +#define LTDC_GCR_DBW_MASK (0x7 << LTDC_GCR_DBW_SHIFT) +# define LTDC_GCR_DBW(n) ((uint32_t)(n) << LTDC_GCR_DBW_SHIFT) +#define LTDC_GCR_DGW_SHIFT (8) /* Bits 8-10: Dither Green Width */ +#define LTDC_GCR_DGW_MASK (0x7 << LTDC_GCR_DGW_SHIFT) +# define LTDC_GCR_DGW(n) ((uint32_t)(n) << LTDC_GCR_DGW_SHIFT) +#define LTDC_GCR_DRW_SHIFT (12) /* Bits 12-14: Dither Red Width */ +#define LTDC_GCR_DRW_MASK (0x7 << LTDC_GCR_DRW_SHIFT) +# define LTDC_GCR_DRW(n) ((uint32_t)(n) << LTDC_GCR_DRW_SHIFT) +#define LTDC_GCR_DEN (1 << 16) /* Bit 16: Dither Enable */ +#define LTDC_GCR_PCPOL (1 << 28) /* Bit 28: Pixel Clock Polarity */ +#define LTDC_GCR_DEPOL (1 << 29) /* Bit 29: Data Enable Polarity */ +#define LTDC_GCR_VSPOL (1 << 30) /* Bit 30: Vertical Sync Polarity */ +#define LTDC_GCR_HSPOL (1 << 31) /* Bit 31: Horizontal Sync Polarity */ + +/* LTDC Shadow Reload Configuration Register */ + +#define LTDC_SRCR_IMR (1 << 0) /* Bit 0: Immediate Reload */ +#define LTDC_SRCR_VBR (1 << 1) /* Bit 1: Vertical Blanking Reload */ + +/* LTDC Background Color Configuration Register */ + +#define LTDC_BCCR_BCBLUE_SHIFT (0) /* Bits 0-7: Background Color Blue Value */ +#define LTDC_BCCR_BCBLUE_MASK (0xFF << LTDC_BCCR_BCBLUE_SHIFT) +# define LTDC_BCCR_BCBLUE(n) ((uint32_t)(n) << LTDC_BCCR_BCBLUE_SHIFT) +#define LTDC_BCCR_BCGREEN_SHIFT (8) /* Bits 8-15: Background Color Green Value */ +#define LTDC_BCCR_BCGREEN_MASK (0xFF << LTDC_BCCR_BCGREEN_SHIFT) +# define LTDC_BCCR_BCGREEN(n) ((uint32_t)(n) << LTDC_BCCR_BCGREEN_SHIFT) +#define LTDC_BCCR_BCRED_SHIFT (16) /* Bits 16-23: Background Color Red Value */ +#define LTDC_BCCR_BCRED_MASK (0xFF << LTDC_BCCR_BCRED_SHIFT) +# define LTDC_BCCR_BCRED(n) ((uint32_t)(n) << LTDC_BCCR_BCRED_SHIFT) + +/* LTDC Interrupt Enable Register */ + +#define LTDC_IER_LIE (1 << 0) /* Bit 0: Line Interrupt Enable */ +#define LTDC_IER_FUIE (1 << 1) /* Bit 1: FIFO Underrun Interrupt Enable */ +#define LTDC_IER_TERRIE (1 << 2) /* Bit 2: Transfer Error Interrupt Enable */ +#define LTDC_IER_RRIE (1 << 3) /* Bit 3: Register Reload Interrupt Enable */ + +/* LTDC Interrupt Status Register */ + +#define LTDC_ISR_LIF (1 << 0) /* Bit 0: Line Interrupt Flag */ +#define LTDC_ISR_FUIF (1 << 1) /* Bit 1: FIFO Underrun Interrupt Flag */ +#define LTDC_IER_TERRIF (1 << 2) /* Bit 2: Transfer Error Interrupt Flag */ +#define LTDC_ISR_RRIF (1 << 3) /* Bit 3: Register Reload Interrupt Flag */ + +/* LTDC Interrupt Clear Register */ + +#define LTDC_ICR_CLIF (1 << 0) /* Bit 0: Clear Line Interrupt Flag */ +#define LTDC_ICR_CFUIF (1 << 1) /* Bit 1: Clear FIFO Underrun Interrupt Flag */ +#define LTDC_ICR_CTERRIF (1 << 2) /* Bit 2: Clear Transfer Error Interrupt Flag */ +#define LTDC_ICR_CRRIF (1 << 3) /* Bit 3: Clear Register Reload Interrupt Flag */ + +/* LTDC Line Interrupt Posittion Configuration Register */ + +#define LTDC_LIPCR_LIPOS_SHIFT (0) /* Bits 0-10: Line Interrupt Position */ +#define LTDC_LIPCR_LIPOS_MASK (0x7FF << LTDC_LIPCR_LIPOS_SHIFT) +# define LTDC_LIPCR_LIPOS(n) ((uint32_t)(n) << LTDC_LIPCR_LIPOS_SHIFT) + +/* LTDC Current Position Status Register */ + +#define LTDC_CPSR_CYPOS_SHIFT (0) /* Bits 0-15: Current Y Position */ +#define LTDC_CPSR_CYPOS_MASK (0xFFFF << LTDC_CPSR_CYPOS_SHIFT) +# define LTDC_CPSR_CYPOS(n) ((uint32_t)(n) << LTDC_CPSR_CYPOS_SHIFT) +#define LTDC_CPSR_CXPOS_SHIFT (16) /* Bits 15-31: Current X Position */ +#define LTDC_CPSR_CXPOS_MASK (0xFFFF << LTDC_CPSR_CXPOS_SHIFT) +# define LTDC_CPSR_CXPOS(n) ((uint32_t)(n) << LTDC_CPSR_CXPOS_SHIFT) + +/* LTDC Current Display Status Register */ + +#define LTDC_CDSR_VDES (1 << 0) /* Bit 0: Vertical Data Enable display Status */ +#define LTDC_CDSR_HDES (1 << 1) /* Bit 1: Horizontal Data Enable display Status */ +#define LTDC_CDSR_VSYNCS (1 << 2) /* Bit 2: Vertical Sync display Status */ +#define LTDC_CDSR_HSYNCS (1 << 3) /* Bit 3: Horizontal Sync display Status */ + +/* LTDC Layer x Control Register */ + +#define LTDC_LxCR_LEN (1 << 0) /* Bit 0: Layer Enable */ +#define LTDC_LxCR_COLKEN (1 << 1) /* Bit 1: Color Keying Enable */ +#define LTDC_LxCR_CLUTEN (1 << 4) /* Bit 4: Color Look-Up Table Enable */ + +/* LTDC Layer x Window Horizontal Position Configuration Register */ + +#define LTDC_LxWHPCR_WHSTPOS_SHIFT (0) /* Bits 0-11: Window Horizontal Start Position */ +#define LTDC_LxWHPCR_WHSTPOS_MASK (0xFFF << LTDC_LxWHPCR_WHSTPOS_SHIFT) +# define LTDC_LxWHPCR_WHSTPOS(n) ((uint32_t)(n) << LTDC_LxWHPCR_WHSTPOS_SHIFT) +#define LTDC_LxWHPCR_WHSPPOS_SHIFT (16) /* Bits 16-27: Window Horizontal Stop Position */ +#define LTDC_LxWHPCR_WHSPPOS_MASK (0xFFF << LTDC_LxWHPCR_WHSPPOS_SHIFT) +# define LTDC_LxWHPCR_WHSPPOS(n) ((uint32_t)(n) << LTDC_LxWHPCR_WHSPPOS_SHIFT) + +/* LTDC Layer x Window Vertical Position Configuration Register */ + +#define LTDC_LxWVPCR_WVSTPOS_SHIFT (0) /* Bits 0-10: Window Vertical Start Position */ +#define LTDC_LxWVPCR_WVSTPOS_MASK (0x7FF << LTDC_LxWVPCR_WVSTPOS_SHIFT) +# define LTDC_LxWVPCR_WVSTPOS(n) ((uint32_t)(n) << LTDC_LxWVPCR_WVSTPOS_SHIFT) +#define LTDC_LxWVPCR_WVSPPOS_SHIFT (16) /* Bits 16-26: Window Vertical Stop Position */ +#define LTDC_LxWVPCR_WVSPPOS_MASK (0x7FF << LTDC_LxWVPCR_WVSPPOS_SHIFT) +# define LTDC_LxWVPCR_WVSPPOS(n) ((uint32_t)(n) << LTDC_LxWVPCR_WVSPPOS_SHIFT) + +/* LTDC Layer x Color Keying Configuration Register */ + +#define LTDC_LxCKCR_CKBLUE_SHIFT (0) /* Bits 0-7: Color Key Blue Value */ +#define LTDC_LxCKCR_CKBLUE_MASK (0xFF << LTDC_LxCKCR_CKBLUE_SHIFT) +# define LTDC_LxCKCR_CKBLUE(n) ((uint32_t)(n) << LTDC_LxCKCR_CKBLUE_SHIFT) +#define LTDC_LxCKCR_CKGREEN_SHIFT (8) /* Bits 8-15: Color Key Green Value */ +#define LTDC_LxCKCR_CKGREEN_MASK (0xFF << LTDC_LxCKCR_CKGREEN_SHIFT) +# define LTDC_LxCKCR_CKGREEN(n) ((uint32_t)(n) << LTDC_LxCKCR_CKGREEN_SHIFT) +#define LTDC_LxCKCR_CKRED_SHIFT (16) /* Bits 16-23: Color Key Red Value */ +#define LTDC_LxCKCR_CKRED_MASK (0xFF << LTDC_LxCKCR_CKRED_SHIFT) +# define LTDC_LxCKCR_CKRED(n) ((uint32_t)(n) << LTDC_LxCKCR_CKRED_SHIFT) + +/* LTDC Layer x Pixel Format Configuration Register */ + +#define LTDC_LxPFCR_PF_SHIFT (0) /* Bits 0-2: Pixel Format */ +#define LTDC_LxPFCR_PF_MASK (0x7 << LTDC_LxPFCR_PF_SHIFT) +# define LTDC_LxPFCR_PF(n) ((uint32_t)(n) << LTDC_LxPFCR_PF_SHIFT) + +#define LTDC_PF_ARGB8888 0 +#define LTDC_PF_RGB888 1 +#define LTDC_PF_RGB565 2 +#define LTDC_PF_ARGB1555 3 +#define LTDC_PF_ARGB4444 4 +#define LTDC_PF_L8 5 /* 8-bit Luninance (CLUT lookup) */ +#define LTDC_PF_AL44 6 /* 4-bit Alpha, 4-bit Luminance */ +#define LTDC_PF_AL88 7 /* 8-bit Alpha, 8-bit Luminance */ + +/* LTDC Layer x Constant Alpha Configuration Register */ + +#define LTDC_LxCACR_CONSTA_SHIFT (0) /* Bits 0-7: Constant Alpha */ +#define LTDC_LxCACR_CONSTA_MASK (0x7 << LTDC_LxCACR_CONSTA_SHIFT) +# define LTDC_LxCACR_CONSTA(n) ((uint32_t)(n) << LTDC_LxCACR_CONSTA_SHIFT) + +/* LTDC Layer x Default Color Configuration Register */ + +#define LTDC_LxDCCR_DCBLUE_SHIFT (0) /* Bits 0-7: Default Color Blue Value */ +#define LTDC_LxDCCR_DCBLUE_MASK (0xFF << LTDC_LxDCCR_DCBLUE_SHIFT) +# define LTDC_LxDCCR_DCBLUE(n) ((uint32_t)(n) << LTDC_LxDCCR_DCBLUE_SHIFT) +#define LTDC_LxDCCR_DCGREEN_SHIFT (8) /* Bits 8-15: Default Color Green Value */ +#define LTDC_LxDCCR_DCGREEN_MASK (0xFF << LTDC_LxDCCR_DCGREEN_SHIFT) +# define LTDC_LxDCCR_DCGREEN(n) ((uint32_t)(n) << LTDC_LxDCCR_DCGREEN_SHIFT) +#define LTDC_LxDCCR_DCRED_SHIFT (16) /* Bits 16-23: Default Color Red Value */ +#define LTDC_LxDCCR_DCRED_MASK (0xFF << LTDC_LxDCCR_DCRED_SHIFT) +# define LTDC_LxDCCR_DCRED(n) ((uint32_t)(n) << LTDC_LxDCCR_DCRED_SHIFT) +#define LTDC_LxDCCR_DCALPHA_SHIFT (24) /* Bits 24-31: Default Color Alpha Value */ +#define LTDC_LxDCCR_DCALPHA_MASK (0xFF << LTDC_LxDCCR_DCALPHA_SHIFT) +# define LTDC_LxDCCR_DCALPHA(n) ((uint32_t)(n) << LTDC_LxDCCR_DCALPHA_SHIFT) + +/* LTDC Layer x Blending Factors Configuration Register */ + +#define LTDC_LxBFCR_BF2_SHIFT (0) /* Bits 0-2: Blending Factor 2 */ +#define LTDC_LxBFCR_BF2_MASK (0x7 << LTDC_LxBFCR_BF2_SHIFT) +# define LTDC_LxBFCR_BF2(n) ((uint32_t)(n) << LTDC_LxBFCR_BF2_SHIFT) +#define LTDC_LxBFCR_BF1_SHIFT (8) /* Bits 8-10: Blending Factor 1 */ +#define LTDC_LxBFCR_BF1_MASK (0x7 << LTDC_LxBFCR_BF1_SHIFT) +# define LTDC_LxBFCR_BF1(n) ((uint32_t)(n) << LTDC_LxBFCR_BF1_SHIFT) + +#define LTDC_BF1_CONST_ALPHA 0x04 /* Constant Alpha */ +#define LTDC_BF1_PIXEL_ALPHA 0x06 /* Pixel Alpha x Constant Alpha */ +#define LTDC_BF2_CONST_ALPHA 0x05 /* Constant Alpha */ +#define LTDC_BF2_PIXEL_ALPHA 0x07 /* Pixel Alpha x Constant Alpha */ + +/* LTDC Layer x Color Frame Buffer Length Configuration Register */ + +#define LTDC_LxCFBLR_CFBLL_SHIFT (0) /* Bits 0-12: Color Frame Buffer Line Length */ +#define LTDC_LxCFBLR_CFBLL_MASK (0x1FFF << LTDC_LxCFBLR_CFBLL_SHIFT) +# define LTDC_LxCFBLR_CFBLL(n) ((uint32_t)(n) << LTDC_LxCFBLR_CFBLL_SHIFT) +#define LTDC_LxCFBLR_CFBP_SHIFT (16) /* Bits 16-28: Color Frame Buffer Pitch */ +#define LTDC_LxCFBLR_CFBP_MASK (0x1FFF << LTDC_LxCFBLR_CFBP_SHIFT) +# define LTDC_LxCFBLR_CFBP(n) ((uint32_t)(n) << LTDC_LxCFBLR_CFBP_SHIFT) + +/* LTDC Layer x Color Frame Buffer Line Number Register */ + +#define LTDC_LxCFBLNR_LN_SHIFT (0) /* Bits 0-10: Color Frame Buffer Line Number */ +#define LTDC_LxCFBLNR_LN_MASK (0x7FF << LTDC_LxCFBLNR_LN_SHIFT) +# define LTDC_LxCFBLNR_LN(n) ((uint32_t)(n) << LTDC_LxCFBLNR_LN_SHIFT) + +/* LTDC Layer x CLUT Write Register */ + +#define LTDC_LxCLUTWR_BLUE_SHIFT (0) /* Bits 0-7: Default Color Blue Value */ +#define LTDC_LxCLUTWR_BLUE_MASK (0xFF << LTDC_LxCLUTWR_BLUE_SHIFT) +# define LTDC_LxCLUTWR_BLUE(n) ((uint32_t)(n) << LTDC_LxCLUTWR_BLUE_SHIFT) +#define LTDC_LxCLUTWR_GREEN_SHIFT (8) /* Bits 8-15: Default Color Green Value */ +#define LTDC_LxCLUTWR_GREEN_MASK (0xFF << LTDC_LxCLUTWR_GREEN_SHIFT) +# define LTDC_LxCLUTWR_GREEN(n) ((uint32_t)(n) << LTDC_LxCLUTWR_GREEN_SHIFT) +#define LTDC_LxCLUTWR_RED_SHIFT (16) /* Bits 16-23: Default Color Red Value */ +#define LTDC_LxCLUTWR_RED_MASK (0xFF << LTDC_LxCLUTWR_RED_SHIFT) +# define LTDC_LxCLUTWR_RED(n) ((uint32_t)(n) << LTDC_LxCLUTWR_RED_SHIFT) +#define LTDC_LxCLUTWR_CLUTADD_SHIFT (24) /* Bits 24-31: CLUT Address */ +#define LTDC_LxCLUTWR_CLUTADD_MASK (0xFF << LTDC_LxCLUTWR_CLUTADD_SHIFT) +# define LTDC_LxCLUTWR_CLUTADD(n) ((uint32_t)(n) << LTDC_LxCLUTWR_CLUTADD_SHIFT) + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32_LTDC_H */ diff --git a/arch/arm/src/stm32f7/stm32_dma2d.c b/arch/arm/src/stm32f7/stm32_dma2d.c new file mode 100755 index 00000000000..8611ab2c1a3 --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_dma2d.c @@ -0,0 +1,2309 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_dma2d.c + * + * Copyright (C) 2014-2015 Marco Krahl. All rights reserved. + * Author: Marco Krahl + * + * 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 regerr lcderr +# define reginfo lcdinfo +#else +# define regerr(x...) +# define reginfo(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, FAR void *arg); +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; + + lcdinfo("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, FAR void *arg) +{ + uint32_t regval = getreg32(STM32_DMA2D_ISR); + FAR struct stm32_interrupt_s *priv = &g_interrupt; + + reginfo("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) + { + lcderr("ERROR: 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 a critical section. + * + * 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) + { + lcderr("ERROR: 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 = enter_critical_section(); + + 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; + reginfo("set regval=%08x\n", regval); + putreg32(regval, pfcreg); + reginfo("configured regval=%08x\n", getreg32(pfcreg)); + } + + leave_critical_section(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 = enter_critical_section(); + + 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(); + } + + leave_critical_section(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; + + lcdinfo("%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 */ + + lcdinfo("%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) +{ + lcdinfo("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: + lcderr("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) +{ + lcdinfo("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: + lcderr("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; + + lcdinfo("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) +{ + lcdinfo("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) +{ + lcdinfo("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; + + lcdinfo("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) +{ + lcdinfo("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 */ + + lcderr("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; + + lcdinfo("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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) + { + lcderr("ERROR: CLUT is not supported for the pixel format: %d\n", + priv->vinfo.fmt); + ret = -EINVAL; + } + else if (cmap->first >= STM32_DMA2D_NCLUT) + { + lcderr("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]; + + reginfo("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]); + + reginfo("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; + } + + lcderr("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; + + lcdinfo("layer=%p, cmap=%p\n", layer, cmap); + + if (stm32_dma2d_lvalidate(priv) && cmap) + { + sem_wait(priv->lock); + + if (priv->fmt != DMA2D_PF_L8) + { + lcderr("ERROR: CLUT is not supported for the pixel format: %d\n", + priv->vinfo.fmt); + ret = -EINVAL; + } + else if (cmap->first >= STM32_DMA2D_NCLUT) + { + lcderr("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]; + + reginfo("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]); + + reginfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + } + + lcderr("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; + + lcdinfo("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; + lcderr("ERROR: Returning ECANCELED\n"); + } + } + + sem_post(destlayer->lock); + } + else + { + ret = -EINVAL; + lcderr("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; + + lcdinfo("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; + lcderr("ERROR: Returning ECANCELED\n"); + } + } + + sem_post(destlayer->lock); + } + else + { + ret = -EINVAL; + lcderr("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; + + lcdinfo("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; + lcderr("ERROR: Returning ECANCELED\n"); + } + } + + sem_post(priv->lock); + } + else + { + ret = -EINVAL; + lcderr("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; + } + + lcderr("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; + + lcdinfo("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->display = 0; + pinfo->bpp = bpp; + + /* Bind the layer to the identifier */ + + g_layers[lid] = layer; + } + else + { + /* free the layer struture */ + + kmm_free(layer); + layer = NULL; + lcderr("ERROR: ENOMEM, Unable to allocate layer buffer\n"); + errno = ENOMEM; + } + } + else + { + lcderr("ERROR: ENOMEM, unable to allocate layer structure\n"); + errno = ENOMEM; + } + } + else + { + lcderr("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) +{ + lcdinfo("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. This waitsem + * semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + sem_init(g_interrupt.sem, 0, 0); + sem_setprotocol(g_interrupt.sem, SEM_PRIO_NONE); + +#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, NULL); + + /* 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; + + lcdinfo("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) + { + lcderr("ERROR: 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 */ diff --git a/arch/arm/src/stm32f7/stm32_dma2d.h b/arch/arm/src/stm32f7/stm32_dma2d.h new file mode 100755 index 00000000000..ddaeada7b20 --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_dma2d.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_dma2d.h + * + * Copyright (C) 2014-2015 Marco Krahl. All rights reserved. + * Author: Marco Krahl + * + * 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_STM32_DMA2D_H +#define __ARCH_ARM_SRC_STM32_STM32_DMA2D_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#ifdef CONFIG_STM32_DMA2D +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +# 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 function 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 + * + * 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); +# endif /* CONFIG_STM32_LTDC_INTERFACE */ + +#endif /* CONFIG_STM32_DMA2D */ +#endif /* __ARCH_ARM_SRC_STM32_STM32_DMA2D_H */ diff --git a/arch/arm/src/stm32f7/stm32_ltdc.c b/arch/arm/src/stm32f7/stm32_ltdc.c new file mode 100755 index 00000000000..22b650c598b --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_ltdc.c @@ -0,0 +1,3624 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_ltdc.c + * + * Copyright (C) 2013-2015 Ken Pettit. All rights reserved. + * Authors: Ken Pettit + * Marco Krahl + * + * References: + * STM32F429 Technical Reference Manual and Data Sheet + * + * 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 + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "up_internal.h" +#include "stm32.h" +#include "chip/stm32_ltdc.h" +#include "stm32_ltdc.h" +#include "stm32_dma2d.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register definition ******************************************************/ + +#ifndef BOARD_LTDC_WIDTH +# error BOARD_LTDC_WIDTH must be defined in the board.h header file +#endif + +#ifndef BOARD_LTDC_HEIGHT +# error BOARD_LTDC_HEIGHT must be defined in the board.h header file +#endif + +#define STM32_LTDC_HEIGHT BOARD_LTDC_HEIGHT +#define STM32_LTDC_WIDTH BOARD_LTDC_WIDTH + +/* Configure LTDC register */ + +/* LTDC_LxWHPCR register */ + +#define STM32_LTDC_LxWHPCR_WHSTPOS (BOARD_LTDC_HSYNC + BOARD_LTDC_HBP - 1) +#define STM32_LTDC_LxWHPCR_WHSPPOS (BOARD_LTDC_HSYNC + BOARD_LTDC_HBP + \ + STM32_LTDC_WIDTH - 1) + +/* LTDC_LxWVPCR register */ + +#define STM32_LTDC_LxWVPCR_WVSTPOS (BOARD_LTDC_VSYNC + BOARD_LTDC_VBP - 1) +#define STM32_LTDC_LxWVPCR_WVSPPOS (BOARD_LTDC_VSYNC + BOARD_LTDC_VBP + \ + STM32_LTDC_HEIGHT - 1) + +/* LTDC_SSCR register */ + +#define STM32_LTDC_SSCR_VSH LTDC_SSCR_VSH(BOARD_LTDC_VSYNC - 1) +#define STM32_LTDC_SSCR_HSW LTDC_SSCR_HSW(BOARD_LTDC_HSYNC - 1) + +/* LTDC_BPCR register */ + +#define STM32_LTDC_BPCR_AVBP LTDC_BPCR_AVBP(STM32_LTDC_LxWVPCR_WVSTPOS) +#define STM32_LTDC_BPCR_AHBP LTDC_BPCR_AHBP(STM32_LTDC_LxWHPCR_WHSTPOS) + +/* LTDC_AWCR register */ + +#define STM32_LTDC_AWCR_AAH LTDC_AWCR_AAH(STM32_LTDC_LxWVPCR_WVSPPOS) +#define STM32_LTDC_AWCR_AAW LTDC_AWCR_AAW(STM32_LTDC_LxWHPCR_WHSPPOS) + +/* LTDC_TWCR register */ + +#define STM32_LTDC_TWCR_TOTALH LTDC_TWCR_TOTALH(BOARD_LTDC_VSYNC + \ + BOARD_LTDC_VBP + \ + STM32_LTDC_HEIGHT + BOARD_LTDC_VFP - 1) +#define STM32_LTDC_TWCR_TOTALW LTDC_TWCR_TOTALW(BOARD_LTDC_HSYNC + \ + BOARD_LTDC_HBP + \ + STM32_LTDC_WIDTH + BOARD_LTDC_HFP - 1) + +/* Global GCR register */ + +/* Synchronisation and Polarity */ + +#define STM32_LTDC_GCR_PCPOL BOARD_LTDC_GCR_PCPOL +#define STM32_LTDC_GCR_DEPOL BOARD_LTDC_GCR_DEPOL +#define STM32_LTDC_GCR_VSPOL BOARD_LTDC_GCR_VSPOL +#define STM32_LTDC_GCR_HSPOL BOARD_LTDC_GCR_HSPOL + +/* Dither */ + +#define STM32_LTDC_GCR_DEN BOARD_LTDC_GCR_DEN +#define STM32_LTDC_GCR_DBW LTDC_GCR_GBW(BOARD_LTDC_GCR_DBW) +#define STM32_LTDC_GCR_DGW LTDC_GCR_DGW(BOARD_LTDC_GCR_DGW) +#define STN32_LTDC_GCR_DRW LTDC_GCR_DBW(BOARD_LTDC_GCR_DRW) + +/* LIPCR register */ + +#define STM32_LTDC_LIPCR_LIPOS LTDC_LIPCR_LIPOS(STM32_LTDC_TWCR_TOTALW) + +/* Configuration ************************************************************/ + +#ifndef CONFIG_STM32_LTDC_DEFBACKLIGHT +# define CONFIG_STM32_LTDC_DEFBACKLIGHT 0xf0 +#endif +#define STM32_LTDC_BACKLIGHT_OFF 0x00 + +/* Color/video formats */ + +/* Layer 1 format */ + +#if defined(CONFIG_STM32_LTDC_L1_L8) +# define STM32_LTDC_L1_BPP 8 +# define STM32_LTDC_L1_COLOR_FMT FB_FMT_RGB8 +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_L8) +# define STM32_LTDC_L1CMAP +#elif defined(CONFIG_STM32_LTDC_L1_AL44) +# define STM32_LTDC_L1_BPP 8 +# define STM32_LTDC_L1_COLOR_FMT ??? +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_AL44) +#elif defined(CONFIG_STM32_LTDC_L1_AL88) +# define STM32_LTDC_L1_BPP 16 +# define STM32_LTDC_L1_COLOR_FMT ??? +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_AL88) +#elif defined(CONFIG_STM32_LTDC_L1_ARGB4444) +# define STM32_LTDC_L1_BPP 16 +# define STM32_LTDC_L1_COLOR_FMT ??? +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB4444) +#elif defined(CONFIG_STM32_LTDC_L1_RGB565) +# define STM32_LTDC_L1_BPP 16 +# define STM32_LTDC_L1_COLOR_FMT FB_FMT_RGB16_565 +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_RGB565) +#elif defined(CONFIG_STM32_LTDC_L1_ARGB1555) +# define STM32_LTDC_L1_BPP 16 +# define STM32_LTDC_L1_COLOR_FMT ??? +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB1555) +#elif defined(CONFIG_STM32_LTDC_L1_RGB888) +# define STM32_LTDC_L1_BPP 24 +# define STM32_LTDC_L1_COLOR_FMT FB_FMT_RGB24 +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_RGB888) +#elif defined(CONFIG_STM32_LTDC_L1_ARGB8888) +# define STM32_LTDC_L1_BPP 32 +# define STM32_LTDC_L1_COLOR_FMT ??? +# define STM32_LTDC_L1PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB8888) +#endif + +/* Layer 2 format */ + +#if defined(CONFIG_STM32_LTDC_L2_L8) +# define STM32_LTDC_L2_BPP 8 +# define STM32_LTDC_L2_COLOR_FMT FB_FMT_RGB8 +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_L8) +# define STM32_LTDC_L2CMAP +#elif defined(CONFIG_STM32_LTDC_L2_AL44) +# define STM32_LTDC_L2_BPP 8 +# define STM32_LTDC_L2_COLOR_FMT ??? +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_AL44) +#elif defined(CONFIG_STM32_LTDC_L2_AL88) +# define STM32_LTDC_L2_BPP 16 +# define STM32_LTDC_L2_COLOR_FMT ??? +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_AL88) +#elif defined(CONFIG_STM32_LTDC_L2_ARGB4444) +# define STM32_LTDC_L2_BPP 16 +# define STM32_LTDC_L2_COLOR_FMT ??? +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB4444) +#elif defined(CONFIG_STM32_LTDC_L2_RGB565) +# define STM32_LTDC_L2_BPP 16 +# define STM32_LTDC_L2_COLOR_FMT FB_FMT_RGB16_565 +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_RGB565) +#elif defined(CONFIG_STM32_LTDC_L2_ARGB1555) +# define STM32_LTDC_L2_BPP 16 +# define STM32_LTDC_L2_COLOR_FMT ??? +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB1555) +#elif defined(CONFIG_STM32_LTDC_L2_RGB888) +# define STM32_LTDC_L2_BPP 24 +# define STM32_LTDC_L2_COLOR_FMT FB_FMT_RGB24 +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_RGB888) +#elif defined(CONFIG_STM32_LTDC_L2_ARGB8888) +# define STM32_LTDC_L2_BPP 32 +# define STM32_LTDC_L2_COLOR_FMT ??? +# define STM32_LTDC_L2PFCR_PF LTDC_LxPFCR_PF(LTDC_PF_ARGB8888) +#endif + +/* Framebuffer sizes in bytes */ + +#if STM32_LTDC_L1_BPP == 8 +# define STM32_L1_STRIDE (STM32_LTDC_WIDTH) +#elif STM32_LTDC_L1_BPP == 16 +# define STM32_L1_STRIDE ((STM32_LTDC_WIDTH * 16 + 7) / 8) +#elif STM32_LTDC_L1_BPP == 24 +# define STM32_L1_STRIDE ((STM32_LTDC_WIDTH * 24 + 7) / 8) +#elif STM32_LTDC_L1_BPP == 32 +# define STM32_L1_STRIDE ((STM32_LTDC_WIDTH * 32 + 7) / 8) +#else +# error Undefined or unrecognized base resolution +#endif + +/* LTDC only supports 8 bit per pixel overal */ + +#define STM32_LTDC_Lx_BYPP(n) ((n) / 8) + +#define STM32_L1_FBSIZE (STM32_L1_STRIDE * STM32_LTDC_HEIGHT) + +#ifdef CONFIG_STM32_LTDC_L2 +# ifndef CONFIG_STM32_LTDC_L2_WIDTH +# define CONFIG_STM32_LTDC_L2_WIDTH STM32_LTDC_WIDTH +# endif + +# if CONFIG_STM32_LTDC_L2_WIDTH > STM32_LTDC_WIDTH +# error Width of Layer 2 exceeds the width of the display +# endif + +# ifndef CONFIG_STM32_LTDC_L2_HEIGHT +# define CONFIG_STM32_LTDC_L2_HEIGHT STM32_LTDC_HEIGHT +# endif + +# if CONFIG_STM32_LTDC_L2_HEIGHT > STM32_LTDC_HEIGHT +# error Height of Layer 2 exceeds the height of the display +# endif + +# if STM32_LTDC_L2_BPP == 8 +# define STM32_L2_STRIDE (CONFIG_STM32_LTDC_L2_WIDTH) +# elif STM32_LTDC_L2_BPP == 16 +# define STM32_L2_STRIDE ((CONFIG_STM32_LTDC_L2_WIDTH * 16 + 7) / 8) +# elif STM32_LTDC_L2_BPP == 24 +# define STM32_L2_STRIDE ((CONFIG_STM32_LTDC_L2_WIDTH * 24 + 7) / 8) +# elif STM32_LTDC_L2_BPP == 32 +# define STM32_L2_STRIDE ((CONFIG_STM32_LTDC_L2_WIDTH * 32 + 7) / 8) +# else +# error Undefined or unrecognized base resolution +# endif + +# define STM32_L2_FBSIZE (STM32_L2_STRIDE * CONFIG_STM32_LTDC_L2_HEIGHT) + +#else +# define STM32_L2_FBSIZE (0) +#endif + +/* Total memory used for framebuffers */ + +#define STM32_TOTAL_FBSIZE (STM32_L1_FBSIZE + STM32_L2_FBSIZE) + +/* Debug option */ + +#ifdef CONFIG_STM32_LTDC_REGDEBUG +# define regerr lcderr +# define reginfo lcdinfo +#else +# define regerr(x...) +# define reginfo(x...) +#endif + +/* Preallocated LTDC framebuffers */ + +/* Position the framebuffer memory in the center of the memory set aside. We + * will use any skirts before or after the framebuffer memory as a guard against + * wild framebuffer writes. + */ + +#define STM32_LTDC_BUFFER_SIZE CONFIG_STM32_LTDC_FB_SIZE +#define STM32_LTDC_BUFFER_FREE (STM32_LTDC_BUFFER_SIZE - STM32_TOTAL_FBSIZE) +#define STM32_LTDC_BUFFER_START (CONFIG_STM32_LTDC_FB_BASE + \ + STM32_LTDC_BUFFER_FREE/2) + +#if STM32_LTDC_BUFFER_FREE < 0 +# error "STM32_LTDC_BUFFER_SIZE not large enough for frame buffers" +#endif + +/* Layer frame buffer */ + +#define STM32_LTDC_BUFFER_L1 STM32_LTDC_BUFFER_START +#define STM32_LTDC_ENDBUF_L1 (STM32_LTDC_BUFFER_L1 + STM32_L1_FBSIZE) + +#ifdef CONFIG_STM32_LTDC_L2 +# define STM32_LTDC_BUFFER_L2 STM32_LTDC_ENDBUF_L1 +# define STM32_LTDC_ENDBUF_L2 (STM32_LTDC_BUFFER_L2 + STM32_L2_FBSIZE) +#else +# define STM32_LTDC_ENDBUF_L2 STM32_LTDC_ENDBUF_L1 +#endif + +/* Layer helpers */ + +#ifdef CONFIG_STM32_LTDC_L2 +# define LTDC_NLAYERS 2 +#else +# define LTDC_NLAYERS 1 +#endif + +#define LAYER(i) g_ltdc.layer[i] +#define LAYER_L1 g_ltdc.layer[LTDC_LAYER_L1] +#define LAYER_L2 g_ltdc.layer[LTDC_LAYER_L2] + +/* Dithering */ + +#ifndef CONFIG_STM32_LTDC_DITHER_RED +# define STM32_LTDC_DITHER_RED 0 +#else +# define STM32_LTDC_DITHER_RED CONFIG_STM32_LTDC_DITHER_RED +#endif +#ifndef CONFIG_STM32_LTDC_DITHER_GREEN +# define STM32_LTDC_DITHER_GREEN 0 +#else +# define STM32_LTDC_DITHER_GREEN CONFIG_STM32_LTDC_DITHER_GREEN +#endif +#ifndef CONFIG_STM32_LTDC_DITHER_BLUE +# define STM32_LTDC_DITHER_BLUE 0 +#else +# define STM32_LTDC_DITHER_BLUE CONFIG_STM32_LTDC_DITHER_BLUE +#endif + +/* Background color */ + +#ifndef CONFIG_STM32_LTDC_BACKCOLOR +# define STM32_LTDC_BACKCOLOR 0 +#else +# define STM32_LTDC_BACKCOLOR CONFIG_STM32_LTDC_BACKCOLOR +#endif + +/* Internal operation flags */ + +#define LTDC_LAYER_SETAREA (1 << 0) /* Change visible area */ +#define LTDC_LAYER_SETALPHAVALUE (1 << 1) /* Change constant alpha value */ +#define LTDC_LAYER_SETBLENDMODE (1 << 2) /* Change blendmode */ +#define LTDC_LAYER_SETCOLORKEY (1 << 3) /* Change color key */ +#define LTDC_LAYER_ENABLECOLORKEY (1 << 4) /* Enable colorkey */ +#define LTDC_LAYER_SETCOLOR (1 << 5) /* Change default color */ +#define LTDC_LAYER_SETENABLE (1 << 6) /* Change enabled state */ +#define LTDC_LAYER_ENABLE (1 << 7) /* Enable the layer */ + +/* Layer initializing state */ + +#define LTDC_LAYER_INIT LTDC_LAYER_SETAREA | \ + LTDC_LAYER_SETALPHAVALUE | \ + LTDC_LAYER_SETBLENDMODE | \ + LTDC_LAYER_SETCOLORKEY | \ + LTDC_LAYER_SETCOLOR | \ + LTDC_LAYER_SETENABLE | \ + LTDC_LAYER_ENABLE + +/* Blendfactor reset values for flip operation */ + +#define STM32_LTDC_BF1_RESET 6 +#define STM32_LTDC_BF2_RESET 7 + +/* Check pixel format support by DMA2D driver */ + +#ifdef CONFIG_STM32_DMA2D +# if defined(CONFIG_STM32_LTDC_L1_L8) || \ + defined(CONFIG_STM32_LTDC_L2_L8) +# if !defined(CONFIG_STM32_DMA2D_L8) +# error "DMA2D must support FB_FMT_RGB8 pixel format" +# endif +# endif +# if defined(CONFIG_STM32_LTDC_L1_RGB565) || \ + defined(CONFIG_STM32_LTDC_L2_RGB565) +# if !defined(CONFIG_STM32_DMA2D_RGB565) +# error "DMA2D must support FB_FMT_RGB16_565 pixel format" +# endif +# endif +# if defined(CONFIG_STM32_LTDC_L1_RGB888) || \ + defined(CONFIG_STM32_LTDC_L2_RGB888) +# if !defined(CONFIG_STM32_DMA2D_RGB888) +# error "DMA2D must support FB_FMT_RGB24 pixel format" +# endif +# endif +#endif + +/* Calculate the size of the layers clut table */ + +#ifdef CONFIG_FB_CMAP +# if defined(CONFIG_STM32_DMA2D) && !defined(CONFIG_STM32_DMA2D_L8) +# error "DMA2D must also support L8 CLUT pixel format if supported by LTDC" +# endif +# ifdef STM32_LTDC_L1CMAP +# ifdef CONFIG_FB_TRANSPARENCY +# define STM32_LAYER_CLUT_SIZE STM32_LTDC_NCLUT * sizeof(uint32_t) +# else +# define STM32_LAYER_CLUT_SIZE STM32_LTDC_NCLUT * 3 * sizeof(uint8_t) +# endif +# endif +# ifdef STM32_LTDC_L2CMAP +# undef STM32_LAYER_CLUT_SIZE +# ifdef CONFIG_FB_TRANSPARENCY +# define STM32_LAYER_CLUT_SIZE STM32_LTDC_NCLUT * sizeof(uint32_t) * 2 +# else +# define STM32_LAYER_CLUT_SIZE STM32_LTDC_NCLUT * 3 * sizeof(uint8_t) * 2 +# endif +# endif +#endif + +#ifndef CONFIG_FB_CMAP +# if defined(STM32_LTDC_L1CMAP) || defined(STM32_LTDC_L2CMAP) +# undef STM32_LTDC_L1CMAP +# undef STM32_LTDC_L2CMAP +# error "Enable cmap to support the configured layer format!" +# endif +#endif + +/* Layer clut rgb value positioning */ + +#define LTDC_L1CLUT_REDOFFSET 0 +#define LTDC_L1CLUT_GREENOFFSET 256 +#define LTDC_L1CLUT_BLUEOFFSET 512 +#define LTDC_L2CLUT_REDOFFSET 768 +#define LTDC_L2CLUT_GREENOFFSET 1024 +#define LTDC_L2CLUT_BLUEOFFSET 1280 + +/* Layer argb clut register position */ + +#define LTDC_CLUT_ADD(n) ((uint32_t)(n) << 24) +#define LTDC_CLUT_ALPHA(n) LTDC_CLUT_ADD(n) +#define LTDC_CLUT_RED(n) ((uint32_t)(n) << 16) +#define LTDC_CLUT_GREEN(n) ((uint32_t)(n) << 8) +#define LTDC_CLUT_BLUE(n) ((uint32_t)(n) << 0) +#define LTDC_CLUT_RGB888_MASK 0xffffff + +/* Layer argb cmap conversion */ + +#define LTDC_CMAP_ALPHA(n) ((uint32_t)(n) >> 24) +#define LTDC_CMAP_RED(n) ((uint32_t)(n) >> 16) +#define LTDC_CMAP_GREEN(n) ((uint32_t)(n) >> 8) +#define LTDC_CMAP_BLUE(n) ((uint32_t)(n) >> 0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This enumeration names each layer supported by the hardware */ + +enum stm32_layer_e +{ + LTDC_LAYER_L1 = 0, /* LCD Layer 1 */ + LTDC_LAYER_L2, /* LCD Layer 2 */ +}; + +/* LTDC General layer information */ + +struct stm32_layer_s +{ +#ifdef CONFIG_STM32_LTDC_INTERFACE + /* LTDC interface */ + + struct ltdc_layer_s ltdc; /* Layer control structure */ +#endif + + struct stm32_ltdc_s state; /* Layer state structure */ + + /* Blending */ + + uint8_t opac; /* Opacity value for blending */ + uint8_t bf1; /* Blend factor 1 */ + uint8_t bf2; /* Blend factor 2 */ + + /* Operation */ + + uint8_t operation; /* Operation flags */ +#ifdef CONFIG_STM32_DMA2D + FAR struct dma2d_layer_s *dma2d; /* dma2d interface */ +#endif +}; + +/* This structure provides the state of each LTDC layer */ + +struct stm32_state_s +{ + /* Layer state */ + + struct stm32_ltdc_s state[LTDC_NLAYERS]; +}; + +/* This structure provides the overall state of the LTDC layer */ + +struct stm32_ltdcdev_s +{ + /* Layer information */ + + struct stm32_layer_s layer[LTDC_NLAYERS]; +}; + +/* Layer cmap table description */ + +#ifdef STM32_LAYER_CLUT_SIZE +enum stm32_clut_e +{ + LTDC_L1CLUT_OFFSET = 0, + LTDC_L2CLUT_OFFSET = STM32_LTDC_NCLUT * sizeof(uint32_t) +}; +#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 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Global register operation */ + +static void stm32_lcd_enable(bool enable); +static void stm32_ltdc_gpioconfig(void); +static void stm32_ltdc_periphconfig(void); +static void stm32_ltdc_bgcolor(uint32_t rgb); +static void stm32_ltdc_dither(bool enable, uint8_t red, + uint8_t green, uint8_t blue); +static int stm32_ltdcirq(int irq, void *context, FAR void *arg); +static int stm32_ltdc_waitforirq(void); +static int stm32_ltdc_reload(uint8_t value, bool waitvblank); + +/* Layer and layer register operation */ + +static inline void stm32_ltdc_lsetopac(FAR struct stm32_layer_s *layer); +static inline void stm32_ltdc_lunsetopac(FAR struct stm32_layer_s *layer); +static inline uint8_t stm32_ltdc_lgetopac(FAR struct stm32_layer_s *layer); +static inline bool stm32_ltdc_lvalidate(FAR const struct stm32_layer_s *layer); +#ifdef CONFIG_STM32_LTDC_INTERFACE +static int stm32_ltdc_lvalidatearea(FAR struct stm32_layer_s *layer, + fb_coord_t xpos, fb_coord_t ypos, + fb_coord_t xres, fb_coord_t yres, + fb_coord_t srcxpos, fb_coord_t srcypos); +#endif +static void stm32_ltdc_lupdate(FAR struct stm32_layer_s *layer); + +static void stm32_ltdc_lpixelformat(FAR struct stm32_layer_s *layer); +static inline void stm32_ltdc_lframebuffer(FAR struct stm32_layer_s *layer); +static void stm32_ltdc_larea(FAR struct stm32_layer_s *layer); +static void stm32_ltdc_lcolor(FAR struct stm32_layer_s *layer, uint32_t argb); +static void stm32_ltdc_lcolorkey(FAR struct stm32_layer_s *layer); +static void stm32_ltdc_lalpha(FAR struct stm32_layer_s *layer); +static void stm32_ltdc_lblendmode(FAR struct stm32_layer_s *layer, + uint8_t bf1, uint8_t bf2); + +#ifdef STM32_LAYER_CLUT_SIZE +static void stm32_ltdc_lclut(FAR struct stm32_layer_s *layer, + FAR const struct fb_cmap_s *cmap); +static void stm32_ltdc_lclutenable(FAR struct stm32_layer_s *layer, + bool enable); +#endif +static void stm32_ltdc_linit(int lid); +static void stm32_ltdc_lenable(FAR struct stm32_layer_s *layer); +static void stm32_ltdc_lclear(FAR struct stm32_layer_s *layer, + nxgl_mxpixel_t color); + +/* Generic frame buffer interface */ + +static int stm32_getvideoinfo(FAR struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo); +static int stm32_getplaneinfo(FAR struct fb_vtable_s *vtable, + int planeno, struct fb_planeinfo_s *pinfo); + +/* The following is provided only if the video hardware supports RGB color + * mapping + */ + +#ifdef STM32_LAYER_CLUT_SIZE +static int stm32_getcmap(struct fb_vtable_s *vtable, + struct fb_cmap_s *cmap); +static int stm32_putcmap(struct fb_vtable_s *vtable, + const struct fb_cmap_s *cmap); +#endif + +/* ltdc interface */ + +#ifdef STM32_LAYER_CLUT_SIZE +static int stm32_setclut(struct ltdc_layer_s *layer, + const struct fb_cmap_s *cmap); +static int stm32_getclut(struct ltdc_layer_s *layer, + struct fb_cmap_s *cmap); +#endif +static int stm32_lgetvideoinfo(struct ltdc_layer_s *layer, + struct fb_videoinfo_s *vinfo); +static int stm32_lgetplaneinfo(struct ltdc_layer_s *layer, int planeno, + struct fb_planeinfo_s *pinfo); + +#ifdef CONFIG_STM32_LTDC_INTERFACE +static int stm32_getlid(FAR struct ltdc_layer_s *layer, + int *lid, uint32_t flag); +static int stm32_setcolor(FAR struct ltdc_layer_s *layer, uint32_t argb); +static int stm32_getcolor(FAR struct ltdc_layer_s *layer, uint32_t *argb); +static int stm32_setcolorkey(FAR struct ltdc_layer_s *layer, uint32_t argb); +static int stm32_getcolorkey(FAR struct ltdc_layer_s *layer, uint32_t *argb); +static int stm32_setalpha(FAR struct ltdc_layer_s *layer, uint8_t alpha); +static int stm32_getalpha(FAR struct ltdc_layer_s *layer, uint8_t *alpha); +static int stm32_setblendmode(FAR struct ltdc_layer_s *layer, uint32_t mode); +static int stm32_getblendmode(FAR struct ltdc_layer_s *layer, uint32_t *mode); +static int stm32_setarea(FAR struct ltdc_layer_s *layer, + FAR const struct ltdc_area_s *area, + fb_coord_t srcxpos, fb_coord_t srcypos); +static int stm32_getarea(FAR struct ltdc_layer_s *layer, + FAR struct ltdc_area_s *area, + fb_coord_t *srcxpos, fb_coord_t *srcypos); +static int stm32_update(FAR struct ltdc_layer_s *layer, uint32_t mode); + +#ifdef CONFIG_STM32_DMA2D +static int stm32_blit(FAR struct ltdc_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_blend(FAR struct ltdc_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_fillarea(FAR struct ltdc_layer_s *layer, + FAR const struct ltdc_area_s *area, + uint32_t color); +#endif +#endif /* CONFIG_STM32_LTDC_INTERFACE */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* PIO pin configurations */ + +static const uint32_t g_ltdcpins[] = +{ + GPIO_LTDC_R4, GPIO_LTDC_R5, GPIO_LTDC_R6, GPIO_LTDC_R7, + GPIO_LTDC_G4, GPIO_LTDC_G5, GPIO_LTDC_G6, GPIO_LTDC_G7, + GPIO_LTDC_B4, GPIO_LTDC_B5, GPIO_LTDC_B6, GPIO_LTDC_B7, +#if BOARD_LTDC_OUTPUT_BPP > 12 + GPIO_LTDC_R3, GPIO_LTDC_G2, GPIO_LTDC_G3, GPIO_LTDC_B3, +# if BOARD_LTDC_OUTPUT_BPP > 16 + GPIO_LTDC_R2, GPIO_LTDC_B2, +# if BOARD_LTDC_OUTPUT_BPP > 18 + GPIO_LTDC_R0, GPIO_LTDC_R1, GPIO_LTDC_G0, GPIO_LTDC_G1, + GPIO_LTDC_B0, GPIO_LTDC_B1, +# endif +# endif +#endif + GPIO_LTDC_VSYNC, GPIO_LTDC_HSYNC, GPIO_LTDC_DE, GPIO_LTDC_CLK +}; + +#define STM32_LTDC_NPINCONFIGS (sizeof(g_ltdcpins) / sizeof(uint32_t)) + +/* This structure provides the base layer interface */ + +static const struct fb_vtable_s g_vtable = +{ + .getvideoinfo = stm32_getvideoinfo, + .getplaneinfo = stm32_getplaneinfo +#ifdef STM32_LAYER_CLUT_SIZE + , + .getcmap = stm32_getcmap, + .putcmap = stm32_putcmap +#endif +}; + +/* The LTDC semaphore that enforces mutually exclusive access */ + +static sem_t g_lock; + +/* The 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_LTDCINT, + .sem = &g_semirq +}; + +/* The layer active state */ + +static uint8_t g_lactive; + +#ifdef STM32_LAYER_CLUT_SIZE +/* The layers clut table entries */ + +static uint32_t g_clut[STM32_LAYER_CLUT_SIZE]; +#endif + +/* The initialized state of the overall LTDC layers */ + +static struct stm32_ltdcdev_s g_ltdc = +{ + .layer[LTDC_LAYER_L1] = + { + .state = + { + .lid = LTDC_LAYER_L1, + .pinfo = + { + .fbmem = (uint8_t *)STM32_LTDC_BUFFER_L1, + .fblen = STM32_L1_FBSIZE, + .stride = STM32_L1_STRIDE, + .display = 0, + .bpp = STM32_LTDC_L1_BPP + }, + .vinfo = + { + .fmt = STM32_LTDC_L1_COLOR_FMT, + .xres = STM32_LTDC_WIDTH, + .yres = STM32_LTDC_HEIGHT, + .nplanes = 1 + } +#ifdef STM32_LTDC_L1CMAP + , .clut = &g_clut[LTDC_L1CLUT_OFFSET] +#endif + } + } +#ifdef CONFIG_STM32_LTDC_L2 + , + .layer[LTDC_LAYER_L2] = + { + .state = + { + .lid = LTDC_LAYER_L2, + .pinfo = + { + .fbmem = (uint8_t *)STM32_LTDC_BUFFER_L2, + .fblen = STM32_L2_FBSIZE, + .stride = STM32_L2_STRIDE, + .display = 1, + .bpp = STM32_LTDC_L2_BPP + }, + .vinfo = + { + .fmt = STM32_LTDC_L2_COLOR_FMT, + .xres = STM32_LTDC_WIDTH, + .yres = STM32_LTDC_HEIGHT, + .nplanes = 1 + } +#ifdef STM32_LTDC_L2CMAP + , .clut = &g_clut[LTDC_L2CLUT_OFFSET] +#endif + } + } +#endif +}; + +/* Pixel format lookup table */ + +static const uint32_t stm32_fmt_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1PFCR_PF +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2PFCR_PF +#endif +}; + +/* Register lookup tables */ + +/* LTDC_LxCR */ + +static const uintptr_t stm32_cr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CR +#endif +}; + +/* LTDC_LxWHPCR */ + +static const uintptr_t stm32_whpcr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1WHPCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2WHPCR +#endif +}; + +/* LTDC_LxWVPCR */ + +static const uintptr_t stm32_wvpcr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1WVPCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2WVPCR +#endif +}; + +/* LTDC_LxPFCR */ + +static const uintptr_t stm32_pfcr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1PFCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2PFCR +#endif +}; + +/* LTDC_LxDCCR */ + +static const uintptr_t stm32_dccr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1DCCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2DCCR +#endif +}; + +/* LTDC_LxCKCR */ + +static const uintptr_t stm32_ckcr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CKCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CKCR +#endif +}; + +/* LTDC_LxCACR */ + +static const uintptr_t stm32_cacr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CACR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CACR +#endif +}; + +/* LTDC_LxBFCR */ + +static const uintptr_t stm32_bfcr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1BFCR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2BFCR +#endif +}; + +/* LTDC_LxCFBAR */ + +static const uintptr_t stm32_cfbar_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CFBAR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CFBAR +#endif +}; + +/* LTDC_LxCFBLR */ + +static const uintptr_t stm32_cfblr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CFBLR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CFBLR +#endif +}; + +/* LTDC_LxCFBLNR */ + +static const uintptr_t stm32_cfblnr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CFBLNR +#ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CFBLNR +#endif +}; + +/* LTDC_LxCLUTWR */ + +#ifdef STM32_LAYER_CLUT_SIZE +static const uintptr_t stm32_clutwr_layer_t[LTDC_NLAYERS] = +{ + STM32_LTDC_L1CLUTWR +# ifdef CONFIG_STM32_LTDC_L2 + , STM32_LTDC_L2CLUTWR +# endif +}; +#endif + +/* The initialized state of the driver */ + +static bool g_initialized; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Configure global register + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_ltdc_gpioconfig + * + * Description: + * Configure GPIO pins for use with the LTDC + * + ****************************************************************************/ + +static void stm32_ltdc_gpioconfig(void) +{ + int i; + + lcdinfo("Configuring pins\n"); + + /* Configure each pin */ + + for (i = 0; i < STM32_LTDC_NPINCONFIGS; i++) + { + reginfo("set gpio%d = %08x\n", i, g_ltdcpins[i]); + stm32_configgpio(g_ltdcpins[i]); + } +} + +/**************************************************************************** + * Name: stm32_ltdc_periphconfig + * + * Description: + * Configures the synchronous timings + * Configures the synchronous signals and clock polarity + * + ****************************************************************************/ + +static void stm32_ltdc_periphconfig(void) +{ + uint32_t regval; + + /* Configure GPIO's */ + + stm32_ltdc_gpioconfig(); + + /* Configure APB2 LTDC clock external */ + + reginfo("configured RCC_APB2ENR=%08x\n", getreg32(STM32_RCC_APB2ENR)); + + /* Configure the SAI PLL external to provide the LCD_CLK */ + + reginfo("configured RCC_PLLSAI=%08x\n", getreg32(STM32_RCC_PLLSAICFGR)); + + /* Configure dedicated clock external */ + + reginfo("configured RCC_DCKCFGR=%08x\n", getreg32(STM32_RCC_DCKCFGR)); + + /* Configure LTDC_SSCR */ + + regval = (STM32_LTDC_SSCR_VSH | STM32_LTDC_SSCR_HSW); + reginfo("set LTDC_SSCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_SSCR); + reginfo("configured LTDC_SSCR=%08x\n", getreg32(STM32_LTDC_SSCR)); + + /* Configure LTDC_BPCR */ + + regval = (STM32_LTDC_BPCR_AVBP | STM32_LTDC_BPCR_AHBP); + reginfo("set LTDC_BPCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_BPCR); + reginfo("configured LTDC_BPCR=%08x\n", getreg32(STM32_LTDC_BPCR)); + + /* Configure LTDC_AWCR */ + + regval = (STM32_LTDC_AWCR_AAH | STM32_LTDC_AWCR_AAW); + reginfo("set LTDC_AWCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_AWCR); + reginfo("configured LTDC_AWCR=%08x\n", getreg32(STM32_LTDC_AWCR)); + + /* Configure LTDC_TWCR */ + + regval = (STM32_LTDC_TWCR_TOTALH | STM32_LTDC_TWCR_TOTALW); + reginfo("set LTDC_TWCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_TWCR); + reginfo("configured LTDC_TWCR=%08x\n", getreg32(STM32_LTDC_TWCR)); + + /* Configure LTDC_GCR */ + + regval = (STM32_LTDC_GCR_PCPOL | STM32_LTDC_GCR_DEPOL + | STM32_LTDC_GCR_VSPOL | STM32_LTDC_GCR_HSPOL); + reginfo("set LTDC_GCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_GCR); + reginfo("configured LTDC_GCR=%08x\n", getreg32(STM32_LTDC_GCR)); +} + +/**************************************************************************** + * Name: stm32_ltdc_bgcolor + * + * Description: + * Configures background color of the LCD controller. + * + * Parameter: + * rgb - RGB888 background color + * + ****************************************************************************/ + +static void stm32_ltdc_bgcolor(uint32_t rgb) +{ + reginfo("set LTDC_BCCR=%08x\n", rgb); + putreg32(rgb, STM32_LTDC_BCCR); + reginfo("configured LTDC_BCCR=%08x\n", getreg32(STM32_LTDC_BCCR)); +} + +/**************************************************************************** + * Name: stm32_ltdc_dither + * + * Description: + * Configures dither settings of the LCD controller. + * + * Parameter: + * enable - Enable dithering + * red - Red dither width + * green - Green dither width + * blue - Blue dither width + * + ****************************************************************************/ + +static void stm32_ltdc_dither(bool enable, + uint8_t red, + uint8_t green, + uint8_t blue) +{ + uint32_t regval; + + regval = getreg32(STM32_LTDC_GCR); + + if (enable == true) + { + regval |= LTDC_GCR_DEN; + } + else + { + regval &= ~LTDC_GCR_DEN; + } + + regval &= ~(!LTDC_GCR_DEN | LTDC_GCR_DRW(0) | + LTDC_GCR_DGW(0) | LTDC_GCR_DBW(0)); + regval |= (LTDC_GCR_DRW(red) | LTDC_GCR_DGW(green) | LTDC_GCR_DBW(blue)); + + reginfo("set LTDC_GCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_GCR); + reginfo("configured LTDC_GCR=%08x\n", getreg32(STM32_LTDC_GCR)); +} + +/**************************************************************************** + * Name: stm32_ltdc_linepos + * + * Description: + * Configures line position register + * + ****************************************************************************/ + +static void stm32_ltdc_linepos(void) +{ + /* Configure LTDC_LIPCR */ + + reginfo("set LTDC_LIPCR=%08x\n", STM32_LTDC_LIPCR_LIPOS); + putreg32(STM32_LTDC_LIPCR_LIPOS, STM32_LTDC_LIPCR); + reginfo("configured LTDC_LIPCR=%08x\n", getreg32(STM32_LTDC_LIPCR)); +} + +/**************************************************************************** + * Name: stm32_ltdc_irqctrl + * + * Description: + * Control interrupts generated by the ltdc controller + * + * Parameter: + * setirqs - set interrupt mask + * clrirqs - clear interrupt mask + * + ****************************************************************************/ + +static void stm32_ltdc_irqctrl(uint32_t setirqs, uint32_t clrirqs) +{ + uint32_t regval; + + regval = getreg32(STM32_LTDC_IER); + regval &= ~clrirqs; + regval |= setirqs; + reginfo("set LTDC_IER=%08x\n", regval); + putreg32(regval, STM32_LTDC_IER); + reginfo("configured LTDC_IER=%08x\n", getreg32(STM32_LTDC_IER)); +} + +/**************************************************************************** + * Name: stm32_ltdcirq + * + * Description: + * LTDC interrupt handler + * + ****************************************************************************/ + +static int stm32_ltdcirq(int irq, void *context, FAR void *arg) +{ + FAR struct stm32_interrupt_s *priv = &g_interrupt; + + uint32_t regval = getreg32(STM32_LTDC_ISR); + + reginfo("irq = %d, regval = %08x\n", irq, regval); + + if (regval & LTDC_ISR_RRIF) + { + /* Register reload interrupt */ + + /* Clear the interrupt status register */ + + putreg32(LTDC_ICR_CRRIF, STM32_LTDC_ICR); + + /* Update the handled flag */ + + priv->handled = true; + + /* Unlock the semaphore if locked */ + + if (priv->wait) + { + int ret = sem_post(priv->sem); + + if (ret != OK) + { + lcderr("ERROR: sem_post() failed\n"); + return ret; + } + } + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_ltdc_waitforirq + * + * Description: + * Helper waits until the ltdc irq occurs. In the current design That means + * that a register reload was been completed. + * Note! The caller must use this function within a critical section. + * + * Return: + * OK - On success otherwise ERROR + * + ****************************************************************************/ + +static int stm32_ltdc_waitforirq(void) +{ + int ret = OK; + FAR struct stm32_interrupt_s *priv = &g_interrupt; + + irqstate_t flags; + + flags = enter_critical_section(); + + /* Only waits if last enabled interrupt is currently not handled */ + + if (!priv->handled) + { + /* 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) + { + lcderr("ERROR: sem_wait() failed\n"); + } + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: stm32_ltdc_reload + * + * Description: + * Reload the layer shadow register and make layer changes visible. + * Note! The caller must ensure that a previous register reloading has been + * completed. + * + * Parameter: + * value - Reload flag (e.g. upon vertical blank or immediately) + * waitvblank - Wait until register reload is finished + * + ****************************************************************************/ + +static int stm32_ltdc_reload(uint8_t value, bool waitvblank) +{ + int ret = OK; + FAR struct stm32_interrupt_s *priv = &g_interrupt; + + if (value == LTDC_SRCR_VBR) + { + irqstate_t flags; + + /* Prepare shadow register reload for later detection by the task. + * At this point the last register reload must be completed. This is done + * in stm32_update before the next operation is triggered and manipulates + * the shadow register. This handling is only neccessary in the case of + * the application causes shadow register reload. + */ + + flags = enter_critical_section(); + + ASSERT(priv->handled == true); + + /* Reset the handled flag */ + + priv->handled = false; + leave_critical_section(flags); + } + + /* Reloads the shadow register. + * Note! This will not trigger an register reload interrupt if + * immediately reload is set. + */ + + reginfo("set LTDC_SRCR=%08x\n", value); + putreg32(value, STM32_LTDC_SRCR); + reginfo("configured LTDC_SRCR=%08x\n", getreg32(STM32_LTDC_SRCR)); + + if (waitvblank & (value == LTDC_SRCR_VBR)) + { + /* Wait upon vertical blanking period */ + + ret = stm32_ltdc_waitforirq(); + } + + /* Otherwise check if reload is completed before the next operation */ + + return ret; +} + +/**************************************************************************** + * Name: stm32_global_configure + * + * Description: + * Configure background color + * Configure interrupts + * Configure dithering + * + ****************************************************************************/ + +static void stm32_global_configure(void) +{ + /* Initialize the LTDC semaphore that enforces mutually exclusive access */ + + sem_init(&g_lock, 0, 1); + + /* Initialize the semaphore for interrupt handling. This waitsem + * semaphore is used for signaling and, hence, should not have priority + * inheritance enabled. + */ + + sem_init(g_interrupt.sem, 0, 0); + sem_setprotocol(g_interrupt.sem, SEM_PRIO_NONE); + + /* Attach LTDC interrupt vector */ + + (void)irq_attach(g_interrupt.irq, stm32_ltdcirq, NULL); + + /* Enable the IRQ at the NVIC */ + + up_enable_irq(g_interrupt.irq); + + /* Enable register reload interrupt only */ + + stm32_ltdc_irqctrl(LTDC_IER_RRIE, LTDC_IER_TERRIE | LTDC_IER_FUIE | LTDC_IER_LIE); + + /* Configure line interrupt */ + + stm32_ltdc_linepos(); + + /* Set the default active layer */ + +#ifndef CONFIG_STM32_LTDC_L2 + g_lactive = LTDC_LAYER_L1; +#else + g_lactive = LTDC_LAYER_L2; +#endif + +#ifdef STM32_LAYER_CLUT_SIZE + /* cleanup clut */ + + memset(g_clut, 0, sizeof(g_clut)); +#endif + + /* Configure dither */ + + stm32_ltdc_dither( +#ifdef CONFIG_STM32_LTDC_DITHER + true, +#else + false, +#endif + STM32_LTDC_DITHER_RED, + STM32_LTDC_DITHER_GREEN, + STM32_LTDC_DITHER_BLUE); + + /* Configure background color of the controller */ + + stm32_ltdc_bgcolor(STM32_LTDC_BACKCOLOR); +} + +/**************************************************************************** + * Name: stm32_lcd_enable + * + * Description: + * Disable the LCD peripheral + * + * Parameter: + * enable - Enable or disable + * + ****************************************************************************/ + +static void stm32_lcd_enable(bool enable) +{ + uint32_t regval; + + regval = getreg32(STM32_LTDC_GCR); + reginfo("get LTDC_GCR=%08x\n", regval); + + if (enable == true) + { + regval |= LTDC_GCR_LTDCEN; + } + else + { + regval &= ~LTDC_GCR_LTDCEN; + } + + reginfo("set LTDC_GCR=%08x\n", regval); + putreg32(regval, STM32_LTDC_GCR); + reginfo("configured LTDC_GCR=%08x\n", getreg32(STM32_LTDC_GCR)); +} + +/**************************************************************************** + * Configure layer register + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_ltdc_lclutenable + * + * Description: + * Disable or enable the layer clut support + * + * Parameter: + * layer - Reference to the layer control structure + * enable - Enable or disable + * + ****************************************************************************/ + +#ifdef STM32_LAYER_CLUT_SIZE +static void stm32_ltdc_lclutenable(FAR struct stm32_layer_s *layer, bool enable) +{ + uint32_t regval; + + regval = getreg32(stm32_cr_layer_t[layer->state.lid]); + reginfo("get LTDC_L%dCR=%08x\n", layer->state.lid + 1, regval); + + /* Disable the clut support during update the color table */ + + if (enable == true) + { + regval |= LTDC_LxCR_CLUTEN; + } + else + { + regval &= ~LTDC_LxCR_CLUTEN; + } + + reginfo("set LTDC_L%dCR=%08x\n", layer->state.lid + 1, regval); + putreg32(regval, stm32_cr_layer_t[layer->state.lid]); +} +#endif + +/**************************************************************************** + * Name: stm32_ltdc_lsetopac + * + * Description: + * Helper to set the layer to opac + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static inline void stm32_ltdc_lsetopac(FAR struct stm32_layer_s *layer) +{ + layer->opac = 0xff; +} + +/**************************************************************************** + * Name: stm32_ltdc_lunsetopac + * + * Description: + * Helper to set the layer opacity to the alpha value + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static inline void stm32_ltdc_lunsetopac(FAR struct stm32_layer_s *layer) +{ + layer->opac = 0; +} + +/**************************************************************************** + * Name: stm32_ltdc_lgetopac + * + * Description: + * Helper to get the configured layer opacity + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static inline uint8_t stm32_ltdc_lgetopac(FAR struct stm32_layer_s *layer) +{ + return layer->opac | layer->state.alpha; +} + +/**************************************************************************** + * Name: stm32_ltdc_lvalidate + * + * Description: + * Helper to check if the layer is an valid ltdc layer + * + * Parameter: + * layer - Reference to the layer control structure + * + * Return: + * true - layer valid + * false - layer invalid + * + ****************************************************************************/ + +static inline bool stm32_ltdc_lvalidate(FAR const struct stm32_layer_s *layer) +{ +#ifdef CONFIG_STM32_LTDC_L2 + return layer == &LAYER_L1 || layer == &LAYER_L2; +#else + return layer == &LAYER_L1; +#endif +} + +/**************************************************************************** + * Name: stm32_ltdc_lvalidatearea + * + * Description: + * Check if layer coordinates out of valid area. + * + * Parameter: + * layer - Reference to the layer control structure + * xpos - top left x position of the active area + * ypos - top left y position of the active area + * xres - width of the active area + * yres - height of teh active area + * srcxpos - Top left x position from where data visible in the active area + * srcypos - Top left y position from where data visible in the active area + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_LTDC_INTERFACE +static int stm32_ltdc_lvalidatearea(FAR struct stm32_layer_s *layer, + fb_coord_t xpos, fb_coord_t ypos, + fb_coord_t xres, fb_coord_t yres, + fb_coord_t srcxpos, fb_coord_t srcypos) +{ + FAR const struct fb_videoinfo_s *vinfo = &layer->state.vinfo; + + if ((xpos > vinfo->xres - 1) || + (ypos > vinfo->yres -1) || + (xres > vinfo->xres - xpos) || + (yres > vinfo->yres - ypos) || + (srcxpos > xpos + xres - 1) || + (srcypos > ypos + yres - 1)) + + { + lcderr("ERROR: layer coordinates out of valid area: xpos = %d > %d, \ + ypos = %d > %d, width = %d > %d, height = %d > %d, \ + srcxpos = %d > %d, srcypos = %d > %d", + xpos, vinfo->xres - 1, + ypos, vinfo->yres - 1, + xres, vinfo->xres - xpos, + yres, vinfo->yres - ypos, + srcxpos, xpos + xres - 1, + srcypos, ypos + yres - 1); + + lcderr(" Returning EINVAL\n"); + return -EINVAL; + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: stm32_ltdc_lupdate + * + * Description: + * Updates shadow register content depending on the layer operation flag. + * This made changes for the given layer visible after the next shadow + * register reload. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lupdate(FAR struct stm32_layer_s *layer) +{ + if (layer->operation & LTDC_LAYER_SETAREA) + { + /* Updates the layer horizontal and vertical position register */ + + stm32_ltdc_larea(layer); + } + + if (layer->operation & LTDC_LAYER_SETALPHAVALUE) + { + /* Updates the constant alpha register */ + + stm32_ltdc_lalpha(layer); + } + + if (layer->operation & LTDC_LAYER_SETBLENDMODE) + { + /* Update blendfactor 1 and 2 register */ + + stm32_ltdc_lblendmode(layer, layer->bf1, layer->bf2); + } + + if (layer->operation & LTDC_LAYER_SETCOLORKEY) + { + /* Update layer colorkey register */ + + stm32_ltdc_lcolorkey(layer); + } + + if (layer->operation & LTDC_LAYER_SETCOLOR) + { + /* Update layer color register */ + + stm32_ltdc_lcolor(layer, layer->state.color); + } + + if (layer->operation & LTDC_LAYER_SETENABLE) + { + /* Enable the layer */ + + stm32_ltdc_lenable(layer); + } +} + +/**************************************************************************** + * Name: stm32_ltdc_larea + * + * Description: + * Change the active area of the layer + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_larea(struct stm32_layer_s *layer) +{ + uint32_t lxpos; + uint32_t lypos; + uint32_t whpcr; + uint32_t wvpcr; + FAR struct stm32_ltdc_s *priv = &layer->state; + FAR struct ltdc_area_s *area = &priv->area; + + reginfo("xpos = %d, ypos = %d, xres = %d, yres = %d\n", + area->xpos, area->ypos, area->xres, area->yres); + + lxpos = area->xpos + (STM32_LTDC_LxWHPCR_WHSTPOS + 1); + lypos = area->ypos + (STM32_LTDC_LxWVPCR_WVSTPOS + 1); + + /* Accumulate horizontal position */ + + whpcr = LTDC_LxWHPCR_WHSTPOS(lxpos); + whpcr |= LTDC_LxWHPCR_WHSPPOS(lxpos + area->xres - 1); + + /* Accumulate vertical position */ + + wvpcr = LTDC_LxWVPCR_WVSTPOS(lypos); + wvpcr |= LTDC_LxWVPCR_WVSPPOS(lypos + area->yres - 1); + + /* Configure LxWHPCR / LxWVPCR register */ + + reginfo("set LTDC_L%dWHPCR=%08x\n", priv->lid + 1, whpcr); + putreg32(whpcr, stm32_whpcr_layer_t[priv->lid]); + reginfo("set LTDC_L%dWVPCR=%08x\n", priv->lid + 1, wvpcr); + putreg32(wvpcr, stm32_wvpcr_layer_t[priv->lid]); + + /* Configure framebuffer */ + + stm32_ltdc_lframebuffer(layer); + + /* Clear area operation flag */ + + layer->operation &= ~LTDC_LAYER_SETAREA; +} + +/**************************************************************************** + * Name: stm32_ltdc_lpixelformat + * + * Description: + * Set the layer pixel format. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lpixelformat(FAR struct stm32_layer_s *layer) +{ + /* Configure PFCR register */ + + reginfo("set LTDC_L%dPFCR=%08x\n", layer->state.lid + 1, + stm32_fmt_layer_t[layer->state.lid]); + putreg32(stm32_fmt_layer_t[layer->state.lid], + stm32_pfcr_layer_t[layer->state.lid]); +} + +/**************************************************************************** + * Name: stm32_ltdc_framebuffer + * + * Description: + * Change layer framebuffer offset. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * Reference to the layer control structure + * + ****************************************************************************/ + +static inline void stm32_ltdc_lframebuffer(FAR struct stm32_layer_s *layer) +{ + uint32_t offset; + uint32_t cfblr; + FAR struct stm32_ltdc_s *priv = &layer->state; + FAR struct ltdc_area_s *area = &priv->area; + FAR const struct fb_planeinfo_s *pinfo = &priv->pinfo; + + /* Configure LxCFBAR register */ + + /* Calculate offset position in the framebuffer */ + + offset = priv->xpos * STM32_LTDC_Lx_BYPP(pinfo->bpp) + + pinfo->stride * priv->ypos; + + reginfo("set LTDC_L%dCFBAR=%08x\n", priv->lid + 1, pinfo->fbmem + offset); + putreg32((uint32_t)pinfo->fbmem + offset, stm32_cfbar_layer_t[priv->lid]); + + /* Configure LxCFBLR register */ + + /* Calculate line length */ + + cfblr = LTDC_LxCFBLR_CFBP(pinfo->stride) | + LTDC_LxCFBLR_CFBLL(area->xres * STM32_LTDC_Lx_BYPP(pinfo->bpp) + 3); + + reginfo("set LTDC_L%dCFBLR=%08x\n", priv->lid + 1, cfblr); + putreg32(cfblr, stm32_cfblr_layer_t[priv->lid]); + + /* Configure LxCFBLNR register */ + + reginfo("set LTDC_L%dCFBLNR=%08x\n", priv->lid + 1, area->yres); + putreg32(area->yres, stm32_cfblnr_layer_t[priv->lid]); +} + +/**************************************************************************** + * Name: stm32_ltdc_lalpha + * + * Description: + * Change the layer alpha value and clear the alpha operation flag. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lalpha(FAR struct stm32_layer_s *layer) +{ + uint8_t opac = stm32_ltdc_lgetopac(layer); + reginfo("set LTDC_L%dCACR=%02x\n", layer->state.lid + 1, opac); + putreg32(opac, stm32_cacr_layer_t[layer->state.lid]); + + /* Clear the constant alpha operation flag */ + + layer->operation &= ~LTDC_LAYER_SETALPHAVALUE; +} + +/**************************************************************************** + * Name: stm32_ltdc_blendfactor + * + * Description: + * Change layer blend factors used for blend operation and clear the + * blendmode operation flag. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * layer - Reference to the laxer control structure + * bf1 - Value of blend factor 1 + * bf2 - Value of blend factor 2 + * + ****************************************************************************/ + +static void stm32_ltdc_lblendmode(FAR struct stm32_layer_s *layer, + uint8_t bf1, uint8_t bf2) +{ + reginfo("set LTDC_L%dBFCR=%08x\n", layer->state.lid + 1, + (LTDC_LxBFCR_BF1(bf1) | LTDC_LxBFCR_BF2(bf2))); + putreg32((LTDC_LxBFCR_BF1(bf1) | LTDC_LxBFCR_BF2(bf2)), + stm32_bfcr_layer_t[layer->state.lid]); + + /* Clear the blendmode operation flag */ + + layer->operation &= ~LTDC_LAYER_SETBLENDMODE; +} + +/**************************************************************************** + * Name: stm32_ltdc_lcolor + * + * Description: + * Change layer default color and clear the color operation flag. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lcolor(FAR struct stm32_layer_s *layer, uint32_t argb) +{ + reginfo("set LTDC_L%dDCCR=%08x\n", layer->state.lid + 1, argb); + putreg32(argb, stm32_dccr_layer_t[layer->state.lid]); + + /* Clear the color operation flag */ + + layer->operation &= ~LTDC_LAYER_SETCOLOR; +} + +/**************************************************************************** + * Name: stm32_ltdc_lcolorkey + * + * Description: + * Change layer colorkey and clear the colorkey operation flag. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lcolorkey(FAR struct stm32_layer_s *layer) +{ + uint32_t regval; + + regval = getreg32(stm32_cr_layer_t[layer->state.lid]); + + if (layer->operation & LTDC_LAYER_ENABLECOLORKEY) + { + /* Set colorkey */ + + reginfo("set LTDC_L%dCKCR=%08x\n", + layer->state.lid + 1, layer->state.colorkey); + putreg32(layer->state.colorkey, stm32_ckcr_layer_t[layer->state.lid]); + + /* Enable colorkey */ + + regval |= LTDC_LxCR_COLKEN; + } + else + { + /* Disable colorkey */ + + regval &= ~LTDC_LxCR_COLKEN; + } + + reginfo("set LTDC_L%dCR=%08x\n", layer->state.lid + 1, regval); + putreg32(regval, stm32_cr_layer_t[layer->state.lid]); + + /* Clear the colorkey operation flag */ + + layer->operation &= ~LTDC_LAYER_SETCOLORKEY; +} + +/**************************************************************************** + * Name: stm32_ltdc_lclut + * + * Description: + * Update the clut layer register during blank period. + * Note! The clut register are no shadow register. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +#ifdef STM32_LAYER_CLUT_SIZE +static void stm32_ltdc_lclut(FAR struct stm32_layer_s *layer, + FAR const struct fb_cmap_s *cmap) +{ + int n; + uint32_t regval; + uint32_t *clut; + irqstate_t flags; + + /* Disable clut during register update */ + + stm32_ltdc_lclutenable(layer, false); + + /* Set the clut memory address */ + + clut = layer->state.clut; + + /* Reload shadow control register. + * This never changed any layer setting as long the layer register not up to + * date. This is what stm32_update does. + */ + + stm32_ltdc_reload(LTDC_SRCR_IMR, false); + + flags = enter_critical_section(); + + /* Update the clut registers */ + + for (n = cmap->first; n < cmap->len && n < STM32_LTDC_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]; + + regval = (uint32_t)LTDC_CLUT_BLUE(clut888[offset]) | + (uint32_t)LTDC_CLUT_GREEN(clut888[offset + 1]) | + (uint32_t)LTDC_CLUT_RED(clut888[offset + 2]) | + (uint32_t)LTDC_CLUT_ADD(n); +#else + clut[n] = (uint32_t)LTDC_CLUT_ALPHA(cmap->transp[n]) | + (uint32_t)LTDC_CLUT_RED(cmap->red[n]) | + (uint32_t)LTDC_CLUT_GREEN(cmap->green[n]) | + (uint32_t)LTDC_CLUT_BLUE(cmap->blue[n]); + regval = (uint32_t)LTDC_CLUT_ADD(n) | (clut[n] & LTDC_CLUT_RGB888_MASK); +#endif + + + reginfo("set LTDC_L%dCLUTWR = %08x, cmap->first = %d, cmap->len = %d\n", + layer->state.lid + 1, regval, cmap->first, cmap->len); + putreg32(regval, stm32_clutwr_layer_t[layer->state.lid]); + } + + leave_critical_section(flags); + + /* Enable clut */ + + stm32_ltdc_lclutenable(layer, true); + + /* Reload shadow control register */ + + stm32_ltdc_reload(LTDC_SRCR_IMR, false); +} +#endif + +/**************************************************************************** + * Name: stm32_ltdc_lenable + * + * Description: + * Disable or enable specific layer. + * Note! This changes have no effect until the shadow register reload has + * been done. + * + * Parameter: + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_lenable(FAR struct stm32_layer_s *layer) +{ + uint32_t regval; + + /* Enable or disable layer */ + + regval = getreg32(stm32_cr_layer_t[layer->state.lid]); + + if (layer->operation & LTDC_LAYER_ENABLE) + { + regval |= LTDC_LxCR_LEN; + } + else + { + regval &= ~LTDC_LxCR_LEN; + } + + reginfo("set LTDC_L%dCR=%08x\n", layer->state.lid + 1, regval); + putreg32(regval, stm32_cr_layer_t[layer->state.lid]); + + /* Clear the enable operation flag */ + + layer->operation &= ~LTDC_LAYER_SETENABLE; +} + +/**************************************************************************** + * Name stm32_ltdc_lclear + * + * Description: + * Clear the whole layer + * + * Parameter: + * layer - Reference to the layer control structure + * color - The color to clear + * + * Return: + * OK - On success + * -EINVAL - If one of the parameter invalid + * + ****************************************************************************/ + +static void stm32_ltdc_lclear(FAR struct stm32_layer_s *layer, + nxgl_mxpixel_t color) +{ + FAR struct stm32_ltdc_s *priv = &layer->state; + +#if STM32_LTDC_L1_BPP == 8 || STM32_LTDC_L2_BPP == 8 + if (priv->pinfo.bpp == 8) + { + uint8_t *dest = (uint8_t *)priv->pinfo.fbmem; + int i; + + lcdinfo("Clearing display: BPP=%d color=%04x framebuffer=%08x size=%d\n", + priv->pinfo.bpp, color, dest, priv->pinfo.fblen); + + for (i = 0; i < priv->pinfo.fblen; i += sizeof(uint8_t)) + { + *dest++ = (uint8_t)color; + } + + return; + } +#endif + +#if STM32_LTDC_L1_BPP == 16 || STM32_LTDC_L2_BPP == 16 + if (priv->pinfo.bpp == 16) + { + uint16_t *dest = (uint16_t *)priv->pinfo.fbmem; + int i; + + lcdinfo("Clearing display: BPP=%d color=%04x framebuffer=%08x size=%d\n", + priv->pinfo.bpp, color, dest, priv->pinfo.fblen); + + for (i = 0; i < priv->pinfo.fblen; i += sizeof(uint16_t)) + { + *dest++ = (uint16_t)color; + } + + return; + } +#endif + +#if STM32_LTDC_L1_BPP == 24 || STM32_LTDC_L2_BPP == 24 + if (priv->pinfo.bpp == 24) + { + uint8_t *dest = (uint8_t *)priv->pinfo.fbmem; + uint8_t r; + uint8_t g; + uint8_t b; + int i; + + lcdinfo("Clearing display: BPP=%d color=%04x framebuffer=%08x size=%d\n", + priv->pinfo.bpp, color, dest, priv->pinfo.fblen); + + r = (uint8_t) color; + g = (uint8_t) (color >> 8); + b = (uint8_t) (color >> 16); + + for (i = 0; i < priv->pinfo.fblen; i += 3*sizeof(uint8_t)) + { + *dest++ = r; + *dest++ = g; + *dest++ = b; + } + + return; + } +#endif + +#if STM32_LTDC_L1_BPP == 32 || STM32_LTDC_L2_BPP == 32 + if (priv->pinfo.bpp == 32) + { + uint32_t *dest = (uint32_t *)priv->pinfo.fbmem; + int i; + + lcdinfo("Clearing display: BPP=%d color=%04x framebuffer=%08x size=%d\n", + priv->pinfo.bpp, color, dest, priv->pinfo.fblen); + + for (i = 0; i < priv->pinfo.fblen; i += sizeof(uint32_t)) + { + *dest++ = (uint32_t)color; + } + } +#endif +} + +/**************************************************************************** + * Name: stm32_ltdc_linit + * + * Description: + * Initialize layer to their default states. + * + * Initialize: + * - Reset layer + * - layer fram + * - Reset layerebuffers + * - layer position + * - layer pixelformat + * - layer color + * - layer colorkey + * - layer alpha + * - layer blendmode + * - layer dma2d interface binding + * + * Parameter + * layer - Reference to the layer control structure + * + ****************************************************************************/ + +static void stm32_ltdc_linit(int lid) +{ + /* Reset layer to their default state */ + + FAR struct stm32_layer_s *layer = &LAYER(lid); + FAR struct stm32_ltdc_s *state = &layer->state; +#ifdef CONFIG_STM32_LTDC_INTERFACE + FAR struct ltdc_layer_s *ltdc = &layer->ltdc; + + /* Initialize the ltdc interface */ + + ltdc->getlid = stm32_getlid; + ltdc->getvideoinfo = stm32_lgetvideoinfo; + ltdc->getplaneinfo = stm32_lgetplaneinfo; +# ifdef STM32_LAYER_CLUT_SIZE + ltdc->setclut = stm32_setclut; + ltdc->getclut = stm32_getclut; +#endif + ltdc->setcolor = stm32_setcolor; + ltdc->getcolor = stm32_getcolor; + ltdc->setcolorkey = stm32_setcolorkey; + ltdc->getcolorkey = stm32_getcolorkey; + ltdc->setalpha = stm32_setalpha; + ltdc->getalpha = stm32_getalpha; + ltdc->setblendmode = stm32_setblendmode; + ltdc->getblendmode = stm32_getblendmode; + ltdc->setarea = stm32_setarea; + ltdc->getarea = stm32_getarea; + ltdc->update = stm32_update; +#ifdef CONFIG_STM32_DMA2D + ltdc->blit = stm32_blit; + ltdc->blend = stm32_blend; + ltdc->fillarea = stm32_fillarea; +#endif +#endif + + /* Initialize the layer state */ + + state->area.xpos = 0; + state->area.ypos = 0; + state->area.xres = STM32_LTDC_WIDTH; + state->area.yres = STM32_LTDC_HEIGHT; + state->xpos = 0; + state->ypos = 0; + state->color = 0; + state->colorkey = 0; + state->alpha = 0xff; + state->blendmode = LTDC_BLEND_NONE; + state->lock = &g_lock; + + /* Initialize driver internals */ + + layer->opac = 0xff; + layer->bf1 = LTDC_BF1_CONST_ALPHA; + layer->bf2 = LTDC_BF2_CONST_ALPHA; + layer->operation = LTDC_LAYER_INIT; + + /* Clear the layer framebuffer */ + + stm32_ltdc_lclear(layer, 0); + + /* Set Pixel input format */ + + stm32_ltdc_lpixelformat(layer); + + /* Set position, color, colorkey, blendmode, alpha */ + + stm32_ltdc_lupdate(layer); + +#ifdef STM32_LAYER_CLUT_SIZE + /* Disable clut by default */ + + if (layer->state.vinfo.fmt == FB_FMT_RGB8) + { + stm32_ltdc_lclutenable(layer, false); + } +#endif + +#ifdef CONFIG_STM32_DMA2D + /* Bind the dma2d interface */ + + layer->dma2d = stm32_dma2dinitltdc(state); + DEBUGASSERT(layer->dma2d); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_getvideoinfo + * + * Description: + * Get the videoinfo for the framebuffer + * + * Parameter: + * vtable - The framebuffer driver object + * vinfo - the videoinfo object + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_getvideoinfo(struct fb_vtable_s *vtable, + struct fb_videoinfo_s *vinfo) +{ + lcdinfo("vtable=%p vinfo=%p\n", vtable, vinfo); + if (vtable) + { + FAR struct ltdc_layer_s *ltdc; +#ifdef CONFIG_STM32_LTDC_L2 + ltdc = (FAR struct ltdc_layer_s *)&LAYER_L2; +#else + ltdc = (FAR struct ltdc_layer_s *)&LAYER_L1; +#endif + return stm32_lgetvideoinfo(ltdc, vinfo); + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getplaneinfo + * + * Description: + * Get the planeinfo for the framebuffer + * + * Parameter: + * vtable - The framebuffer driver object + * pinfo - the planeinfo object + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_getplaneinfo(struct fb_vtable_s *vtable, int planeno, + struct fb_planeinfo_s *pinfo) +{ + lcdinfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo); + if (vtable) + { + FAR struct ltdc_layer_s *ltdc; +#ifdef CONFIG_STM32_LTDC_L2 + ltdc = (FAR struct ltdc_layer_s *)&LAYER_L2; +#else + ltdc = (FAR struct ltdc_layer_s *)&LAYER_L1; +#endif + return stm32_lgetplaneinfo(ltdc, planeno, pinfo); + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getcmap + * + * Description: + * Get a range of CLUT values for the LCD + * + * Parameter: + * vtable - The framebuffer driver object + * cmap - the color table + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +#ifdef STM32_LAYER_CLUT_SIZE +static int stm32_getcmap(struct fb_vtable_s *vtable, + struct fb_cmap_s *cmap) +{ +#ifdef CONFIG_STM32_LTDC_L2 + return stm32_getclut((FAR struct ltdc_layer_s *)&LAYER_L2, cmap); +#else + return stm32_getclut((FAR struct ltdc_layer_s *)&LAYER_L1, cmap); +#endif +} + +/**************************************************************************** + * Name: stm32_putcmap + * + * Description: + * Set a range of the CLUT values for the LCD + * + * Parameter: + * vtable - The framebuffer driver object + * cmap - the color table + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_putcmap(struct fb_vtable_s *vtable, + const struct fb_cmap_s *cmap) +{ +#ifdef CONFIG_STM32_LTDC_L2 + return stm32_setclut((FAR struct ltdc_layer_s *)&LAYER_L2, cmap); +#else + return stm32_setclut((FAR struct ltdc_layer_s *)&LAYER_L1, cmap); +#endif +} +#endif /* STM32_LAYER_CLUT_SIZE */ + +/**************************************************************************** + * Name: stm32_lgetvideoinfo + * + * 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_lgetvideoinfo(struct ltdc_layer_s *layer, + struct fb_videoinfo_s *vinfo) +{ + lcdinfo("layer=%p vinfo=%p\n", layer, vinfo); + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + if (stm32_ltdc_lvalidate(priv)) + { + memcpy(vinfo, &priv->state.vinfo, sizeof(struct fb_videoinfo_s)); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_lgetplaneinfo + * + * 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_lgetplaneinfo(struct ltdc_layer_s *layer, int planeno, + struct fb_planeinfo_s *pinfo) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer=%p planeno=%d pinfo=%p\n", layer, planeno, pinfo); + if (stm32_ltdc_lvalidate(priv) && planeno == 0) + { + memcpy(pinfo, &priv->state.pinfo, sizeof(struct fb_planeinfo_s)); + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_setclut + * + * Description: + * Configure layer clut (color lookup table). + * Non clut is defined during initializing. + * Clut is active during next vertical blank period. Do not need an update. + * + * Parameter: + * layer - Reference to the layer structure + * cmap - color lookup table with up the 256 entries + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +#ifdef STM32_LAYER_CLUT_SIZE +static int stm32_setclut(struct ltdc_layer_s *layer, + const struct fb_cmap_s *cmap) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + int ret; + + lcdinfo("layer=%p cmap=%p\n", layer, cmap); + + if (stm32_ltdc_lvalidate(priv) && cmap) + { + sem_wait(priv->state.lock); + + if (priv->state.vinfo.fmt != FB_FMT_RGB8) + { + lcderr("ERROR: CLUT is not supported for the pixel format: %d\n", + priv->state.vinfo.fmt); + ret = -EINVAL; + } + else if (cmap->first >= STM32_LTDC_NCLUT) + { + lcderr("ERROR: only %d color table entries supported\n", + STM32_LTDC_NCLUT); + ret = -EINVAL; + } + else + { + /* Update layer clut and clut register */ + + stm32_ltdc_lclut(priv, cmap); + + ret = OK; + } + + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getclut + * + * 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_getclut(struct ltdc_layer_s *layer, + struct fb_cmap_s *cmap) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + int ret; + + lcdinfo("layer=%p cmap=%p\n", layer, cmap); + + if (priv == &LAYER_L1 || priv == &LAYER_L2) + { + sem_wait(priv->state.lock); +#ifdef CONFIG_STM32_DMA2D + /* Note! We share the same color lookup table with the dma2d driver and + * the getclut implementation works in the same way. + * To prevent redundant code we simply call the getclut function of the + * dma2d interface. + */ + + ret = priv->dma2d->getclut(priv->dma2d, cmap); +#else + if (priv->state.vinfo.fmt != FB_FMT_RGB8) + { + lcderr("ERROR: CLUT is not supported for the pixel format: %d\n", + priv->state.vinfo.fmt); + ret = -EINVAL; + } + else if (cmap->first >= STM32_LTDC_NCLUT) + { + lcderr("ERROR: only %d color table entries supported\n", + STM32_LTDC_NCLUT); + ret = -EINVAL; + } + else + { + /* Copy from the layer clut */ + + uint32_t *clut; + int n; + + clut = priv->state.clut; + + for (n = cmap->first; n < cmap->len && n < STM32_LTDC_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]; + + reginfo("n=%d, red=%02x, green=%02x, blue=%02x\n", n, + clut888[offset], clut888[offset + 1], + clut888[offset + 2]); +# else + cmap->transp[n] = (uint8_t)LTDC_CMAP_ALPHA(clut[n]); + cmap->red[n] = (uint8_t)LTDC_CMAP_RED(clut[n]); + cmap->green[n] = (uint8_t)LTDC_CMAP_GREEN(clut[n]); + cmap->blue[n] = (uint8_t)LTDC_CMAP_BLUE(clut[n]); + + reginfo("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; + } +#endif + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} +#endif /* STM32_LAYER_CLUT_SIZE */ + +#ifdef CONFIG_STM32_LTDC_INTERFACE +/**************************************************************************** + * Name: getlid + * + * Description: + * Get a specific layer identifier. + * + * Parameter: + * layer - Reference to the layer structure + * lid - Reference to store the layer id + * flag - Operation flag describe the layer identifier + * e.g. get the current active or inactive layer. + * See LTDC_LAYER_* for possible values + * + * Return: + * OK - On success + * Null if invalid flag + * + ****************************************************************************/ + +static int stm32_getlid(FAR struct ltdc_layer_s *layer, int *lid, + uint32_t flag) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("flag = %08x\n", flag); + + if (stm32_ltdc_lvalidate(priv)) + { + int ret = OK; + + sem_wait(priv->state.lock); + + switch (flag) + { + case LTDC_LAYER_OWN: + *lid = priv->state.lid; + break; +#ifdef CONFIG_STM32_LTDC_L2 + case LTDC_LAYER_ACTIVE: + *lid = g_lactive; + break; + case LTDC_LAYER_INACTIVE: + *lid = !g_lactive; + break; + case LTDC_LAYER_TOP: + *lid = LTDC_LAYER_L2; + break; + case LTDC_LAYER_BOTTOM: + *lid = LTDC_LAYER_L1; + break; +#else + case LTDC_LAYER_ACTIVE: + case LTDC_LAYER_INACTIVE: + case LTDC_LAYER_TOP: + case LTDC_LAYER_BOTTOM: + *lid = LTDC_LAYER_L1; + break; +#endif +#ifdef CONFIG_STM32_DMA2D + case LTDC_LAYER_DMA2D: + ret = priv->dma2d->getlid(priv->dma2d, lid); + break; +#endif + default: + ret = EINVAL; + lcderr("ERROR: Returning EINVAL\n"); + break; + } + + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_setcolor + * + * Description: + * Configure layer default color value for the non active layer area. + * Default value during initializing: 0x00000000 + * Color is active after next update. + * + * Parameter: + * layer - Reference to the layer structure + * argb - ARGB8888 color value + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_setcolor(FAR struct ltdc_layer_s *layer, uint32_t argb) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, argb = %08x\n", layer, argb); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + priv->state.color = argb; + priv->operation |= LTDC_LAYER_SETCOLOR; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getcolor + * + * Description: + * Get configured layer color for the non active layer area. + * + * Parameter: + * layer - Reference to the layer structure + * argb - Reference to store the ARGB8888 color value + * + * Return: + * On success - OK + * On error - -EINVAL + * +*******************************************************************************/ + +static int stm32_getcolor(FAR struct ltdc_layer_s *layer, uint32_t *argb) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, argb = %p\n", layer, argb); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + *argb = priv->state.color; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_setcolorkey + * + * Description: + * Configure layer default color key (chromakey) value for transparency. + * Layer default value during initializing: 0x00000000 + * Colorkey is active after next update. + * + * Parameter: + * layer - Reference to the layer structure + * rgb - RGB888 color value + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_setcolorkey(FAR struct ltdc_layer_s *layer, uint32_t rgb) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, argb = %08x\n", layer, rgb); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + priv->state.colorkey = rgb; + priv->operation |= LTDC_LAYER_SETCOLORKEY; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getcolorkey + * + * Description: + * Get the configured layer color key (chromakey) for transparency. + * + * Parameter: + * layer - Reference to the layer structure + * rgb - Reference to store the RGB888 color key + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_getcolorkey(FAR struct ltdc_layer_s *layer, uint32_t *rgb) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, argb = %p\n", layer, rgb); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + *rgb = priv->state.colorkey; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: setalpha + * + * 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 alpha value during initializing: 0xff + * Alpha is active after next update. + * + * Parameter: + * layer - Reference to the layer structure + * alpha - Alpha value + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_setalpha(FAR struct ltdc_layer_s *layer, uint8_t alpha) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, alpha = %02x\n", layer, alpha); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + priv->state.alpha = alpha; + priv->operation |= LTDC_LAYER_SETALPHAVALUE; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getalpha + * + * 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_getalpha(FAR struct ltdc_layer_s *layer, uint8_t *alpha) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, alpha = %p\n", layer, alpha); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + *alpha = priv->state.alpha; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: setblendmode + * + * Description: + * Configure blend mode of the layer. + * Default mode during initializing: LTDC_BLEND_NONE + * Blendmode is active after next update. + * + * Parameter: + * layer - Reference to the layer structure + * mode - Blend mode (see LTDC_BLEND_*) + * + * Return: + * On success - OK + * On error - -EINVAL + * + * Procedure information: + * LTDC_BLEND_NONE: + * Informs the driver to disable all blend operation for the given layer. + * That means the layer is opaque. Note this has no effect on the + * colorkey settings. + * + * LTDC_BLEND_ALPHA: + * Informs the driver to enable alpha blending for the given layer. + * + * LTDC_BLEND_COLORKEY: + * Informs the driver to enable colorkeying for the given layer. + * + * LTDC_BLEND_SRCPIXELALPHA: + * 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. + * + * LTDC_BLEND_DESTPIXELALPHA: + * Informs the driver to use the pixel alpha value of the subjacent layer + * instead the constant alpha value. This is only useful for ARGB8888 + * color format. + * + ****************************************************************************/ + +static int stm32_setblendmode(FAR struct ltdc_layer_s *layer, uint32_t mode) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + uint32_t blendmode = mode; + + lcdinfo("layer = %p, mode = %08x\n", layer, mode); + + if (stm32_ltdc_lvalidate(priv)) + { + int ret = OK; + + sem_wait(priv->state.lock); + + /* Disable colorkeying by default */ + + priv->operation &= ~LTDC_LAYER_ENABLECOLORKEY; + + if (blendmode & (LTDC_BLEND_ALPHA | LTDC_BLEND_PIXELALPHA | + LTDC_BLEND_ALPHAINV | LTDC_BLEND_PIXELALPHAINV)) + { + /* Enable any alpha blending */ + + stm32_ltdc_lunsetopac(priv); + } + else + { + /* Disable any alpha blending */ + + stm32_ltdc_lsetopac(priv); + } + + if (blendmode & LTDC_BLEND_ALPHA || blendmode == LTDC_BLEND_NONE) + { + /* alpha blending introduce LTDC_BLEND_ALPHAINV */ + + priv->bf1 = LTDC_BF1_CONST_ALPHA; + priv->bf2 = LTDC_BF2_CONST_ALPHA; + blendmode &= ~LTDC_BLEND_ALPHA; + } + + if (blendmode & LTDC_BLEND_PIXELALPHA) + { + /* pixel alpha blending introduce LTDC_BLEND_PIXELALPHAINV */ + + priv->bf1 = LTDC_BF1_PIXEL_ALPHA; + priv->bf2 = LTDC_BF2_PIXEL_ALPHA; + blendmode &= ~LTDC_BLEND_PIXELALPHA; + } + + if (blendmode & LTDC_BLEND_ALPHAINV) + { + /* alpha blending of source input */ + + priv->bf2 = LTDC_BF2_CONST_ALPHA; + blendmode &= ~LTDC_BLEND_ALPHAINV; + } + + if (blendmode & LTDC_BLEND_PIXELALPHAINV) + { + /* pixel alpha blending of source input */ + + priv->bf2 = LTDC_BF2_PIXEL_ALPHA; + blendmode &= ~LTDC_BLEND_PIXELALPHAINV; + } + + if (mode & LTDC_BLEND_COLORKEY) + { + /* Enable colorkeying */ + + priv->operation |= LTDC_LAYER_ENABLECOLORKEY; + blendmode &= ~LTDC_BLEND_COLORKEY; + } + if (blendmode) + { + lcderr("ERROR: Unknown blendmode %02x\n", blendmode); + ret = -EINVAL; + } + + if (ret == OK) + { + priv->state.blendmode = mode; + priv->operation |= (LTDC_LAYER_SETBLENDMODE | + LTDC_LAYER_SETALPHAVALUE | + LTDC_LAYER_SETCOLORKEY); + } + + sem_post(priv->state.lock); + return ret; + } + + lcderr("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_getblendmode(FAR struct ltdc_layer_s *layer, uint32_t *mode) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, mode = %p\n", layer, mode); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + *mode = priv->state.blendmode; + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_setarea + * + * Description: + * Configure visible layer area and the reference position of the first + * pixel of the whole layer which is the first visible top left pixel in + * the active area. + * Area is active after next update. + * + * Parameter: + * layer - Reference to the layer control structure + * area - Reference to the valid area structure for the new active area + * srcxpos - x position of the visible pixel of the whole layer + * srcypos - y position of the visible pixel of the whole layer + * + * Return: + * On success - OK + * On error - -EINVAL + * + * Procedure Information: + * If the srcxpos and srcypos unequal the xpos and ypos of the area + * structure this acts like moving the visible area to another position on + * the screen during the next update operation. + * + ****************************************************************************/ + +static int stm32_setarea(FAR struct ltdc_layer_s *layer, + FAR const struct ltdc_area_s *area, + fb_coord_t srcxpos, + fb_coord_t srcypos) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, area = %p, srcxpos = %d, srcypos = %d\n", + layer, area, srcxpos, srcypos); + + if (stm32_ltdc_lvalidate(priv)) + { + int ret; + + sem_wait(priv->state.lock); + + ret = stm32_ltdc_lvalidatearea(priv, area->xpos, area->ypos, area->xres, + area->yres, srcxpos, srcypos); + + if (ret == OK) + { + priv->state.xpos = srcxpos; + priv->state.ypos = srcypos; + priv->state.area.xpos = area->xpos; + priv->state.area.ypos = area->ypos; + priv->state.area.xres = area->xres; + priv->state.area.yres = area->yres; + priv->operation |= LTDC_LAYER_SETAREA; + } + + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_getarea + * + * Description: + * Get configured visible layer area. + * + * Parameter: + * layer - Reference to the layer control structure + * area - Reference to the area structure to store the active area + * srcxpos - Reference to store the referenced x position of the whole layer + * srcypos - Reference to store the reterenced y position of the whole layer + * + * Return: + * On success - OK + * On error - -EINVAL + * + ****************************************************************************/ + +static int stm32_getarea(FAR struct ltdc_layer_s *layer, + FAR struct ltdc_area_s *area, + fb_coord_t *srcxpos, fb_coord_t *srcypos) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, area = %p, srcxpos = %p, srcypos = %p\n", + layer, area, srcxpos, srcypos); + + if (stm32_ltdc_lvalidate(priv)) + { + sem_wait(priv->state.lock); + *srcxpos = priv->state.xpos; + *srcypos = priv->state.ypos; + memcpy(area, &priv->state.area, sizeof(struct ltdc_area_s)); + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_update + * + * Description: + * Update current layer settings and make changes visible. + * + * Parameter: + * layer - Reference to the layer structure + * mode - operation mode + * + * Return: + * OK - On success + * -EINVAL - If one of the parameter invalid + * -ECANCELED - Operation cancelled, something goes wrong + * + * Procedure information: + * LTDC_UPDATE_SIM: + * Informs the driver to update both layers simultaneously. Otherwise update + * the given layer only. + * + * LTDC_UPDATE_FLIP: + * Informs the driver to perform a flip operation. + * This only effects the ltdc layer 1 and 2 and can be useful for double + * buffering. Each flip operation changed the active layer to the inactive + * and vice versa. In the context of the ltdc that means, the inactive layer + * is complete disabled. So the subjacent layer is the background layer + * (background color). To reactivate both layer and their current settings + * perform an update without LTDC_UPDATE_FLIP flag. + * + * LTDC_UPDATE_ACTIVATE: + * Informs the driver that the given layer should be the active layer when + * the operation is complete. + * + * LTDC_SYNC_VBLANK: + * Informs the driver to update the layer upon vertical blank. Otherwise + * immediately. + * + ****************************************************************************/ + +static int stm32_update(FAR struct ltdc_layer_s *layer, uint32_t mode) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; +#ifdef CONFIG_STM32_LTDC_L2 + FAR struct stm32_layer_s *active = &LAYER(g_lactive); + FAR struct stm32_layer_s *inactive = &LAYER(!g_lactive); +#endif + + lcdinfo("layer = %p, mode = %08x\n", layer, mode); + + if (stm32_ltdc_lvalidate(priv)) + { + /* Reload immediately by default */ + + bool waitvblank = false; + uint8_t reload = LTDC_SRCR_IMR; + + sem_wait(priv->state.lock); + + if (mode & LTDC_SYNC_VBLANK) + { + reload = LTDC_SRCR_VBR; + } + + if (mode & LTDC_SYNC_WAIT) + { + waitvblank = true; + } + + /* Ensures that last register reload operation has been completed */ + + if (stm32_ltdc_waitforirq() != OK) + { + lcderr("ERROR: Returning ECANCELED\n"); + return -ECANCELED; + } + + /* Update the given layer */ + + stm32_ltdc_lupdate(priv); + +#ifdef CONFIG_STM32_LTDC_L2 + /* The following operation only useful if layer 2 is supported. + * Otherwise ignore it. + */ + + if (mode & LTDC_UPDATE_SIM) + { + /* Also update the flip layer */ + + stm32_ltdc_lupdate(&LAYER(!priv->state.lid)); + } + + if (mode & LTDC_UPDATE_ACTIVATE) + { + /* Set the given layer to the next active layer */ + + g_lactive = priv->state.lid; + + /* Also change the current active layer for flip operation */ + + active = &LAYER(!g_lactive); + } + + if (mode & LTDC_UPDATE_FLIP) + { + /* Reset if manipulated by ACTIVATE flag */ + + inactive = &LAYER(!active->state.lid); + + /* Set blendfactor for current active layer to there reset value */ + + stm32_ltdc_lblendmode(active, STM32_LTDC_BF1_RESET, + STM32_LTDC_BF2_RESET); + + /* Set blendfactor for current inactive layer */ + + stm32_ltdc_lblendmode(inactive, inactive->bf1, inactive->bf2); + + /* Disable the active layer */ + + active->operation &= ~LTDC_LAYER_ENABLE; + + stm32_ltdc_lenable(active); + + /* Enable the inactive layer */ + + inactive->operation |= LTDC_LAYER_ENABLE; + + stm32_ltdc_lenable(inactive); + + /* Ensure that both layer active and the manipulated layer + * settings restored during the next update (non flip) operation + */ + + active->operation |= (LTDC_LAYER_SETBLENDMODE | + LTDC_LAYER_ENABLE | + LTDC_LAYER_SETCOLOR | + LTDC_LAYER_SETENABLE); + + /* Change layer activity */ + + g_lactive = inactive->state.lid; + } +#endif + + /* Make the changes visible */ + + stm32_ltdc_reload(reload, waitvblank); + + sem_post(priv->state.lock); + + return OK; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +#ifdef CONFIG_STM32_DMA2D +/**************************************************************************** + * Name: stm32_blit + * + * Description: + * Copy selected area from a source layer to selected position of the + * destination layer. + * + * Parameter: + * dest - Reference to the destination layer + * destxpos - Selected x position of the destination layer + * destypos - Selected y position of the destination layer + * src - Reference to the source layer + * srcarea - 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) + * + ****************************************************************************/ + +static int stm32_blit(FAR struct ltdc_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) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)dest; + + lcdinfo("dest = %p, destxpos = %d, destypos = %d, src = %p, srcarea = %p\n", + dest, destxpos, destypos, src, srcarea); + + if (stm32_ltdc_lvalidate(priv)) + { + int ret; + + sem_wait(priv->state.lock); + priv->dma2d->blit(priv->dma2d, destxpos, destypos, src, srcarea); + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: stm32_blend + * + * Description: + * Blends the selected area from a foreground layer with selected position + * of the background layer. Copy the result to the destination layer. Note! + * The content of the foreground and background layer is not changed. + * + * Parameter: + * dest - Reference to the destination layer + * destxpos - Selected x position of the destination layer + * destypos - Selected y position of the destination layer + * fore - Reference to the foreground layer + * forexpos - Selected x position of the foreground layer + * foreypos - Selected y 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) + * + ****************************************************************************/ + +static int stm32_blend(FAR struct ltdc_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) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)dest; + + lcdinfo("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_ltdc_lvalidate(priv)) + { + int ret; + + sem_wait(priv->state.lock); + priv->dma2d->blend(priv->dma2d, destxpos, destypos, + fore, forexpos, foreypos, back, backarea); + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} + +/**************************************************************************** + * Name: fillarea + * + * 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. + * + ****************************************************************************/ + +static int stm32_fillarea(FAR struct ltdc_layer_s *layer, + FAR const struct ltdc_area_s *area, + uint32_t color) +{ + FAR struct stm32_layer_s *priv = (FAR struct stm32_layer_s *)layer; + + lcdinfo("layer = %p, area = %p, color = %08x\n", layer, area, color); + + if (stm32_ltdc_lvalidate(priv)) + { + int ret; + + sem_wait(priv->state.lock); + priv->dma2d->fillarea(priv->dma2d, area, color); + sem_post(priv->state.lock); + + return ret; + } + + lcderr("ERROR: Returning EINVAL\n"); + return -EINVAL; +} +#endif + +/**************************************************************************** + * Name: stm32_ltdcgetlayer + * + * Description: + * This is a non-standard framebuffer interface. + * Get the specific layer object by the layer id to enable layer hardware + * support. + * + * Parameter: + * lid - Layer identifier + * + * Return: + * Reference to the layer control structure on success or Null if lid + * is invalid. + * + ****************************************************************************/ + +FAR struct ltdc_layer_s *stm32_ltdcgetlayer(int lid) +{ + lcdinfo("lid: %d\n", lid); + + if (lid == LTDC_LAYER_L1 || lid == LTDC_LAYER_L2) + { + return (FAR struct ltdc_layer_s *) &LAYER(lid); + } + + lcderr("ERROR: Returning EINVAL\n"); + errno = EINVAL; + return NULL; +} +#endif /* CONFIG_STM32_LTDC_INTERFACE */ + +/**************************************************************************** + * Name: stm32_ltdcinitialize + * + * Description: + * Initialize the ltdc controller + * + * Return: + * OK + * + ****************************************************************************/ + +int stm32_ltdcinitialize(void) +{ +#ifdef CONFIG_STM32_DMA2D + int ret; +#endif + + lcdinfo("Initialize LTDC driver\n"); + + if (g_initialized == true) + { + return OK; + } + + /* Disable the LCD */ + + stm32_lcd_enable(false); + + lcdinfo("Configuring the LCD controller\n"); + + /* Configure LCD periphery */ + + lcdinfo("Configure lcd periphery\n"); + stm32_ltdc_periphconfig(); + + /* Configure global ltdc register */ + + lcdinfo("Configure global register\n"); + stm32_global_configure(); + +#ifdef CONFIG_STM32_DMA2D + /* Initialize the dma2d controller */ + + ret = up_dma2dinitialize(); + + if (ret != OK) + { + return ret; + } +#endif + + /* Initialize ltdc layer */ + + lcdinfo("Initialize ltdc layer\n"); + stm32_ltdc_linit(LTDC_LAYER_L1); +#ifdef CONFIG_STM32_LTDC_L2 + stm32_ltdc_linit(LTDC_LAYER_L2); +#endif + + /* Display layer 1 and 2 */ + + stm32_ltdc_lenable(&LAYER_L1); +#ifdef CONFIG_STM32_LTDC_L2 + stm32_ltdc_lenable(&LAYER_L2); +#endif + + /* Enable the backlight */ + +#ifdef CONFIG_STM32_LCD_BACKLIGHT + stm32_backlight(true); +#endif + + /* Reload shadow register */ + + lcdinfo("Reload shadow register\n"); + stm32_ltdc_reload(LTDC_SRCR_IMR, false); + + /* Turn the LCD on */ + + lcdinfo("Enabling the display\n"); + stm32_lcd_enable(true); + + /* Set initialized state */ + + g_initialized = true; + return OK; +} + +/**************************************************************************** + * Name: stm32_ltdcgetvplane + * + * Description: + * Return a a reference to the framebuffer object for the specified video + * plane. + * + * Input parameters: + * None + * + * Returned value: + * Reference to the framebuffer object (NULL on failure) + * + ****************************************************************************/ + +struct fb_vtable_s *stm32_ltdcgetvplane(int vplane) +{ + lcdinfo("vplane: %d\n", vplane); + + if (vplane == 0) + { + return (struct fb_vtable_s *)&g_vtable; + } + + return NULL; +} + +/**************************************************************************** + * Name: stm32_ltdcuninitialize + * + * Description: + * Uninitialize the framebuffer driver. Bad things will happen if you + * call this without first calling fb_initialize()! + * + ****************************************************************************/ + +void stm32_ltdcuninitialize(void) +{ + /* Disable all ltdc interrupts */ + + stm32_ltdc_irqctrl(0, LTDC_IER_RRIE | LTDC_IER_TERRIE | + LTDC_IER_FUIE | LTDC_IER_LIE); + + up_disable_irq(g_interrupt.irq); + irq_detach(g_interrupt.irq); + + /* Disable the LCD controller */ + + stm32_lcd_enable(false); + + /* Set initialized state */ + + g_initialized = false; +} + +/**************************************************************************** + * Name: stm32_lcdclear + * + * Description: + * This is a non-standard LCD interface just for the STM32 LTDC. Clearing the + * display in the normal way by writing a sequences of runs that covers the + * entire display can be slow. Here the display is cleared by simply setting + * all video memory to the specified color. + * + * Parameter: + * color - The color the clear the whole framebuffer + * + ****************************************************************************/ + +void stm32_lcdclear(nxgl_mxpixel_t color) +{ +#ifdef CONFIG_STM32_LTDC_L2 + stm32_ltdc_lclear(&LAYER(LTDC_LAYER_L2), color); +#endif + stm32_ltdc_lclear(&LAYER(LTDC_LAYER_L1), color); +} + +/**************************************************************************** + * Name: stm32_lcd_backlight + * + * Description: + * Provide this interface to turn the backlight on and off. + * + * Parameter: + * blon - Enable or disable the lcd backlight + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_LCD_BACKLIGHT +void stm32_backlight(bool blon) +{ + /* Set default backlight level CONFIG_STM32_LTDC_DEFBACKLIGHT */ + + lcderr("ERROR: Not supported\n"); +} +#endif diff --git a/arch/arm/src/stm32f7/stm32_ltdc.h b/arch/arm/src/stm32f7/stm32_ltdc.h new file mode 100755 index 00000000000..9214d83e351 --- /dev/null +++ b/arch/arm/src/stm32f7/stm32_ltdc.h @@ -0,0 +1,157 @@ +/************************************************************************************ + * arch/arm/src/stm32/stm32_ltdc.h + * + * Copyright (C) 2013-2014 Ken Pettit. All rights reserved. + * Authors: Ken Pettit + * Marco Krahl + * + * 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_STM32_LTDC_H +#define __ARCH_ARM_SRC_STM32_STM32_LTDC_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include + +#ifdef CONFIG_STM32_LTDC + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +/* Common layer state structure for the LTDC and DMA2D controller */ + +struct stm32_ltdc_s +{ + /* Fixed settings */ + + int lid; /* Layer identifier */ + struct fb_videoinfo_s vinfo; /* Layer videoinfo */ + struct fb_planeinfo_s pinfo; /* Layer planeinfo */ + + /* Positioning */ + + struct ltdc_area_s area; /* Active layer area */ + fb_coord_t xpos; /* Reference x position */ + fb_coord_t ypos; /* Reference y position */ + + /* Coloring */ + + uint32_t color; /* Layer color definition */ +#ifdef CONFIG_FB_CMAP + uint32_t *clut; /* 32-bit aligned clut color table */ +#endif + + /* Blending */ + + uint8_t alpha; /* Layer constant alpha value */ + uint32_t colorkey; /* Layer colorkey */ + uint32_t blendmode; /* Layer blend factor */ + + /* Operation */ + + sem_t *lock; /* Ensure mutually exclusive access */ +}; + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ +/* The STM32 LTDC driver uses the common framebuffer interfaces declared in + * include/nuttx/video/fb.h. + */ + +int stm32_ltdcinitialize(void); +FAR struct fb_vtable_s *stm32_ltdcgetvplane(int vplane); +void stm32_ltdcuninitialize(void); + +/************************************************************************************ + * Name: stm32_ltdcgetlayer + * + * Description: + * Get the ltdc layer structure to perform hardware layer operation + * + * Parameter: + * lid - Layer identifier + * + * Return: + * Reference to the layer control structure on success or Null if parameter + * invalid. + * + ************************************************************************************/ + +FAR struct ltdc_layer_s *stm32_ltdcgetlayer(int lid); + +/************************************************************************************ + * Name: stm32_lcdclear + * + * Description: + * This is a non-standard LCD interface just for the STM32 LTDC. Clearing the + * display in the normal way by writing a sequences of runs that covers the + * entire display can be slow. Here the display is cleared by simply setting + * all video memory to the specified color. + * + ************************************************************************************/ + +void stm32_lcdclear(nxgl_mxpixel_t color); + +/************************************************************************************ + * Name: stm32_lcd_backlight + * + * Description: + * If CONFIG_STM32_LCD_BACKLIGHT is defined, then the board-specific logic must + * provide this interface to turn the backlight on and off. + * + ************************************************************************************/ + +#ifdef CONFIG_STM32_LCD_BACKLIGHT +void stm32_backlight(bool blon); +#endif + +#endif /* CONFIG_STM32_LTDC */ +#endif /* __ARCH_ARM_SRC_STM32_STM32_LTDC_H */