/*******************************************************************************
* 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 2018-2024 Renesas Electronics Corporation All rights reserved.
*******************************************************************************/



/*******************************************************************************
 * DESCRIPTION   : emmc interrupt
 ******************************************************************************/
/******************************************************************************
 * @file          emmc_interrupt.c
 * - Version      : 0.04
 * @brief         
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 02.02.2022 0.01     First Release
 *         : 16.06.2022 0.02     Change log output
 *         : 31.10.2022 0.03     License notation change.
 *         : 07.06.2024 0.04     Modify the transfer end bit of DMAC channel.
 *****************************************************************************/

#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"
#include "log.h"
#include "mem_io.h"
#include <stdint.h>
/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */

/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */

/* ********************** DECLARATION OF EXTERNAL DATA ********************* */

/* ************************** FUNCTION PROTOTYPES ************************** */
static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual);


/* ********************************* CODE ********************************** */



/** emmc driver interrupt service routine.
 *
 * - Pre-conditions:<BR>
 * Must be block emmc driver state machine.
 * - Post-conditions:<BR>
 * unblocking emmc driver state machine.
 *
 * retval INT_SUCCESS
 */
uint32_t emmc_interrupt(void)
{
    EMMC_ERROR_CODE result = EMMC_ERR;

    /* SD_INFO */
    mmc_drv_obj.error_info.info1 = mem_read32(SD_INFO1);
    mmc_drv_obj.error_info.info2 = mem_read32(SD_INFO2);

    /* SD_INFO EVENT */
    mmc_drv_obj.int_event1 = mmc_drv_obj.error_info.info1 & mem_read32(SD_INFO1_MASK);
    mmc_drv_obj.int_event2 = mmc_drv_obj.error_info.info2 & mem_read32(SD_INFO2_MASK);

    /* ERR_STS */
    mmc_drv_obj.error_info.status1 = mem_read32(SD_ERR_STS1);
    mmc_drv_obj.error_info.status2 = mem_read32(SD_ERR_STS2);

    /* DM_CM_INFO */
    mmc_drv_obj.error_info.dm_info1 = mem_read32(DM_CM_INFO1);
    mmc_drv_obj.error_info.dm_info2 = mem_read32(DM_CM_INFO2);

    /* DM_CM_INFO EVENT */
    mmc_drv_obj.dm_event1 = mmc_drv_obj.error_info.dm_info1 & mem_read32(DM_CM_INFO1_MASK);
    mmc_drv_obj.dm_event2 = mmc_drv_obj.error_info.dm_info2 & mem_read32(DM_CM_INFO2_MASK);

    /* ERR SD_INFO2 */
    if ((SD_INFO2_ALL_ERR & mmc_drv_obj.int_event2) != 0U)
    {
        mem_write32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */
        mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */
        mem_write32(SD_INFO1, 0x00000000U); /* interrupt clear */
        mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* interrupt clear */
        mmc_drv_obj.state_machine_blocking = FALSE;
    }

    /* PIO Transfer */
    /* BWE/BRE */
    else if ((( SD_INFO2_BWE | SD_INFO2_BRE) & mmc_drv_obj.int_event2) != 0U) {
        /* BWE */
        if (( SD_INFO2_BWE & mmc_drv_obj.int_event2) != 0U)
        {
            mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BWE)); /* interrupt clear */
        }
        /* BRE */
        else {
            mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BRE)); /* interrupt clear */
        }

        result = emmc_trans_sector((uint32_t *)mmc_drv_obj.buff_address_virtual); /* sector R/W */
        mmc_drv_obj.buff_address_virtual += EMMC_BLOCK_LENGTH;
        mmc_drv_obj.remain_size -= EMMC_BLOCK_LENGTH;

        if (result != EMMC_SUCCESS)
        {
            /* data transfer error */
            ERROR("%s:0x%x\n",__func__, result);

            /* Panic */
            mem_write32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */
            mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */
            mem_write32(SD_INFO1, 0x00000000U); /* interrupt clear */
            mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* interrupt clear */
            mmc_drv_obj.force_terminate = TRUE;
        } else {
            mmc_drv_obj.during_transfer = FALSE;
        }
        mmc_drv_obj.state_machine_blocking = FALSE;
    }

    /* DMA_TRANSFER */
    /* DM_CM_INFO1: DMA-ch0 transfer complete or error occured */
    else if ((DM_CM_INFO_DTRANEND0 & mmc_drv_obj.dm_event1) != 0U) {
        mem_write32(DM_CM_INFO1, 0x00000000U);
        mem_write32(DM_CM_INFO2, 0x00000000U);
        mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BWE)); /* interrupt clear */
        /* DM_CM_INFO2:  DMA-ch0 error occured */
        if (( DM_CM_INFO2_DTRANEND0 & mmc_drv_obj.dm_event2) != 0U)
        {
            mmc_drv_obj.dma_error_flag = TRUE;
        } else {
            mmc_drv_obj.during_dma_transfer = FALSE;
            mmc_drv_obj.during_transfer = FALSE;
        }
        mmc_drv_obj.state_machine_blocking = FALSE; /* wait next interrupt */
    }
    /* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */
    else if ((DM_CM_INFO_DTRANEND1 & mmc_drv_obj.dm_event1) != 0U) {
        mem_write32(DM_CM_INFO1, 0x00000000U);
        mem_write32(DM_CM_INFO2, 0x00000000U);
        mem_write32(SD_INFO2, (mem_read32(SD_INFO2) & ~SD_INFO2_BRE)); /* interrupt clear */
        /* DM_CM_INFO2: DMA-ch1 error occured */
        if (( DM_CM_INFO2_DTRANEND1 & mmc_drv_obj.dm_event2) != 0U)
        {
            mmc_drv_obj.dma_error_flag = TRUE;
        } else {
            mmc_drv_obj.during_dma_transfer = FALSE;
            mmc_drv_obj.during_transfer = FALSE;
        }
        mmc_drv_obj.state_machine_blocking = FALSE; /* wait next interrupt */
    }

    /* Response end  */
    else if ((SD_INFO1_INFO0 & mmc_drv_obj.int_event1) != 0U) {
        mem_write32(SD_INFO1, (mem_read32(SD_INFO1) & ~SD_INFO1_INFO0)); /* interrupt clear */
        mmc_drv_obj.state_machine_blocking = FALSE;
    }
    /* Access end  */
    else if ((SD_INFO1_INFO2 & mmc_drv_obj.int_event1) != 0U) {
        mem_write32(SD_INFO1, (mem_read32(SD_INFO1) & ~SD_INFO1_INFO2)); /* interrupt clear */
        mmc_drv_obj.state_machine_blocking = FALSE;
    } else {
        /* nothing to do. */
    }

    return 0U;
}

/** Data transfer function with PIO (Single sector).
 *
 * - Pre-conditions:<BR>
 * Called from interrupt service.
 * - Post-conditions:<BR>
 * .
 *
 * param[in,out] buff_address_virtual Dest/Src buffer address(virtual).
 * retval EMMC_SUCCESS successful.
 * retval EMMC_ERR_PARAM parameter error.
 * retval EMMC_ERR_STATE state error.
 */
static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual)
{
    uint32_t length, i;
    uint64_t *bufPtrLL;

    if (buff_address_virtual == NULL)
    {
        return EMMC_ERR_PARAM;
    }

    if ((mmc_drv_obj.during_transfer != TRUE) || (mmc_drv_obj.remain_size == 0U))
    {
        return EMMC_ERR_STATE;
    }

    bufPtrLL = (uint64_t*)buff_address_virtual;
    length = mmc_drv_obj.remain_size;

    /* data transefer */
    for (i = 0U; i < (length >> 3U); i++)
    {
        /* Write */
        if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE)
        {
            mem_write64(SD_BUF0, *bufPtrLL); /* buffer --> FIFO */
        }
        /* Read */
        else {
            *bufPtrLL = mem_read64(SD_BUF0); /* FIFO --> buffer */
        }
        bufPtrLL++;
    }

    return EMMC_SUCCESS;
}

/* ******************************** END ************************************ */

