blob: c3a3ee5870449e63ff251f066f926098fb253050 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include <stdint.h>
#include <math.h>
#include <string.h>
#ifdef LCDC
/** \addtogroup lcdd_base
* Implementation of LCD driver, Include LCD initialization,
* LCD on/off and LCD backlight control.
*/
/**@{*/
/*----------------------------------------------------------------------------
* Local types
*----------------------------------------------------------------------------*/
/** DMA descriptor for LCDC */
typedef struct _LCDCDescriptor {
uint32_t addr;
uint32_t ctrl;
uint32_t next;
}sLCDCDescriptor;
/** CULT information */
typedef struct _CLUTInfo {
uint8_t bpp;
uint8_t nbColors;
}sCLUTInfo;
/** LCDC General Layer information */
typedef struct _Layer {
sLCDCDescriptor dmaD;
void* pBuffer;
sCLUTInfo clut;
uint16_t reserved;
} sLayer;
/** LCDC HEO Layer information */
typedef struct _HeoLayer {
sLCDCDescriptor dmaD[3];
void* pBuffer;
sCLUTInfo clut;
uint16_t reserved;
} sHeoLayer;
/** Pins for LCDC */
static const Pin pPinsLCD[] = {PINS_LCD};
/** Current selected canvas information */
static sLCDDLayer lcddCanvas;
/** Base Layer */
#if defined ( __ICCARM__ ) /* IAR Ewarm */
#pragma data_alignment=64
#elif defined ( __GNUC__ ) /* GCC CS3 */
__attribute__((aligned(64)))
#endif
static sLayer lcddBase;
/** Overlay 1 Layer */
#if defined ( __ICCARM__ ) /* IAR Ewarm */
#pragma data_alignment=64
#elif defined ( __GNUC__ ) /* GCC CS3 */
__attribute__((aligned(64)))
#endif
static sLayer lcddOvr1;
#if defined ( __ICCARM__ ) /* IAR Ewarm */
#pragma data_alignment=64
#elif defined ( __GNUC__ ) /* GCC CS3 */
__attribute__((aligned(64)))
#endif
static sLayer lcddOvr2;
/** High End Overlay Layer */
#if defined ( __ICCARM__ ) /* IAR Ewarm */
#pragma data_alignment=64
#elif defined ( __GNUC__ ) /* GCC CS3 */
__attribute__((aligned(64)))
#endif
static sHeoLayer lcddHeo;
/** Hardware cursor Layer */
#if defined ( __ICCARM__ ) /* IAR Ewarm */
#pragma data_alignment=64
#elif defined ( __GNUC__ ) /* GCC CS3 */
__attribute__((aligned(64)))
#endif
static sLayer lcddHcc;
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* Return a pointer to layer.
* \param bLayer Layer ID.
*/
static sLayer *pLayer( uint8_t bLayer )
{
switch( bLayer )
{
case LCDD_BASE: return &lcddBase;
case LCDD_OVR1: return &lcddOvr1;
case LCDD_OVR2: return &lcddOvr2;
case LCDD_HEO: return (sLayer*)&lcddHeo;
case LCDD_CUR: return &lcddHcc;
}
return NULL;
}
/**
* Return true if Pixel stride supported.
* \param bLayer Layer ID.
*/
static uint8_t LCDD_IsPStrideSupported( uint8_t bLayer )
{
switch( bLayer )
{
case LCDD_OVR1: case LCDD_OVR2:case LCDD_HEO: return 1;
default: return 0;
}
}
/**
* Return a pointer to enable register.
* (Starts following register list: _ER, _DR, _SR, _IER, _IDR, _IMR, _ISR)
* \param bLayer Layer ID.
*/
static volatile uint32_t *pEnableReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_CONTROLLER: return (volatile uint32_t*)&pHw->LCDC_LCDEN;
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASECHER;
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CHER;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CHER;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCHER;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCHER;
}
return NULL;
}
/**
* Return a pointer to blender configuration register.
* \param bLayer Layer ID.
*/
static volatile uint32_t *pBlenderReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t *)&pHw->LCDC_BASECFG4;
case LCDD_OVR1: return (volatile uint32_t *)&pHw->LCDC_OVR1CFG9;
case LCDD_OVR2: return (volatile uint32_t *)&pHw->LCDC_OVR2CFG9;
case LCDD_HEO: return (volatile uint32_t *)&pHw->LCDC_HEOCFG12;
case LCDD_CUR: return (volatile uint32_t *)&pHw->LCDC_HCRCFG9;
}
return NULL;
}
/**
* Return a pointer to DMA head register.
* (Starts following register list: _HEAD, _ADDRESS, _CONTROL, _NEXT)
* \param bLayer Layer ID.
*/
static volatile uint32_t *pHeadReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASEHEAD;
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1HEAD;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2HEAD;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOHEAD;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRHEAD;
}
return NULL;
}
/**
* Return a pointer to layer configure register.
* (Including: _CFG0, _CFG1 (RGB mode ...))
* \param bLayer Layer ID.
*/
static volatile uint32_t *pCfgReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASECFG0;
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CFG0;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CFG0;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCFG0;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCFG0;
}
return NULL;
}
/**
* Return a pointer to Window configure register.
* (Including: X Y register, W H register)
* \param bLayer Layer ID.
*/
static volatile uint32_t *pWinReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CFG2;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CFG2;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCFG2;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCFG2;
}
return NULL;
}
/**
* Return a pointer to striding regiters.
* \param bLayer Layer ID.
*/
static volatile uint32_t *pStrideReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASECFG2;
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CFG4;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CFG4;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCFG5;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCFG4;
}
return NULL;
}
/**
* Return a pointer to Color configure regiters.
* (Including: RGB Default, RGB Key, RGB Mask)
* Note that base layer only has one register (default).
* \param bLayer Layer ID.
*/
static volatile uint32_t *pColorReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASECFG3;
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CFG6;
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CFG6;
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCFG9;
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCFG6;
}
return NULL;
}
/**
* Return a pointer to scaling register.
* \param bLayer Layer ID.
*/
static volatile uint32_t *pScaleReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCFG13;
}
return NULL;
}
/**
* Return bits per pixel from RGB mode settings.
* (Note the bits is bits occupied in memory, including reserved)
*/
static uint32_t LCDD_GetBitsPerPixel(uint32_t modeReg)
{
switch (modeReg)
{
/* RGB mode */
case LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444:
case LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444:
case LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444:
case LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565:
case LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555:
return 2*8;
case LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666PACKED:
case LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED:
case LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED:
return 3*8;
case LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666:
case LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666:
case LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888:
case LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888:
case LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888:
case LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888:
return 3*8;
/* CLUT mode */
case LCDC_HEOCFG1_CLUTMODE_CLUT_1BPP | LCDC_HEOCFG1_CLUTEN: return 1;
case LCDC_HEOCFG1_CLUTMODE_CLUT_2BPP | LCDC_HEOCFG1_CLUTEN: return 2;
case LCDC_HEOCFG1_CLUTMODE_CLUT_4BPP | LCDC_HEOCFG1_CLUTEN: return 4;
case LCDC_HEOCFG1_CLUTMODE_CLUT_8BPP | LCDC_HEOCFG1_CLUTEN: return 8;
/* YUV mode */
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR:
return 32;
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR:
case LCDC_HEOCFG1_YUVEN | LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR:
return 16;
}
return 0;
}
/**
* Enable a LCDC DMA channel
*/
static void LCDD_SetDMA( void* pBuffer,
sLCDCDescriptor *pTD,
uint32_t regAddr)
{
volatile uint32_t *pDmaR = (volatile uint32_t*)regAddr;
/* Modify descriptor */
pTD->addr = (uint32_t)pBuffer;
pTD->ctrl = LCDC_BASECTRL_DFETCH;
pTD->next = (uint32_t)pTD;
/* Modify registers */
pDmaR[1] = (uint32_t)pBuffer;
pDmaR[2] = LCDC_BASECTRL_DFETCH;
pDmaR[3] = (uint32_t)pTD;
}
/**
* Disable a LCDC DMA channel
*/
static void LCDD_ClearDMA( sLCDCDescriptor *pTD, uint32_t regAddr )
{
uint32_t *pReg = (uint32_t *)regAddr;
volatile uint32_t *pRegCtrl = (volatile uint32_t*)&pReg[1];
volatile uint32_t *pRegNext = (volatile uint32_t*)&pReg[2];
/* Modify descriptor */
if (pTD)
{
pTD->ctrl &= ~LCDC_BASECTRL_DFETCH;
pTD->next = (uint32_t)pTD;
}
/* Modify control registers */
*pRegCtrl &= ~LCDC_BASECTRL_DFETCH;
*pRegNext = (uint32_t)pTD;
}
/**
* Return scaling factor
*/
static uint32_t LCDD_CalcScaleFactor(uint32_t targetW, uint32_t imgW)
{
uint32_t factor;
factor = 2048 * (imgW + 1) / (targetW + 1);
//factor = 1024 * (imgW + 1) / (targetW + 1);
//if (targetW > imgW * 2)
// factor -= 7;
return factor;
}
/**
* Return a pointer to Color Palette lookup regiters.
* \param bLayer Layer ID.
*/
static volatile uint32_t *pCLUTReg( uint8_t bLayer )
{
Lcdc *pHw = LCDC;
switch( bLayer )
{
case LCDD_BASE: return (volatile uint32_t*)&pHw->LCDC_BASECLUT[0];
case LCDD_OVR1: return (volatile uint32_t*)&pHw->LCDC_OVR1CLUT[0];
case LCDD_OVR2: return (volatile uint32_t*)&pHw->LCDC_OVR2CLUT[0];
case LCDD_HEO: return (volatile uint32_t*)&pHw->LCDC_HEOCLUT[0];
case LCDD_CUR: return (volatile uint32_t*)&pHw->LCDC_HCRCLUT[0];
}
return NULL;
}
/**
* Build 8-bit color palette (actually true color)
*/
static void LCDD_BuildCLUT8(volatile uint32_t* pCLUT)
{
uint32_t r, g, b; /* 3:3:2 */
for (r = 0; r < 8; r ++)
{
for (g = 0; g < 8; g ++)
{
for (b = 0; b < 4; b ++)
{
*pCLUT ++ = (r << (16 + 5))
+ (g << (8 + 5))
+ (b << (0 + 6));
}
}
}
}
/**
* Build 4-bit color palette (16 color)
*/
static void LCDD_BuildCLUT4(volatile uint32_t* pCLUT)
{
uint32_t r, g, b;
for (r = 0; r < 4; r ++)
{
for (g = 0; g < 2; g ++)
{
for (b = 0; b < 2; b ++)
{
*pCLUT ++ = (r << (16 + 6))
+ (g << (8 + 7))
+ (b << (0 + 7));
}
}
}
}
/**
* Build 2-bit color palette (4 gray)
*/
static void LCDD_BuildCLUT2(volatile uint32_t* pCLUT)
{
pCLUT[0] = 0x000000;
pCLUT[1] = 0x505050;
pCLUT[2] = 0xA0A0A0;
pCLUT[3] = 0xFFFFFF;
}
/**
* Build 1-bit color palette (black & white)
*/
static void LCDD_BuildCLUT1(volatile uint32_t* pCLUT)
{
pCLUT[0] = 0x000000;
pCLUT[1] = 0xFFFFFF;
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Initializes the LCD controller.
* Configure SMC to access LCD controller at 64MHz MCK.
*/
void LCDD_Initialize( void )
{
Lcdc *pHw = LCDC;
Pmc *pPmc = PMC;
/* Configure PIO */
PIO_Configure(pPinsLCD, PIO_LISTSIZE(pPinsLCD));
LCDD_Off();
/* Reset CLUT information */
lcddBase.clut.bpp = 0;
lcddOvr1.clut.bpp = 0;
lcddOvr2.clut.bpp = 0;
lcddHeo.clut.bpp = 0;
lcddHcc.clut.bpp = 0;
/* Reset layer information */
lcddBase.pBuffer = NULL;
lcddOvr1.pBuffer = NULL;
lcddOvr2.pBuffer = NULL;
lcddHeo.pBuffer = NULL;
lcddHcc.pBuffer = NULL;
/* No canvas selected */
lcddCanvas.pBuffer = NULL;
/* Enable peripheral clock */
PMC_EnablePeripheral(ID_LCDC);
pPmc->PMC_SCER = (0x1u << 3);
/* Timing Engine Configuration */
/* Disable interrupt */
pHw->LCDC_LCDIDR = 0xFFFFFFFF;
/* Configure channels */
/* Base */
pHw->LCDC_BASECFG0 = LCDC_BASECFG0_DLBO | LCDC_BASECFG0_BLEN_AHB_INCR16;
pHw->LCDC_BASECFG1 = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
/* Overlay 1, GA 0xFF */
pHw->LCDC_OVR1CFG0 = LCDC_OVR1CFG0_DLBO | LCDC_OVR1CFG0_BLEN_AHB_BLEN_INCR16
| LCDC_OVR1CFG0_ROTDIS
;
pHw->LCDC_OVR1CFG1 = LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED;
pHw->LCDC_OVR1CFG9 = LCDC_OVR1CFG9_GA(0xFF) | LCDC_OVR1CFG9_GAEN;
/* Overlay 2, GA 0xFF */
pHw->LCDC_OVR2CFG0 = LCDC_OVR2CFG0_DLBO | LCDC_OVR2CFG0_BLEN_AHB_INCR16
| LCDC_OVR2CFG0_ROTDIS
;
pHw->LCDC_OVR2CFG1 = LCDC_OVR2CFG1_RGBMODE_24BPP_RGB_888_PACKED;
pHw->LCDC_OVR2CFG9 = LCDC_OVR2CFG9_GA(0xFF) | LCDC_OVR2CFG9_GAEN;
/* High End Overlay, GA 0xFF */
pHw->LCDC_HEOCFG0 = LCDC_HEOCFG0_DLBO | LCDC_HEOCFG0_BLEN_AHB_BLEN_INCR16
| LCDC_HEOCFG0_ROTDIS
;
pHw->LCDC_HEOCFG1 = LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED;
pHw->LCDC_HEOCFG12 = LCDC_HEOCFG12_GA(0xFF) | LCDC_HEOCFG12_GAEN;
/* Hardware Cursor, GA 0xFF, Key #000000 */
pHw->LCDC_HCRCFG0 = LCDC_HCRCFG0_DLBO | LCDC_HCRCFG0_BLEN_AHB_BLEN_INCR16;
pHw->LCDC_HCRCFG1 = LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED;
pHw->LCDC_HCRCFG7 = 0x000000;
pHw->LCDC_HCRCFG8 = 0xFFFFFF;
pHw->LCDC_HCRCFG9 = LCDC_HCRCFG9_GA(0xFF) | LCDC_HCRCFG9_GAEN;
LCDD_On();
}
/**
* Check if specified layer is working.
* \param bLayer Layer ID.
* \return 1 if layer is on.
*/
uint8_t LCDD_IsLayerOn( uint8_t bLayer )
{
volatile uint32_t *pReg = pEnableReg(bLayer);
if (pReg) return ((pReg[2] & LCDC_BASECHSR_CHSR) > 0);
return 0;
}
/**
* Enable(turn on)/Disable(hide) specified layer.
* \param bLayer Layer ID.
* \param bEnDis Enable/Disable.
*/
void LCDD_EnableLayer( uint8_t bLayer, uint8_t bEnDis )
{
volatile uint32_t *pReg = pEnableReg(bLayer);
volatile uint32_t *pBlR = pBlenderReg(bLayer);
if (pReg && bLayer > LCDD_CONTROLLER)
{
if (bEnDis)
{
pReg[0] = LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN;
pBlR[0] |= LCDC_HEOCFG12_DMA | LCDC_HEOCFG12_OVR;
}
else
{
pReg[1] = LCDC_BASECHDR_CHDIS;
pBlR[0] &= ~(LCDC_HEOCFG12_DMA | LCDC_HEOCFG12_OVR);
}
}
}
/**
* Refresh layer
* \param bLayer Layer ID.
*/
void LCDD_Refresh( uint8_t bLayer )
{
volatile uint32_t *pBlR = pBlenderReg(bLayer);
volatile uint32_t *pEnR = pEnableReg(bLayer);
if (pBlR)
{
if (pEnR[2] & LCDC_OVR1CHSR_CHSR)
{
pBlR[0] |= LCDC_HEOCFG12_DMA;
pEnR[0] = LCDC_OVR1CHER_UPDATEEN;
}
}
}
/**
* Set display window position.
* \param bLayer Layer ID.
* \param x X position.
* \param y Y position.
*/
void LCDD_SetPosition( uint8_t bLayer,
uint32_t x, uint32_t y )
{
volatile uint32_t *pChReg = pEnableReg(bLayer);
volatile uint32_t *pXyReg = pWinReg(bLayer);
uint32_t w, h;
w = (pXyReg[1] & LCDC_OVR1CFG3_XSIZE_Msk) >> LCDC_OVR1CFG3_XSIZE_Pos;
h = (pXyReg[1] & LCDC_OVR1CFG3_YSIZE_Msk) >> LCDC_OVR1CFG3_YSIZE_Pos;
if (x+w >= BOARD_LCD_WIDTH) x = BOARD_LCD_WIDTH - w;
if (y+h >= BOARD_LCD_HEIGHT) y = BOARD_LCD_HEIGHT - h;
if (pXyReg)
{
pXyReg[0] = LCDC_OVR1CFG2_XPOS(x) | LCDC_OVR1CFG2_YPOS(y);
if (pChReg[2] & LCDC_OVR1CHSR_CHSR)
pChReg[0] = LCDC_OVR1CHER_UPDATEEN;
}
}
/**
* Set Prioty of layer (only for HEO now).
* \param bLayer Layer ID (HEO).
* \param bPri Prority value.
*/
void LCDD_SetPrioty( uint8_t bLayer, uint8_t bPri )
{
Lcdc * pHw = LCDC;
if ( bLayer != LCDD_HEO ) return;
if (bPri)
pHw->LCDC_HEOCFG12 |= LCDC_HEOCFG12_VIDPRI;
else
pHw->LCDC_HEOCFG12 &= ~LCDC_HEOCFG12_VIDPRI;
pHw->LCDC_HEOCHER = LCDC_HEOCHER_UPDATEEN;
}
/**
* Return Prioty of layer (only for HEO now).
* \param bLayer Layer ID (HEO).
*/
uint8_t LCDD_GetPrioty( uint8_t bLayer )
{
Lcdc * pHw = LCDC;
if ( bLayer != LCDD_HEO ) return 0;
return (pHw->LCDC_HEOCFG12 & LCDC_HEOCFG12_VIDPRI) > 0;
}
/**
* Global & Local Alpha Enable/Disable
* \param bLayer Layer ID.
* \param bEnDisLA Enable/Disable local alpha.
* \param bEnDisGA Enable/Disable global alpha.
*/
void LCDD_EnableAlpha( uint8_t bLayer,
uint8_t bEnDisLA,
uint8_t bEnDisGA )
{
volatile uint32_t *pEnR = pEnableReg(bLayer);
volatile uint32_t *pCfgR = pBlenderReg(bLayer);
uint32_t cfg;
if (pCfgR)
{
cfg = (*pCfgR) & ~(LCDC_OVR1CFG9_LAEN | LCDC_OVR1CFG9_GAEN);
if (bEnDisGA) cfg |= LCDC_OVR1CFG9_GAEN;
if (bEnDisLA) cfg |= LCDC_OVR1CFG9_LAEN;
(*pCfgR) = cfg;
pEnR[0] = LCDC_OVR1CHER_UPDATEEN;
}
}
/**
* Set alpha value
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param bReverse Reverse alpha (alpha -> 1 - alpha).
* \param bAlpha Global alpha value.
*/
void LCDD_SetAlpha( uint8_t bLayer,
uint8_t bReverse,
uint8_t bAlpha )
{
volatile uint32_t *pEnR = pEnableReg(bLayer);
volatile uint32_t *pCfgR = pBlenderReg(bLayer);
uint32_t cfg;
if (pCfgR)
{
cfg = (*pCfgR) & ~(LCDC_OVR1CFG9_REVALPHA | LCDC_OVR1CFG9_GA_Msk);
if (bReverse) cfg |= LCDC_OVR1CFG9_REVALPHA;
(*pCfgR) = cfg | LCDC_OVR1CFG9_GA(bAlpha);
pEnR[0] = LCDC_OVR1CHER_UPDATEEN;
}
}
/**
* Get alpha value
* \param bLayer Layer ID (OVR1, HEO or CUR).
*/
uint8_t LCDD_GetAlpha( uint8_t bLayer )
{
Lcdc * pHw = LCDC;
volatile uint32_t *pCfg;
uint32_t bmMask = LCDC_OVR1CFG9_GA_Msk;
uint32_t bShift = LCDC_OVR1CFG9_GA_Pos;
switch( bLayer )
{
case LCDD_OVR1: pCfg = (volatile uint32_t *)&pHw->LCDC_OVR1CFG9; break;
case LCDD_OVR2: pCfg = (volatile uint32_t *)&pHw->LCDC_OVR2CFG9; break;
case LCDD_HEO: pCfg = (volatile uint32_t *)&pHw->LCDC_HEOCFG9; break;
case LCDD_CUR: pCfg = (volatile uint32_t *)&pHw->LCDC_HCRCFG9; break;
default: return 0;
}
return (((*pCfg) >> bShift) & bmMask);
}
/**
* Enable and Set Color Keying
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param bDstSrc Destination/Source keying.
* \param dwColor Color to matching.
* \param dwMask Color bit mask.
*/
void LCDD_SetColorKeying( uint8_t bLayer, uint8_t bDstSrc,
uint32_t dwColor, uint32_t dwMask )
{
volatile uint32_t *pEnR = pEnableReg(bLayer);
volatile uint32_t *pBCfgR = pBlenderReg(bLayer);
volatile uint32_t *pColorR = pColorReg(bLayer);
if (pBCfgR == NULL) return;
/* Select the Overlay to Blit */
/* Dest/Source Keying */
if (bDstSrc) *pBCfgR |= LCDC_HEOCFG12_DSTKEY;
else *pBCfgR &= ~LCDC_HEOCFG12_DSTKEY;
/* Activate Color Keying */
*pBCfgR |= LCDC_HEOCFG12_CRKEY;
/* Program Color Keying */
pColorR[1] = dwColor;
pColorR[2] = dwMask;
/* Update */
pEnR[0] = LCDC_HEOCHER_UPDATEEN;
}
/**
* Disable Color Keying
* \param bLayer Layer ID (OVR1, HEO or CUR).
*/
void LCDD_DisableColorKeying( uint8_t bLayer )
{
volatile uint32_t *pEnR = pEnableReg(bLayer);
volatile uint32_t *pBCfgR = pBlenderReg(bLayer);
volatile uint32_t *pColorR = pColorReg(bLayer);
if (pBCfgR == NULL) return;
*pBCfgR &= ~LCDC_HEOCFG12_CRKEY;
pColorR[2] = 0;
/* Update */
pEnR[0] = LCDC_HEOCHER_UPDATEEN;
}
/**
* Set Color Lookup Table
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param pCLUT Pointer to color lookup table.
* \param bpp Bits Per Pixel (1, 2, 4, 8).
* \param nbColors Number of colors indexed in table.
*/
void LCDD_SetCLUT( uint8_t bLayer,
uint32_t *pCLUT,
uint8_t bpp, uint8_t nbColors )
{
//Lcdc *pHw = LCDC;
volatile uint32_t* pCLUTR = pCLUTReg(bLayer);
sCLUTInfo * pInfo = &pLayer(bLayer)->clut;
if (pInfo == NULL) return;
pInfo->bpp = bpp;
/* Customize CLUT */
if (pCLUT)
{
uint32_t i;
if (nbColors == 0) nbColors = 1 << bpp;
pInfo->nbColors = nbColors;
for (i = 0; i < nbColors; i ++) pCLUTR[i] = pCLUT[i];
}
/* Build CLUT */
else
{
pInfo->nbColors = 1 << bpp;
switch (bpp)
{
case 1: LCDD_BuildCLUT1(pCLUTR); break;
case 2: LCDD_BuildCLUT2(pCLUTR); break;
case 4: LCDD_BuildCLUT4(pCLUTR); break;
case 8: LCDD_BuildCLUT8(pCLUTR); break;
}
}
}
/**
* Display an image on specified layer.
* (Image scan origion: Left -> Right, Top -> Bottom.)
* \note w & h should be the rotated result.
* \note for LCDD_BASE: x, y don't care. w always > 0.
* \note for LCDD_HEO:imgW & imgH is used.
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param pBuffer Pointer to image data.
* \param bPP Bits Per Pixel.
* - 16: TRGB 1555
* - 24: RGB 888 packed
* - 32: ARGB 8888
* \param x X position.
* \param y Y position.
* \param w Width (<0 means Right -> Left data).
* \param h Height (<0 means Bottom -> Top data).
* \param imgW Source image width.
* \param imgH Source image height.
* \param wRotate Rotation (clockwise, 0, 90, 180, 270 accepted).
*/
void *LCDD_ShowBMPRotated( uint8_t bLayer,
void* pBuffer, uint8_t bpp,
uint32_t x, uint32_t y,
int32_t w, int32_t h,
uint32_t imgW, uint32_t imgH,
int16_t wRotate)
{
//Lcdc *pHw = LCDC;
sLayer *pLD = pLayer(bLayer);
//sCLUTInfo *pClut = &pLD->clut;
sLCDCDescriptor *pTD = &pLD->dmaD;
volatile uint32_t *pEnR = pEnableReg(bLayer);
volatile uint32_t *pDmaR = pHeadReg(bLayer);
volatile uint32_t *pWinR = pWinReg(bLayer);
volatile uint32_t *pStrR = pStrideReg(bLayer);
volatile uint32_t *pSclR = pScaleReg(bLayer);
volatile uint32_t *pBlR = pBlenderReg(bLayer);
volatile uint32_t *pCfgR = pCfgReg(bLayer);
uint8_t bPStride = LCDD_IsPStrideSupported(bLayer);
uint8_t bBottomUp = (h < 0);
uint8_t bRightLeft = (w < 0);
uint32_t padding = 0;
int32_t srcW, srcH;
uint32_t bitsPRow, bytesPRow;
uint32_t bytesPPix = bpp >> 3;
void* pOldBuffer = pLD->pBuffer;
if (pCfgR == NULL) return pOldBuffer;
//printf("Show %x @ %d: (%d,%d)+(%d,%d) img %d x %d * %d\n\r", pBuffer, bLayer, x, y, w, h, imgW, imgH, bpp);
switch (bpp)
{
case 16: /* RGB 565 */
if((pCfgR[1] & LCDC_HEOCFG1_YUVEN)!= LCDC_HEOCFG1_YUVEN)
{
pCfgR[1] = LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565;//LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555;
}
break;
case 24: /* RGB 888 packed */
pCfgR[1] = LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED;
break;
case 32: /* ARGB 8888 */
pCfgR[1] = LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888;
break;
default: return pOldBuffer;
}
/* Windows position & size check */
if (h < 0) h =- h;
if (w < 0) w =- w;
if (x + w > BOARD_LCD_WIDTH)
{
//printf("! w %d -> %d\n\r", w, BOARD_LCD_WIDTH-x);
w = BOARD_LCD_WIDTH - x;
}
if (y + h > BOARD_LCD_HEIGHT)
{
//printf("! h %d -> %d\n\r", h, BOARD_LCD_HEIGHT-y);
h = BOARD_LCD_HEIGHT - y;
}
if (w == 0) w ++;
if (h == 0) h ++;
if (imgW == 0) imgW ++;
if (imgH == 0) imgH ++;
/* Only 0,(-)90,(-)180,(-)270 accepted */
switch(wRotate)
{
case 0: case 90: case 180: case 270:
break;
case -90: case -180: case -270:
wRotate += 360;
break;
default: return NULL;
}
/* Setup display buffer & window */
if (pBuffer) pLD->pBuffer = pBuffer;
else pBuffer = pLD->pBuffer;
/* Set display buffer & mode */
bitsPRow = imgW * bpp;
bytesPRow = bitsPRow >> 3;
if (bitsPRow & 0x7) bytesPRow ++;
if (bytesPRow & 0x3) padding = 4 - (bytesPRow & 0x3);
/* No X mirror supported layer, no Right->Left scan */
if (!bPStride) bRightLeft = 0;
/* --------- Mirror & then rotate --------- */
/* Normal direction: Left,Top -> Right,Down */
if ( (!bRightLeft && !bBottomUp && wRotate == 0)
|| ( bRightLeft && bBottomUp && wRotate == 180) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* X0 ++ */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0);
/* Y0 ++ */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(padding);
/* Pointer to Left,Top (x0,y0) */
}
/* X mirror: Right,Top -> Left,Down */
else if ( ( bRightLeft && !bBottomUp && wRotate == 0)
||(!bRightLeft && bBottomUp && wRotate == 180) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* X1 -- */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0-2*bytesPPix);
/* Y0 ++ */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(bytesPRow*2+padding-2*bytesPPix);
/* Pointer to Right,Top (x1,y0) */
pBuffer = (void*)((uint32_t)pBuffer
+ bytesPPix*(imgW-1));
}
/* Y mirror: Left,Down -> Right,Top */
else if ( (!bRightLeft && bBottomUp && wRotate == 0)
||( bRightLeft && !bBottomUp && wRotate == 180) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* X0 ++ */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0);
/* Y1 -- */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(0-(bytesPRow*2+padding));
/* Pointer to Left,Down (x0,y1) */
pBuffer = (void*)((uint32_t)pBuffer
+ (bytesPRow+padding)*(imgH-1));
}
/* X,Y mirror: Right,Top -> Left,Down */
else if ( ( bRightLeft && bBottomUp && wRotate == 0)
||(!bRightLeft && !bBottomUp && wRotate == 180) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* X1 -- */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0-2*bytesPPix);
/* Y1 -- */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(0-(bytesPPix*2+padding));
/* Pointer to Left,Down (x1,y1) */
pBuffer = (void*)((uint32_t)pBuffer
+ (bytesPRow+padding)*(imgH-1)
+ (bytesPPix)*(imgW-1));
}
/* Rotate 90: Down,Left -> Top,Right (with w,h swap) */
else if ( (!bRightLeft && !bBottomUp && wRotate == 90)
||( bRightLeft && bBottomUp && wRotate == 270) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* Y -- as pixels in row */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0-(bytesPPix+bytesPRow+padding));
/* X ++ as rows */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE((bytesPRow+padding)*(imgH-1));
/* Pointer to Bottom,Left */
pBuffer = (void*)((uint32_t)pBuffer
+ (bytesPRow+padding)*(imgH-1));
}
/* Rotate 270: Top,Right -> Down,Left (with w,h swap) */
else if ( (!bRightLeft && !bBottomUp && wRotate == 270)
||( bRightLeft && bBottomUp && wRotate == 90) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* Y ++ as pixels in row */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(bytesPRow+padding-bytesPPix);
/* X -- as rows */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(0-2*bytesPPix-(bytesPRow+padding)*(imgH-1));
/* Pointer to top right */
pBuffer = (void*)((uint32_t)pBuffer
+ bytesPPix*(imgW-1));
}
/* Mirror X then Rotate 90: Down,Right -> Top,Left */
else if ( ( bRightLeft && !bBottomUp && wRotate == 90)
||(!bRightLeft && bBottomUp && wRotate == 270) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* Y -- as pixels in row */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(0-(bytesPPix+bytesPRow+padding));
/* X -- as rows */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(0-2*bytesPPix+(bytesPRow+padding)*(imgH-1));
/* Pointer to down right (x1,y1) */
pBuffer = (void*)((uint32_t)pBuffer
+ (bytesPRow+padding)*(imgH-1)
+ (bytesPPix)*(imgW-1));
}
/* Mirror Y then Rotate 90: Top,Left -> Down,Right */
else if ( (!bRightLeft && bBottomUp && wRotate == 90)
||( bRightLeft && !bBottomUp && wRotate == 270) )
{
/* No rotation optimization */
pCfgR[0] |= LCDC_HEOCFG0_ROTDIS;
/* Y ++ as pixels in row */
if (bPStride) pStrR[1] = LCDC_HEOCFG6_PSTRIDE(bytesPRow+padding-bytesPPix);
/* X ++ as rows */
pStrR[0] = LCDC_HEOCFG5_XSTRIDE(0-(bytesPRow+padding)*(imgH-1));
/* Pointer to top left (x0,y0) */
}
/** DMA is running, just add new descriptor to queue */
if (pBlR[0] & LCDC_HEOCFG12_DMA)
{
pTD->addr = (uint32_t)pBuffer;
pTD->ctrl = LCDC_HEOCTRL_DFETCH;
pTD->next = (uint32_t)pTD;
pDmaR[0] = (uint32_t)pTD;
pEnR[0] = LCDC_HEOCHER_A2QEN;
}
else
{
/* 2. Write the channel descriptor (DSCR) structure in the system memory by
writing DSCR.CHXADDR Frame base address, DSCR.CHXCTRL channel control
and DSCR.CHXNEXT next descriptor location.
3. If more than one descriptor is expected, the DFETCH field of
DSCR.CHXCTRL is set to one to enable the descriptor fetch operation.
4. Write the DSCR.CHXNEXT register with the address location of the
descriptor structure and set DFETCH field of the DSCR.CHXCTRL register
to one. */
LCDD_SetDMA(pBuffer, pTD, (uint32_t)pDmaR);
}
CP15_flush_dcache_for_dma ((uint32_t)pTD, ((uint32_t)pTD) + sizeof(pTD));
/* Set window & position */
if (pWinR)
{
pWinR[0] = LCDC_HEOCFG2_XPOS(x) | LCDC_HEOCFG2_YPOS(y);
pWinR[1] = LCDC_HEOCFG3_XSIZE(w-1) | LCDC_HEOCFG3_YSIZE(h-1);
}
/* Scaling setup */
if (pSclR)
{
/* Image size only used in scaling */
/* Scaling target */
if (wRotate == 90 || wRotate == 270)
{
srcW = imgH; srcH = imgW;
}
else
{
srcW = imgW; srcH = imgH;
}
pWinR[2] = LCDC_HEOCFG4_XMEM_SIZE(srcW-1) | LCDC_HEOCFG4_YMEM_SIZE(srcH-1);
/* Scaled */
if (w != srcW || h != srcH)
{
uint16_t wYf, wXf;
wXf = LCDD_CalcScaleFactor(w, srcW);
wYf = LCDD_CalcScaleFactor(h, srcH);
//printf("- Scale(%d,%d)\n\r", wXf, wYf);
pSclR[0] = LCDC_HEOCFG13_YFACTOR(wYf)
| LCDC_HEOCFG13_XFACTOR(wXf)
| LCDC_HEOCFG13_SCALEN
;
}
/* Disable scaling */
else
{
pSclR[0] = 0;
}
}
/* Enable DMA */
if (pBuffer)
{
pBlR[0] |= LCDC_HEOCFG12_DMA
| LCDC_HEOCFG12_OVR
;
}
/* Enable & Update */
/* 5. Enable the relevant channel by writing one to the CHEN field of the
CHXCHER register. */
pEnR[0] = LCDC_HEOCHER_UPDATEEN | LCDC_HEOCHER_CHEN;
/* 6. An interrupt may be raised if unmasked when the descriptor has been
loaded. */
return pOldBuffer;
}
/**
* Display an image on specified layer.
* (Image scan: Left -> Right, Top -> Bottom.)
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param pBuffer Pointer to image data.
* \param bPP Bits Per Pixel.
* - 16: TRGB 1555
* - 24: RGB 888 packed
* - 32: ARGB 8888
* \param x X position.
* \param y Y position.
* \param w Width (<0 means Right -> Left data).
* \param h Height (<0 means Bottom -> Top data).
* \param imgW Source image width.
* \param imgH Source image height.
* \return Pointer to old display image data.
*/
void *LCDD_ShowBMPScaled( uint8_t bLayer,
void* pBuffer, uint8_t bpp,
uint32_t x, uint32_t y,
int32_t w, int32_t h,
uint32_t imgW, uint32_t imgH )
{
return LCDD_ShowBMPRotated(bLayer, pBuffer, bpp,
x, y, w, h, imgW, imgH, 0);
}
/**
* Display an image on specified layer.
* (Image scan: Left -> Right, Top -> Bottom.)
* \param bLayer Layer ID (OVR1, HEO or CUR).
* \param pBuffer Pointer to image data.
* \param bPP Bits Per Pixel.
* - 16: TRGB 1555
* - 24: RGB 888 packed
* - 32: ARGB 8888
* \param x X position.
* \param y Y position.
* \param w Width
* \param h Height (<0 means Bottom -> Top data).
* \return Pointer to old display image data.
*/
void *LCDD_ShowBMP( uint8_t bLayer,
void* pBuffer, uint8_t bpp,
uint32_t x, uint32_t y,
int32_t w, int32_t h )
{
return LCDD_ShowBMPRotated(bLayer, pBuffer, bpp,
x, y, w, h,
w, (h < 0) ? (-h) : h,
0);
}
/**
* Start display on base layer
* \param pBuffer Pointer to image data.
* \param bpp Bits Per Pixel.
* \param bBottomUp Scan from bottom to top.
* \return Pointer to old display image data.
*/
void *LCDD_ShowBase( void* pBuffer, uint8_t bpp, uint8_t bBottomUp )
{
return LCDD_ShowBMP(LCDD_BASE, pBuffer, bpp,
0, 0,
BOARD_LCD_WIDTH,
bBottomUp ? -BOARD_LCD_HEIGHT : BOARD_LCD_HEIGHT);
}
/**
* Stop display on base layer
*/
void LCDD_StopBase( void )
{
Lcdc *pHw = LCDC;
if (!(pHw->LCDC_BASECHSR & LCDC_BASECHSR_CHSR))
return;
/* 1. Clear the DFETCH bit in the DSCR.CHXCTRL field of the DSCR structure
will disable the channel at the end of the frame. */
/* 2. Set the DSCR.CHXNEXT field of the DSCR structure will disable the
channel at the end of the frame. */
LCDD_ClearDMA(&lcddBase.dmaD, (uint32_t)&pHw->LCDC_BASEADDR);
/* 3. Writing one to the CHDIS field of the CHXCHDR register will disable
the channel at the end of the frame. */
pHw->LCDC_BASECHDR = LCDC_BASECHDR_CHDIS;
/* 4. Writing one to the CHRST field of the CHXCHDR register will disable
the channel immediately. This may occur in the middle of the image. */
/* 5. Poll CHSR field in the CHXCHSR register until the channel is
successfully disabled. */
while (pHw->LCDC_BASECHSR & LCDC_BASECHSR_CHSR);
}
/**
* Start display on overlay 1 layer
*/
void *LCDD_ShowOvr1( void* pBuffer, uint8_t bpp,
uint32_t x, uint32_t y, int32_t w, int32_t h )
{
return LCDD_ShowBMP(LCDD_OVR1,
pBuffer, bpp, x, y, w, h);
}
/**
* Stop display on overlay 1 layer
*/
void LCDD_StopOvr1( void )
{
Lcdc *pHw = LCDC;
if (!(pHw->LCDC_OVR1CHSR & LCDC_OVR1CHSR_CHSR))
return;
/* 1. Clear the DFETCH bit in the DSCR.CHXCTRL field of the DSCR structure
will disable the channel at the end of the frame. */
/* 2. Set the DSCR.CHXNEXT field of the DSCR structure will disable the
channel at the end of the frame. */
LCDD_ClearDMA(&lcddOvr1.dmaD, (uint32_t)&pHw->LCDC_OVR1ADDR);
/* 3. Writing one to the CHDIS field of the CHXCHDR register will disable
the channel at the end of the frame. */
pHw->LCDC_OVR1CHDR = LCDC_OVR1CHDR_CHDIS;
/* 4. Writing one to the CHRST field of the CHXCHDR register will disable
the channel immediately. This may occur in the middle of the image. */
/* 5. Poll CHSR field in the CHXCHSR register until the channel is
successfully disabled. */
while (pHw->LCDC_OVR1CHSR & LCDC_OVR1CHSR_CHSR);
}
/**
* Start display on High End Overlay layer
*/
void * LCDD_ShowHeo( void *pBuffer, uint8_t bpp,
uint32_t x, uint32_t y, int32_t w, int32_t h,
uint32_t imgW, uint32_t imgH )
{
return LCDD_ShowBMPRotated(LCDD_HEO,
pBuffer, bpp,
x, y, w, h,
imgW,imgH,
0);
}
/**
* Stop display on High End Overlay layer
*/
void LCDD_StopHeo( void )
{
Lcdc *pHw = LCDC;
if (!(pHw->LCDC_HEOCHSR & LCDC_HEOCHSR_CHSR))
return;
/* 1. Clear the DFETCH bit in the DSCR.CHXCTRL field of the DSCR structure
will disable the channel at the end of the frame. */
/* 2. Set the DSCR.CHXNEXT field of the DSCR structure will disable the
channel at the end of the frame. */
LCDD_ClearDMA(&lcddHeo.dmaD[0], (uint32_t)&pHw->LCDC_HEOADDR);
LCDD_ClearDMA(&lcddHeo.dmaD[1], (uint32_t)&pHw->LCDC_HEOUADDR);
LCDD_ClearDMA(&lcddHeo.dmaD[2], (uint32_t)&pHw->LCDC_HEOVADDR);
/* 3. Writing one to the CHDIS field of the CHXCHDR register will disable
the channel at the end of the frame. */
pHw->LCDC_HEOCHDR = LCDC_HEOCHDR_CHDIS;
/* 4. Writing one to the CHRST field of the CHXCHDR register will disable
the channel immediately. This may occur in the middle of the image. */
/* 5. Poll CHSR field in the CHXCHSR register until the channel is
successfully disabled. */
while (pHw->LCDC_HEOCHSR & LCDC_HEOCHSR_CHSR);
}
/**
* Start display on Hardware Cursor layer
* (Default transparent color is set to #000000, black)
*/
void *LCDD_ShowHcr( void* pBuffer, uint8_t bpp,
uint32_t x, uint32_t y, int32_t w, int32_t h )
{
Lcdc *pHw = LCDC;
/* Enable default transparent keying */
if (!(pHw->LCDC_HCRCFG9 & LCDC_HCRCFG9_CRKEY))
{
pHw->LCDC_HCRCFG7 = 0x000000;
pHw->LCDC_HCRCFG8 = 0xFFFFFF;
pHw->LCDC_HCRCFG9 |= LCDC_HCRCFG9_CRKEY;
}
return LCDD_ShowBMP(LCDD_CUR,
pBuffer, bpp,
x, y, w, h);
}
/**
* Stop display on Hardware Cursor layer
*/
void LCDD_StopHcr( void )
{
Lcdc *pHw = LCDC;
if (!(pHw->LCDC_HCRCHDR & LCDC_HCRCHSR_CHSR))
return;
/* 1. Clear the DFETCH bit in the DSCR.CHXCTRL field of the DSCR structure
will disable the channel at the end of the frame. */
/* 2. Set the DSCR.CHXNEXT field of the DSCR structure will disable the
channel at the end of the frame. */
LCDD_ClearDMA(&lcddHcc.dmaD, (uint32_t)&pHw->LCDC_HCRADDR);
/* 3. Writing one to the CHDIS field of the CHXCHDR register will disable
the channel at the end of the frame. */
pHw->LCDC_HCRCHDR = LCDC_HCRCHDR_CHDIS;
/* 4. Writing one to the CHRST field of the CHXCHDR register will disable
the channel immediately. This may occur in the middle of the image. */
/* 5. Poll CHSR field in the CHXCHSR register until the channel is
successfully disabled. */
while (pHw->LCDC_HCRCHSR & LCDC_HCRCHSR_CHSR);
}
/**
* \brief Turn on the LCD.
*/
void LCDD_On(void)
{
Pmc *pPmc = PMC;
Lcdc *pHw = LCDC;
/* Enable peripheral clock */
PMC_EnablePeripheral(ID_LCDC);
pPmc->PMC_SCER = (0x1u << 3);
/* 1. Configure LCD timing parameters, signal polarity and clock period. */
pHw->LCDC_LCDCFG0 = LCDC_LCDCFG0_CLKDIV((BOARD_MCK*2)/BOARD_LCD_PIXELCLOCK-2)
|LCDC_LCDCFG0_CGDISHCR
|LCDC_LCDCFG0_CGDISHEO
|LCDC_LCDCFG0_CGDISOVR1
|LCDC_LCDCFG0_CGDISOVR2
|LCDC_LCDCFG0_CGDISBASE
|LCDC_LCDCFG0_CLKPWMSEL
|LCDC_LCDCFG0_CLKSEL
|LCDC_LCDCFG0_CLKPOL;
pHw->LCDC_LCDCFG1 = LCDC_LCDCFG1_VSPW(BOARD_LCD_TIMING_VPW-1)
|LCDC_LCDCFG1_HSPW(BOARD_LCD_TIMING_HPW-1);
pHw->LCDC_LCDCFG2 = LCDC_LCDCFG2_VBPW(BOARD_LCD_TIMING_VBP)
|LCDC_LCDCFG2_VFPW(BOARD_LCD_TIMING_VFP-1);
pHw->LCDC_LCDCFG3 = LCDC_LCDCFG3_HBPW(BOARD_LCD_TIMING_HBP-1)
|LCDC_LCDCFG3_HFPW(BOARD_LCD_TIMING_HFP-1);
pHw->LCDC_LCDCFG4 = LCDC_LCDCFG4_RPF(BOARD_LCD_HEIGHT-1)
|LCDC_LCDCFG4_PPL(BOARD_LCD_WIDTH-1);
pHw->LCDC_LCDCFG5 = LCDC_LCDCFG5_GUARDTIME(30)
|LCDC_LCDCFG5_MODE_OUTPUT_24BPP
|LCDC_LCDCFG5_DISPDLY
|LCDC_LCDCFG5_VSPDLYS
|LCDC_LCDCFG5_VSPOL
|LCDC_LCDCFG5_HSPOL;
pHw->LCDC_LCDCFG6 = LCDC_LCDCFG6_PWMCVAL(0xF0)
|LCDC_LCDCFG6_PWMPOL
|LCDC_LCDCFG6_PWMPS(6);
/* 2. Enable the Pixel Clock by writing one to the CLKEN field of the
LCDC_LCDEN register. */
pHw->LCDC_LCDEN = LCDC_LCDEN_CLKEN;
/* 3. Poll CLKSTS field of the LCDC_LCDSR register to check that the clock
is running. */
while(!(pHw->LCDC_LCDSR & LCDC_LCDSR_CLKSTS));
/* 4. Enable Horizontal and Vertical Synchronization by writing one to the
SYNCEN field of the LCDC_LCDEN register. */
pHw->LCDC_LCDEN = LCDC_LCDEN_SYNCEN;
/* 5. Poll LCDSTS field of the LCDC_LCDSR register to check that the
synchronization is up. */
while(!(pHw->LCDC_LCDSR & LCDC_LCDSR_LCDSTS));
/* 6. Enable the display power signal writing one to the DISPEN field of the
LCDC_LCDEN register. */
pHw->LCDC_LCDEN = LCDC_LCDEN_DISPEN;
/* 7. Poll DISPSTS field of the LCDC_LCDSR register to check that the power
signal is activated. */
while(!(pHw->LCDC_LCDSR & LCDC_LCDSR_DISPSTS));
/* 8. Enable backlight */
pHw->LCDC_LCDEN = LCDC_LCDEN_PWMEN;
}
/**
* \brief Turn off the LCD.
*/
void LCDD_Off(void)
{
Lcdc *pHw = LCDC;
Pmc *pPmc = PMC;
/* 1. Clear the DFETCH bit in the DSCR.CHXCTRL field of the DSCR structure
will disable the channel at the end of the frame. */
/* 2. Set the DSCR.CHXNEXT field of the DSCR structure will disable the
channel at the end of the frame. */
/* Disable all DMA channel descriptors */
LCDD_ClearDMA(&lcddBase.dmaD, (uint32_t)&pHw->LCDC_BASEADDR);
LCDD_ClearDMA(&lcddOvr1.dmaD, (uint32_t)&pHw->LCDC_OVR1ADDR);
LCDD_ClearDMA(&lcddOvr2.dmaD, (uint32_t)&pHw->LCDC_OVR2ADDR);
LCDD_ClearDMA(&lcddHeo.dmaD[0], (uint32_t)&pHw->LCDC_HEOADDR);
LCDD_ClearDMA(&lcddHeo.dmaD[1], (uint32_t)&pHw->LCDC_HEOUADDR);
LCDD_ClearDMA(&lcddHeo.dmaD[2], (uint32_t)&pHw->LCDC_HEOVADDR);
LCDD_ClearDMA(&lcddHcc.dmaD, (uint32_t)&pHw->LCDC_HCRADDR);
/* 3. Writing one to the CHDIS field of the CHXCHDR register will disable
the channel at the end of the frame. */
/* Disable DMA channels */
pHw->LCDC_BASECHDR = LCDC_BASECHDR_CHDIS;
pHw->LCDC_OVR1CHDR = LCDC_OVR1CHDR_CHDIS;
pHw->LCDC_HEOCHDR = LCDC_HEOCHDR_CHDIS;
pHw->LCDC_HCRCHDR = LCDC_HCRCHDR_CHDIS;
pHw->LCDC_BASECFG4 = 0;
/* 4. Writing one to the CHRST field of the CHXCHDR register will disable
the channel immediately. This may occur in the middle of the image. */
/* 5. Poll CHSR field in the CHXCHSR register until the channel is
successfully disabled. */
while (pHw->LCDC_BASECHSR & LCDC_BASECHSR_CHSR);
while (pHw->LCDC_OVR1CHSR & LCDC_OVR1CHSR_CHSR);
while (pHw->LCDC_HEOCHSR & LCDC_HEOCHSR_CHSR);
while (pHw->LCDC_HCRCHDR & LCDC_HCRCHSR_CHSR);
/* Timing Engine Power Down Software Operation */
/* Disable backlight */
pHw->LCDC_LCDDIS = LCDC_LCDDIS_PWMDIS;
while (pHw->LCDC_LCDSR & LCDC_LCDSR_PWMSTS);
/* 1. Disable the DISP signal writing DISPDIS field of the LCDC_LCDDIS
register. */
pHw->LCDC_LCDDIS = LCDC_LCDDIS_DISPDIS;
/* 2. Poll DISPSTS field of the LCDC_LCDSR register to verify that the DISP
is no longer activated. */
while (pHw->LCDC_LCDSR & LCDC_LCDSR_DISPSTS);
/* 3. Disable the hsync and vsync signals by writing one to SYNCDIS field of
the LCDC_LCDDIS register. */
pHw->LCDC_LCDDIS = LCDC_LCDDIS_SYNCDIS;
/* 4. Poll LCDSTS field of the LCDC_LCDSR register to check that the
synchronization is off. */
while (pHw->LCDC_LCDSR & LCDC_LCDSR_LCDSTS);
/* 5. Disable the Pixel clock by writing one in the CLKDIS field of the
LCDC_LCDDIS register. */
pHw->LCDC_LCDDIS = LCDC_LCDDIS_CLKDIS;
/* 6. Poll CLKSTS field of the LCDC_LCDSR register to check that Pixel Clock
is disabled. */
while(pHw->LCDC_LCDSR & LCDC_LCDSR_CLKSTS);
/* Disable peripheral clock */
PMC_DisablePeripheral(ID_LCDC);
/* LCD Clock Disable */
pPmc->PMC_SCDR = (0x1u << 3);
}
/**
* \brief Set the backlight of the LCD.
*
* \param level Backlight brightness level [1..255],
* 255 means maximum brightness.
*/
void LCDD_SetBacklight (uint32_t level)
{
Lcdc *pHw = LCDC;
uint32_t cfg = pHw->LCDC_LCDCFG6 & ~LCDC_LCDCFG6_PWMCVAL_Msk;
pHw->LCDC_LCDCFG6 = cfg | LCDC_LCDCFG6_PWMCVAL(level);
}
/**
* Get canvas layer for LCDD_Draw*
* \return Layer information pointer.
*/
sLCDDLayer *LCDD_GetCanvas(void)
{
return &lcddCanvas;
}
/**
* Flush the current canvas layer*
*/
void LCDD_Flush_CurrentCanvas(void)
{
sLCDDLayer *pCurrentLayer;
uint32_t base, height, width;
pCurrentLayer = LCDD_GetCanvas();
base = (uint32_t)pCurrentLayer->pBuffer;
height = pCurrentLayer->wImgH;
width = pCurrentLayer->wImgW;
CP15_flush_dcache_for_dma ((uint32_t)base, ((uint32_t)base) + height*width*4);
}
/**
* Select an LCD layer as canvas layer.
* Then all drawing operations will apply to current display buffer
* of selected layer.
* \note If there is no display buffer for the layer (not running)
* selection fails.
*/
uint8_t LCDD_SelectCanvas(uint8_t bLayer)
{
sLayer *pLD = pLayer(bLayer);
volatile uint32_t *pXyR = pWinReg(bLayer);
volatile uint32_t *pCfR = pCfgReg(bLayer);
if (pLD == NULL) return 0;
lcddCanvas.pBuffer = (void*)pLD->pBuffer;
if (pXyR)
{
lcddCanvas.wImgW = (pXyR[1] & LCDC_HEOCFG3_XSIZE_Msk) >> LCDC_HEOCFG3_XSIZE_Pos;
lcddCanvas.wImgH = (pXyR[1] & LCDC_HEOCFG3_YSIZE_Msk) >> LCDC_HEOCFG3_YSIZE_Pos;
}
else
{
lcddCanvas.wImgW = BOARD_LCD_WIDTH;
lcddCanvas.wImgH = BOARD_LCD_HEIGHT;
}
lcddCanvas.bMode = LCDD_GetBitsPerPixel(pCfR[1] & LCDC_HEOCFG1_RGBMODE_Msk);
lcddCanvas.bLayer = bLayer;
return 1;
}
/**
* Create a blank canvas on a display layer for further operations.
* \param bLayer Layer ID.
* \param pBuffer Pointer to canvas display buffer.
* \param bBPP Bits Per Pixel.
* \param wX Canvas X coordinate on base.
* \param wY Canvas Y coordinate on base.
* \param wW Canvas width.
* \param wH Canvas height.
* \note The content in buffer is destroied.
*/
void *LCDD_CreateCanvas(uint8_t bLayer,
void* pBuffer, uint8_t bBPP,
uint16_t wX, uint16_t wY,
uint16_t wW, uint16_t wH )
{
void* pOldBuffer;
uint32_t maxW = BOARD_LCD_WIDTH;
uint32_t maxH = BOARD_LCD_HEIGHT;
uint32_t bitsPR, bytesPR;
switch (bLayer)
{
case LCDD_BASE:
wX = 0; wY = 0;
break;
case LCDD_OVR1:case LCDD_OVR2: case LCDD_HEO:
/* Size check */
if (wX + wW > BOARD_LCD_WIDTH || wY + wH > BOARD_LCD_HEIGHT)
return NULL;
break;
case LCDD_CUR:
/* Size check */
if (wX + wW > BOARD_LCD_WIDTH || wY + wH > BOARD_LCD_HEIGHT
|| wW > 128 || wH > 128)
return NULL;
maxW = maxH = 128;
break;
}
if (wW == 0) wW = maxW - wX;
if (wH == 0) wH = maxH - wY;
bitsPR = wW * bBPP;
bytesPR = (bitsPR&0x7) ? (bitsPR/8 + 1) : (bitsPR/8);
memset(pBuffer, 0xFF, bytesPR*wH);
pOldBuffer = LCDD_ShowBMPRotated(bLayer, pBuffer, bBPP,
wX, wY, wW, wH, wW, wH,
0);
lcddCanvas.bLayer = bLayer;
lcddCanvas.bMode = bBPP;
lcddCanvas.pBuffer = pBuffer;
lcddCanvas.wImgW = wW;
lcddCanvas.wImgH = wH;
return pOldBuffer;
}
/**@}*/
#endif /* ifdef LCDC */