/**
  ******************************************************************************
  * File Name          : STM32DMA.cpp
  ******************************************************************************
  * This file is generated by TouchGFX Generator 4.21.2. Please, do not edit!
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_dma2d.h"
#include <STM32DMA.hpp>
#include <cassert>
#include <touchgfx/Color.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/OSWrappers.hpp>
#include <touchgfx/lcd/LCD.hpp>

/* Makes touchgfx specific types and variables visible to this file */
using namespace touchgfx;

typedef struct
{
    const uint16_t format;
    const uint16_t size;
    const uint32_t* const data;
} clutData_t;

extern "C" void DMA2D_IRQHandler()
{
    /* Transfer Complete Interrupt management ************************************/
    if ((READ_REG(DMA2D->ISR) & DMA2D_FLAG_TC) != RESET)
    {
        /* Verify Transfer Complete Interrupt */
        if ((READ_REG(DMA2D->CR) & DMA2D_IT_TC) != RESET)
        {
            /* Disable the transfer complete interrupt */
            DMA2D->CR &= ~(DMA2D_IT_TC);

            /* Clear the transfer complete flag */
            DMA2D->IFCR = (DMA2D_FLAG_TC);

            /* Signal DMA queue of execution complete */
            touchgfx::HAL::getInstance()->signalDMAInterrupt();
        }
    }
}

STM32DMA::STM32DMA()
    : DMA_Interface(dma_queue), dma_queue(queue_storage, sizeof(queue_storage) / sizeof(queue_storage[0]))
{
}

STM32DMA::~STM32DMA()
{
    /* Disable DMA2D global Interrupt */
    NVIC_DisableIRQ(DMA2D_IRQn);
}

void STM32DMA::initialize()
{
    /* Ensure DMA2D Clock is enabled */
    __HAL_RCC_DMA2D_CLK_ENABLE();
    __HAL_RCC_DMA2D_FORCE_RESET();
    __HAL_RCC_DMA2D_RELEASE_RESET();

    /* Enable DMA2D global Interrupt */
    HAL_NVIC_SetPriority(DMA2D_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(DMA2D_IRQn);
}

inline uint32_t STM32DMA::getChromARTInputFormat(Bitmap::BitmapFormat format)
{
    // Default color mode set to ARGB8888
    uint32_t dma2dColorMode = DMA2D_INPUT_ARGB8888;

    switch (format)
    {
    case Bitmap::ARGB8888: /* DMA2D input mode set to 32bit ARGB */
        dma2dColorMode = DMA2D_INPUT_ARGB8888;
        break;
    case Bitmap::RGB888: /* DMA2D input mode set to 24bit RGB */
        dma2dColorMode = DMA2D_INPUT_RGB888;
        break;
    case Bitmap::RGB565: /* DMA2D input mode set to 16bit RGB */
        dma2dColorMode = DMA2D_INPUT_RGB565;
        break;
    case Bitmap::ARGB2222: /* Fall through */
    case Bitmap::ABGR2222: /* Fall through */
    case Bitmap::RGBA2222: /* Fall through */
    case Bitmap::BGRA2222: /* Fall through */
    case Bitmap::L8:       /* DMA2D input mode set to 8bit Color Look up table*/
        dma2dColorMode = DMA2D_INPUT_L8;
        break;
    case Bitmap::BW:     /* Fall through */
    case Bitmap::BW_RLE: /* Fall through */
    case Bitmap::GRAY4:  /* Fall through */
    case Bitmap::GRAY2:  /* Fall through */
    default:             /* Unsupported input format for DMA2D */
        assert(0 && "Unsupported Format!");
        break;
    }

    return dma2dColorMode;
}

inline uint32_t STM32DMA::getChromARTOutputFormat(Bitmap::BitmapFormat format)
{
    // Default color mode set to ARGB8888
    uint32_t dma2dColorMode = DMA2D_OUTPUT_ARGB8888;

    switch (format)
    {
    case Bitmap::ARGB8888: /* DMA2D output mode set to 32bit ARGB */
        dma2dColorMode = DMA2D_OUTPUT_ARGB8888;
        break;
    case Bitmap::RGB888:   /* Fall through */
    case Bitmap::ARGB2222: /* Fall through */
    case Bitmap::ABGR2222: /* Fall through */
    case Bitmap::RGBA2222: /* Fall through */
    case Bitmap::BGRA2222: /* DMA2D output mode set to 24bit RGB */
        dma2dColorMode = DMA2D_OUTPUT_RGB888;
        break;
    case Bitmap::RGB565: /* DMA2D output mode set to 16bit RGB */
        dma2dColorMode = DMA2D_OUTPUT_RGB565;
        break;
    case Bitmap::L8:     /* Fall through */
    case Bitmap::BW:     /* Fall through */
    case Bitmap::BW_RLE: /* Fall through */
    case Bitmap::GRAY4:  /* Fall through */
    case Bitmap::GRAY2:  /* Fall through */
    default:             /* Unsupported output format for DMA2D */
        assert(0 && "Unsupported Format!");
        break;
    }

    return dma2dColorMode;
}

BlitOperations STM32DMA::getBlitCaps()
{
    return static_cast<BlitOperations>(BLIT_OP_FILL
                                       | BLIT_OP_FILL_WITH_ALPHA
                                       | BLIT_OP_COPY
                                       | BLIT_OP_COPY_L8
                                       | BLIT_OP_COPY_WITH_ALPHA
                                       | BLIT_OP_COPY_ARGB8888
                                       | BLIT_OP_COPY_ARGB8888_WITH_ALPHA
                                       | BLIT_OP_COPY_A4
                                       | BLIT_OP_COPY_A8);
}

/*
 * void STM32DMA::setupDataCopy(const BlitOp& blitOp) handles blit operation of
 * BLIT_OP_COPY
 * BLIT_OP_COPY_L8
 * BLIT_OP_COPY_WITH_ALPHA
 * BLIT_OP_COPY_ARGB8888
 * BLIT_OP_COPY_ARGB8888_WITH_ALPHA
 * BLIT_OP_COPY_A4
 * BLIT_OP_COPY_A8
 */
void STM32DMA::setupDataCopy(const BlitOp& blitOp)
{
    uint32_t dma2dForegroundColorMode = getChromARTInputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.srcFormat));
    uint32_t dma2dBackgroundColorMode = getChromARTInputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));
    uint32_t dma2dOutputColorMode = getChromARTOutputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));

    /* DMA2D OOR register configuration */
    WRITE_REG(DMA2D->OOR, blitOp.dstLoopStride - blitOp.nSteps);

    /* DMA2D BGOR register configuration */
    WRITE_REG(DMA2D->BGOR, blitOp.dstLoopStride - blitOp.nSteps);

    /* DMA2D FGOR register configuration */
    WRITE_REG(DMA2D->FGOR, blitOp.srcLoopStride - blitOp.nSteps);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, dma2dOutputColorMode);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (blitOp.nLoops | (blitOp.nSteps << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

    /* Configure DMA2D source address */
    WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(blitOp.pSrc));

    switch (blitOp.operation)
    {
    case BLIT_OP_COPY_A4:
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A4 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

        /* set DMA2D foreground color */
        WRITE_REG(DMA2D->FGCOLR, blitOp.color);

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START);
        break;
    case BLIT_OP_COPY_A8:
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

        /* set DMA2D foreground color */
        WRITE_REG(DMA2D->FGCOLR, blitOp.color);

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START);
        break;
    case BLIT_OP_COPY_WITH_ALPHA:
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START);
        break;
    case BLIT_OP_COPY_L8:
        {
            bool blend = true;
            const clutData_t* const palette = reinterpret_cast<const clutData_t*>(blitOp.pClut);

            /* Write foreground CLUT memory address */
            WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&palette->data));

            /* Set DMA2D color mode and alpha mode */
            WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

            /* Write DMA2D BGPFCCR register */
            WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

            /* Configure DMA2D Stream source2 address */
            WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

            /* Configure CLUT */
            switch ((Bitmap::ClutFormat)palette->format)
            {
            case Bitmap::CLUT_FORMAT_L8_ARGB8888:
                /* Write foreground CLUT size and CLUT color mode */
                MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((palette->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_ARGB8888 << DMA2D_FGPFCCR_CCM_Pos)));
                break;
            case Bitmap::CLUT_FORMAT_L8_RGB888:
                if(blitOp.alpha == 255)
                {
                    blend = false;
                }
                MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((palette->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_RGB888 << DMA2D_FGPFCCR_CCM_Pos)));
                break;

            case Bitmap::CLUT_FORMAT_L8_RGB565:
            default:
                assert(0 && "Unsupported format");
                break;
            }

            /* Enable the CLUT loading for the foreground */
            SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);

            while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U)
            {
            }
            DMA2D->IFCR = (DMA2D_FLAG_CTC);

            /* Set DMA2D mode */
            if(blend)
            {
                WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START);
            }
            else
            {
                WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_IT_TC | DMA2D_CR_START);
            }
        }
        break;
    case BLIT_OP_COPY_ARGB8888:
    case BLIT_OP_COPY_ARGB8888_WITH_ALPHA:
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, dma2dBackgroundColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_IT_TC | DMA2D_CR_START);
        break;
    default: /* BLIT_OP_COPY */
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, dma2dForegroundColorMode | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (blitOp.alpha << 24));

        /* Perform pixel-format-conversion (PFC) If Bitmap format is not same format as framebuffer format */
        if (blitOp.srcFormat != blitOp.dstFormat)
        {
            /* Start DMA2D : PFC Mode */
            WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_IT_TC | DMA2D_CR_START);
        }
        else
        {
            /* Start DMA2D : M2M Mode */
            WRITE_REG(DMA2D->CR, DMA2D_M2M | DMA2D_IT_TC | DMA2D_CR_START);
        }
        break;
    }
}

/*
 * void STM32DMA::setupDataFill(const BlitOp& blitOp) handles blit operation of
 * BLIT_OP_FILL
 * BLIT_OP_FILL_WITH_ALPHA
 */
void STM32DMA::setupDataFill(const BlitOp& blitOp)
{
    uint32_t dma2dOutputColorMode = getChromARTOutputFormat(static_cast<Bitmap::BitmapFormat>(blitOp.dstFormat));

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, dma2dOutputColorMode);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (blitOp.nLoops | (blitOp.nSteps << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

    /* DMA2D OOR register configuration */
    WRITE_REG(DMA2D->OOR, blitOp.dstLoopStride - blitOp.nSteps);

    if (blitOp.operation == BLIT_OP_FILL_WITH_ALPHA)
    {
        /* DMA2D BGOR register configuration */
        WRITE_REG(DMA2D->BGOR, blitOp.dstLoopStride - blitOp.nSteps);

        /* DMA2D FGOR register configuration */
        WRITE_REG(DMA2D->FGOR, blitOp.dstLoopStride - blitOp.nSteps);

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, dma2dOutputColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Write DMA2D FGPFCCR register */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_REPLACE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | ((blitOp.alpha << 24) & DMA2D_FGPFCCR_ALPHA));

        /* DMA2D FGCOLR register configuration */
        WRITE_REG(DMA2D->FGCOLR, blitOp.color);

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Configure DMA2D source address */
        WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(blitOp.pDst));

        /* Enable the Peripheral and Enable the transfer complete interrupt */
        WRITE_REG(DMA2D->CR, (DMA2D_IT_TC | DMA2D_CR_START | DMA2D_M2M_BLEND));
    }
    else
    {
        /* Write DMA2D FGPFCCR register */
        WRITE_REG(DMA2D->FGPFCCR, dma2dOutputColorMode | (DMA2D_NO_MODIF_ALPHA << DMA2D_FGPFCCR_AM_Pos));

        /* DMA2D FGOR register configuration */
        WRITE_REG(DMA2D->FGOR, 0);

        /* Set color */
        WRITE_REG(DMA2D->OCOLR, ((blitOp.color >> 8) & 0xF800) | ((blitOp.color >> 5) & 0x07E0) | ((blitOp.color >> 3) & 0x001F));

        /* Enable the Peripheral and Enable the transfer complete interrupt */
        WRITE_REG(DMA2D->CR, (DMA2D_IT_TC | DMA2D_CR_START | DMA2D_R2M));
    }
}

namespace touchgfx
{
namespace paint
{
namespace
{
const clutData_t* L8CLUT = 0;
uint32_t L8ClutLoaded = 0;
} // namespace

void setL8Pallette(const uint8_t* const data)
{
    L8CLUT = reinterpret_cast<const clutData_t*>(data - offsetof(clutData_t, data));
    L8ClutLoaded = 0;
}

/**
* @fn void tearDown();
*
* @brief Waits until previous DMA drawing operation has finished
*/
void tearDown()
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* Clear transfer flags */
    WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);
}

namespace rgb565
{
/**
* @fn void lineFromColor();
*
* @brief Renders Canvas Widget chunks using DMA.
* This functions will not generate an interrupt, and will not affect the DMA queue.
*/
void lineFromColor(uint16_t* const ptr, const unsigned count, const uint32_t color, const uint8_t alpha, const uint32_t color565)
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* Clear transfer flags */
    WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));

    if (alpha < 0xFF)
    {
        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, DMA2D_OUTPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Write DMA2D FGPFCCR register */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_A8 | (DMA2D_REPLACE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | ((alpha << 24) & DMA2D_FGPFCCR_ALPHA));

        /* DMA2D FGCOLR register configuration */
        WRITE_REG(DMA2D->FGCOLR, color);

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, (uint32_t)ptr);

        /* Configure DMA2D source address */
        WRITE_REG(DMA2D->FGMAR, (uint32_t)ptr);

        /* Enable the Peripheral and Enable the transfer complete interrupt */
        WRITE_REG(DMA2D->CR, (DMA2D_CR_START | DMA2D_M2M_BLEND));
    }
    else
    {
        /* Write DMA2D FGPFCCR register */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_OUTPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_FGPFCCR_AM_Pos));

        /* Set color */
        WRITE_REG(DMA2D->OCOLR, color565);

        /* Enable the Peripheral and Enable the transfer complete interrupt */
        WRITE_REG(DMA2D->CR, (DMA2D_CR_START | DMA2D_R2M));
    }
}

void lineFromRGB565(uint16_t* const ptr, const uint16_t* const data, const unsigned count, const uint8_t alpha)
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* Clear transfer flags */
    WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));

    /* Configure DMA2D source address */
    WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));

    if (alpha < 0xFF)
    {
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << 24));

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Configure DMA2D Stream source2 address */
        WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));

        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
    }
    else
    {
        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_COMBINE_ALPHA << DMA2D_FGPFCCR_AM_Pos) | (alpha << 24));

        /* Start DMA2D : M2M Mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M | DMA2D_CR_START);
    }
}

void lineFromARGB8888(uint16_t* const ptr, const uint32_t* const data, const unsigned count, const uint8_t alpha)
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* Clear transfer flags */
    WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC | DMA2D_FLAG_CE | DMA2D_FLAG_TE);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));

    /* Configure DMA2D source address */
    WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));

    /* Set DMA2D color mode and alpha mode */
    WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_ARGB8888 | (DMA2D_COMBINE_ALPHA << DMA2D_BGPFCCR_AM_Pos) | (alpha << 24));

    /* Write DMA2D BGPFCCR register */
    WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

    /* Configure DMA2D Stream source2 address */
    WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));

    /* Set DMA2D mode */
    WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}

void lineFromL8RGB888(uint16_t* const ptr, const uint8_t* const data, const unsigned count, const uint8_t alpha)
{
    /* wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));

    /* Configure DMA2D source address */
    WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));

    /* Configure DMA2D Stream source2 address */
    WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));

    /* Load CLUT if not already loaded */
    if (L8ClutLoaded == 0)
    {
        /* Write foreground CLUT memory address */
        WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&L8CLUT->data));

        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_L8 | (DMA2D_COMBINE_ALPHA << DMA2D_BGPFCCR_AM_Pos) | (alpha << 24));

        MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((L8CLUT->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_RGB888 << DMA2D_FGPFCCR_CCM_Pos)));

        /* Enable the CLUT loading for the foreground */
        SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Mark CLUT loaded */
        L8ClutLoaded = 1;

        /* Wait for load to finish */
        while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U);

        /* Clear CLUT Transfer Complete flag */
        DMA2D->IFCR = (DMA2D_FLAG_CTC);
    }
    else
    {
        /* Set correct alpha for these pixels */
        MODIFY_REG(DMA2D->FGPFCCR, DMA2D_BGPFCCR_ALPHA_Msk, alpha << 24);
    }

    /* Start pixel transfer in correct mode */
    if (alpha < 0xFF)
    {
        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
    }
    else
    {
        /* Set DMA2D mode */
        WRITE_REG(DMA2D->CR, DMA2D_M2M_PFC | DMA2D_CR_START);
    }
}

void lineFromL8ARGB8888(uint16_t* const ptr, const uint8_t* const data, const unsigned count, const uint8_t alpha)
{
    /* wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* DMA2D OPFCCR register configuration */
    WRITE_REG(DMA2D->OPFCCR, DMA2D_OUTPUT_RGB565);

    /* Configure DMA2D data size */
    WRITE_REG(DMA2D->NLR, (1 | (count << DMA2D_NLR_PL_Pos)));

    /* Configure DMA2D destination address */
    WRITE_REG(DMA2D->OMAR, reinterpret_cast<uint32_t>(ptr));

    /* Configure DMA2D source address */
    WRITE_REG(DMA2D->FGMAR, reinterpret_cast<uint32_t>(data));

    /* Configure DMA2D Stream source2 address */
    WRITE_REG(DMA2D->BGMAR, reinterpret_cast<uint32_t>(ptr));

    /* Load CLUT if not already loaded */
    if (L8ClutLoaded == 0)
    {
        /* Write foreground CLUT memory address */
        WRITE_REG(DMA2D->FGCMAR, reinterpret_cast<uint32_t>(&L8CLUT->data));

        /* Set DMA2D color mode and alpha mode */
        WRITE_REG(DMA2D->FGPFCCR, DMA2D_INPUT_L8 | (DMA2D_COMBINE_ALPHA << DMA2D_BGPFCCR_AM_Pos) | (alpha << 24));

        MODIFY_REG(DMA2D->FGPFCCR, (DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM), (((L8CLUT->size - 1) << DMA2D_FGPFCCR_CS_Pos) | (DMA2D_CCM_ARGB8888 << DMA2D_FGPFCCR_CCM_Pos)));

        /* Enable the CLUT loading for the foreground */
        SET_BIT(DMA2D->FGPFCCR, DMA2D_FGPFCCR_START);

        /* Write DMA2D BGPFCCR register */
        WRITE_REG(DMA2D->BGPFCCR, DMA2D_INPUT_RGB565 | (DMA2D_NO_MODIF_ALPHA << DMA2D_BGPFCCR_AM_Pos));

        /* Mark CLUT loaded */
        L8ClutLoaded = 1;

        /* Wait for load to finish */
        while ((READ_REG(DMA2D->FGPFCCR) & DMA2D_FGPFCCR_START) != 0U);

        /* Clear CLUT Transfer Complete flag */
        DMA2D->IFCR = (DMA2D_FLAG_CTC);
    }
    else
    {
        /* Set correct alpha for these pixels */
        MODIFY_REG(DMA2D->FGPFCCR, DMA2D_BGPFCCR_ALPHA_Msk, alpha << 24);
    }

    /* Start pixel transfer in blending mode */
    WRITE_REG(DMA2D->CR, DMA2D_M2M_BLEND | DMA2D_CR_START);
}

} // namespace rgb565
} // namespace paint
} // namespace touchgfx
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/