/*******************************************************************************
 * DISCLAIMER
 * This software is supplied by Renesas Electronics Corporation and is only
 * intended for use with Renesas products. No other uses are authorized. This
 * software is owned by Renesas Electronics Corporation and is protected under
 * all applicable laws, including copyright laws.
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software
 * and to discontinue the availability of this software. By using this software,
 * you agree to the additional terms and conditions found by accessing the
 * following link:
 * http://www.renesas.com/disclaimer
 * Copyright 2015-2022 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   :  DMA driver
 ******************************************************************************/
/******************************************************************************
 * @file          dma.c
 * - Version      : 0.05
 * @brief         RT-DMAC driver.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 15.10.2021 0.01     First Release
 *         : 10.02.2022 0.02     Add dma_start_xbyte function.
 *         : 18.03.2022 0.03     Modify to read modify write when write to
 *         :                     register.
 *         : 29.03.2022 0.04     Modify magic number to definition.
 *         : 09.11.2022 0.05     License notation change.
 *****************************************************************************/

#include <stdint.h>
#include <stddef.h>
#include <mem_io.h>
#include <rpc_register.h>
#include <cpg_register.h>
#include <rpc.h>
#include <wdt.h>
#include <log.h>

/*
 * from flash_writer's reg_rcar.h 
 */
/* RT-DMA Control */
#define RTDMACTL_BASE		(BASE_RTDMACTL_ADDR)
#define RTDMAC_RDMOR		(RTDMACTL_BASE + 0x0060U)	/*  R/W	16	DMA operation register (for channels 0 to 15) */
/* RT-DMAC0(for RPC) */
#define RTDMAC_BASE			(BASE_RTDMA0_ADDR)
#define RTDMAC_RDMSEC		(RTDMAC_BASE + 0x00B0U)	/*  R/W	32	DMA secure control register (for channels 0 to 15) */
#define RTDMAC_RDMSAR(x)	(RTDMAC_BASE + 0x0000U + (0x80U * (x)))	/*  R/W	32	DMA source address register_0 */
#define RTDMAC_RDMDAR(x)	(RTDMAC_BASE + 0x0004U + (0x80U * (x)))	/*  R/W	32	DMA destination address register_0 */
#define RTDMAC_RDMTCR(x)	(RTDMAC_BASE + 0x0008U + (0x80U * (x)))	/*  R/W	32	DMA transfer count register_0 */
#define RTDMAC_RDMCHCR(x)	(RTDMAC_BASE + 0x000CU + (0x80U * (x)))	/*  R/W	32	DMA channel control register_0 */

#include "dma2.h"

#define RDMOR_INITIAL				(0x0301U)
#define	DMACH						(0U)
#define RDMTCR_CNT_SHIFT			(6U)
#define RDMCHCR_TRN_MODE			(0x00105409U)
#define RDMCHCR_TRN_MODE_SRC_FIX	(0x00104409U)
#define RDMCHCR_TRN_MODE_1BYTE		(0x00005401U)
#define RDMCHCR_TE_BIT				(0x00000002U)
#define TE_FLAG						(0x00000000U)
#define RDMCHCR_CAE_BIT				(0x80000000U)
#define RDMCHCR_CAE_BIT_NOERROR		(0x00000000U)
#define RDMCHCR_CAIE_BIT                (0x40000000U)
#define RDMCHCR_DPM_BIT                 (0x30000000U)
#define RDMCHCR_RPT_BIT                 (0x0F000000U)
#define RDMCHCR_WAIT_BIT                (0x00800000U)
#define RDMCHCR_DPB_BIT                 (0x00400000U)
#define RDMCHCR_DSE_BIT                 (0x00080000U)
#define RDMCHCR_DSIE_BIT                (0x00040000U)
#define RDMCHCR_DM_BIT                  (0x0000C000U)
#define RDMCHCR_SM_BIT                  (0x00003000U)
#define RDMCHCR_RS_BIT                  (0x00000F00U)
#define RDMCHCR_TS_BIT                  (0x00300018U)
#define RDMCHCR_IE_BIT                  (0x00000004U)
#define RDMCHCR_TE_BIT                  (0x00000002U)
#define RDMCHCR_DE_BIT                  (0x00000001U)
#define RDMCHCR_CONF_MASK               (RDMCHCR_TS_BIT | RDMCHCR_DM_BIT | RDMCHCR_SM_BIT \
                                        | RDMCHCR_RS_BIT | RDMCHCR_DE_BIT)
#define RDMCHCR_DESCRIPTOR_CONF_MASK    (RDMCHCR_DPM_BIT | RDMCHCR_RPT_BIT | RDMCHCR_WAIT_BIT | RDMCHCR_DPB_BIT)
#define RDMCHCR_INTERRUPT_MASK          (RDMCHCR_CAIE_BIT | RDMCHCR_DSIE_BIT | RDMCHCR_IE_BIT)
#define RDMCHCR_FLAG_MASK               (RDMCHCR_CAE_BIT | RDMCHCR_DSE_BIT | RDMCHCR_TE_BIT)
#define RDMCHCR_ALL_BIT_MASK            (RDMCHCR_CONF_MASK | RDMCHCR_DESCRIPTOR_CONF_MASK \
                                        | RDMCHCR_INTERRUPT_MASK | RDMCHCR_FLAG_MASK)
#define CMNSR_TEND					(0x00000001U)
#define RDMTCR_UPPER_MASK           (0xFF000000U)

/* fraction mask for 64-byte units */
#define FRACTION_MASK_64_BYTE	(0x0000003FU)
/* fraction mask for 256-byte units */
#define	FRACTION_MASK_256_BYTE	(0x000000FFU)

void dma2_init(void)
{
	uint32_t reg;

	/* DMA transfer disabled */
    reg =  mem_read32(RTDMAC_RDMCHCR(DMACH));
    reg &= ~(RDMCHCR_ALL_BIT_MASK);
    mem_write32(RTDMAC_RDMCHCR(DMACH), reg);

	/* DMA operation */
	mem_write16(RTDMAC_RDMOR, RDMOR_INITIAL);
	/* DMA secure control register */
	reg = mem_read32(RTDMAC_RDMSEC);
	reg |= ((uint32_t)1U << DMACH);
	mem_write32(RTDMAC_RDMSEC, reg);
}
/* End of function dma_init */

void dma2_start(uint32_t dst, uint32_t src, uint32_t len, uint32_t mode)
{
    uint32_t reg;

	if (((dst & FRACTION_MASK_64_BYTE) != 0U) || ((src & FRACTION_MASK_64_BYTE) != 0U))
	{
		/* dst or src are not 64-bit alignment. */
		ERROR("not 64-bit alignment in DMA(2) transfer\n");
		while(1)
		{
			;	/* panic */
		}
	}

	/* round up 256 byte alignment */
	len += FRACTION_MASK_256_BYTE;
	len &= (~(uint32_t)(FRACTION_MASK_256_BYTE));

	/* DMA destination address */
	mem_write32(RTDMAC_RDMDAR(DMACH), dst);
	/* DMA source address */
	mem_write32(RTDMAC_RDMSAR(DMACH), src);
	/* DMA 64bytes-unit transfer  count */
	mem_write32(RTDMAC_RDMTCR(DMACH), ((len >> RDMTCR_CNT_SHIFT) & (~RDMTCR_UPPER_MASK)));
	/* DMA channel control */
    reg = mem_read32(RTDMAC_RDMCHCR(DMACH));
	if (mode == DMA_MODE_SRC_FIX)
	{
        reg |= RDMCHCR_TRN_MODE_SRC_FIX;
		mem_write32(RTDMAC_RDMCHCR(DMACH), reg);
	}
	else
	{
        reg |= RDMCHCR_TRN_MODE;
		mem_write32(RTDMAC_RDMCHCR(DMACH), reg);
	}
}
/* End of function dma_start */

void dma2_start_xbyte(uint32_t dst, uint32_t src, uint32_t len, uint32_t trns_unit)
{
    uint32_t reg;

	/* DMA destination address */
	mem_write32(RTDMAC_RDMDAR(DMACH), dst);
	/* DMA source address */
	mem_write32(RTDMAC_RDMSAR(DMACH), src);
	/* DMA transfer count */
	mem_write32(RTDMAC_RDMTCR(DMACH), ((len >> trns_unit) & (~RDMTCR_UPPER_MASK)));
    /* DMA channel control */
    reg = mem_read32(RTDMAC_RDMCHCR(DMACH));
    if (trns_unit == TRANS_UNIT_1BYTE)
    {
    	/* DMA channel control (transfer unit is 1 byte)*/
        reg |= RDMCHCR_TRN_MODE_1BYTE;
	    mem_write32(RTDMAC_RDMCHCR(DMACH), reg);
    }
    if (trns_unit == TRANS_UNIT_64BYTES)
    {
    	/* DMA channel control (transfer unit is 64 bytes) */
        reg |= RDMCHCR_TRN_MODE;
	    mem_write32(RTDMAC_RDMCHCR(DMACH), reg);
    }
}
/* End of function dma_start_byte */

void dma2_end(void)
{
    uint32_t reg;

	/* Check end of DMA transfer. */
	do
	{
        wdt_restart();
		/* Check error of DMA transfer */
		if ((mem_read32(RTDMAC_RDMCHCR(DMACH)) & RDMCHCR_CAE_BIT) != RDMCHCR_CAE_BIT_NOERROR)
		{
			ERROR("DMA(2) - Channel Address Error\n");
			while(1)
			{
				;	/* panic */
			}
		}
	}
	while ((mem_read32(RTDMAC_RDMCHCR(DMACH)) & RDMCHCR_TE_BIT) == TE_FLAG);

	/* DMA transfer disabled */
    reg =  mem_read32(RTDMAC_RDMCHCR(DMACH));
    reg &= ~(RDMCHCR_ALL_BIT_MASK);
    mem_write32(RTDMAC_RDMCHCR(DMACH), reg);

	rpc_end_state_check();
}
/* End of function dma_end */
