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

/*******************************************************************************
 * DESCRIPTION   : Control ECC and Address parity check for CodeSRAM
 ******************************************************************************/
 /******************************************************************************
 * @file          codesram_ecc.c
 * - Version      : 0.01
 * @brief         1. Enable / Disable ECC and Address parity check for CodeSRAM.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 19.01.2023 0.01     First Release
 *****************************************************************************/

#include <stdint.h>
#include <codesram_ecc.h>
#include <mem_io.h>
#include <log.h>
#include <mcu_register.h>
#include <cpu_on_for_mcu.h>

#define CSRM_ECCCTL_EMCA_EN_MOD (0x00004000U)
#define CSRM_ECCCTL_APERR       (0x00001000U)
#define CSRM_ECCCTL_ECERVF      (0x00000040U)
#define CSRM_ECCCTL_EC1ECP      (0x00000020U)
#define CSRM_ECCCTL_ECER2F      (0x00000004U)
#define CSRM_ECCCTL_ECER1F      (0x00000002U)

#define CSRM_APCTL_APCEN        (0x00000001U)
#define CSRM_NO_ERROR           (0x00000000U)

#define CODESRAM_BUS_NUM_SHIFT  (20U)

void disable_codesram_ecc_parity(uint32_t boot_addr, uint32_t size)
{
    uint32_t loop;
    uint32_t bus_num;
    uint32_t set_num;
    uint32_t reg;

    /* Code-SRAMn ECC Control Register */
    const uint32_t eccctl_reg[MCU_CSRM_MAX] = { MCU_CSRM0ECCCTL,
                                                MCU_CSRM1ECCCTL,
                                                MCU_CSRM2ECCCTL,
                                                MCU_CSRM3ECCCTL,
                                                MCU_CSRM4ECCCTL,
                                                MCU_CSRM5ECCCTL};

    /* Code-SRAMn Address Parity Control Register */
    const uint32_t apctl_reg[MCU_CSRM_MAX] = {  MCU_CSRM0APCTL,
                                                MCU_CSRM1APCTL,
                                                MCU_CSRM2APCTL,
                                                MCU_CSRM3APCTL,
                                                MCU_CSRM4APCTL,
                                                MCU_CSRM5APCTL};

    /* Calculate the area used by Code SRAM. */
    bus_num = ((boot_addr  & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);
    set_num = ((size & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);

    for (loop = 0U; loop < set_num; loop++)
    {
        /* Disable ECC error detection and error correction for CodeSRAM. */
        reg  = mem_read32(eccctl_reg[bus_num + loop]);
        reg &= ~(CSRM_ECCCTL_ECERVF);
        reg |= CSRM_ECCCTL_EMCA_EN_MOD;
        reg |= CSRM_ECCCTL_EC1ECP;
        mem_write32(eccctl_reg[bus_num + loop], reg);
        /* Disable Address parity check for CodeSRAM. */
        reg  = mem_read32(apctl_reg[bus_num + loop]);
        reg &= ~(CSRM_APCTL_APCEN);
        mem_write32(apctl_reg[bus_num + loop], reg);
    }
}
/* End of function disable_codesram_ecc_parity */

void enable_codesram_ecc_parity(uint32_t boot_addr, uint32_t size)
{
    uint32_t loop;
    uint32_t bus_num;
    uint32_t set_num;
    uint32_t reg;

    /* Code-SRAMn ECC Control Register */
    const uint32_t eccctl_reg[MCU_CSRM_MAX] = { MCU_CSRM0ECCCTL,
                                                MCU_CSRM1ECCCTL,
                                                MCU_CSRM2ECCCTL,
                                                MCU_CSRM3ECCCTL,
                                                MCU_CSRM4ECCCTL,
                                                MCU_CSRM5ECCCTL};

    /* Code-SRAMn Address Parity Control Register */
    const uint32_t apctl_reg[MCU_CSRM_MAX] = {  MCU_CSRM0APCTL,
                                                MCU_CSRM1APCTL,
                                                MCU_CSRM2APCTL,
                                                MCU_CSRM3APCTL,
                                                MCU_CSRM4APCTL,
                                                MCU_CSRM5APCTL};

    /* Calculate the area used by Code SRAM. */
    bus_num = ((boot_addr  & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);
    set_num = ((size & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);

    for (loop = 0U; loop < set_num; loop++)
    {
        /* Enable ECC error detection and error correction for CodeSRAM. */
        reg  = mem_read32(eccctl_reg[bus_num + loop]);
        reg &= ~(CSRM_ECCCTL_EC1ECP);
        reg |= CSRM_ECCCTL_ECERVF;
        reg |= CSRM_ECCCTL_EMCA_EN_MOD;
        mem_write32(eccctl_reg[bus_num + loop], reg);
        /* Enable Address parity check for CodeSRAM. */
        reg  = mem_read32(apctl_reg[bus_num + loop]);
        reg |= CSRM_APCTL_APCEN;
        mem_write32(apctl_reg[bus_num + loop], reg);
    }
}
/* End of function enable_codesram_ecc_parity */

void chk_codesram_ecc_parity(uint32_t boot_addr, uint32_t size)
{
    uint32_t loop;
    uint32_t bus_num;
    uint32_t set_num;
    uint32_t reg;
    uint32_t err_chk;

    /* Code-SRAMn ECC Control Register */
    const uint32_t eccctl_reg[MCU_CSRM_MAX] = { MCU_CSRM0ECCCTL,
                                                MCU_CSRM1ECCCTL,
                                                MCU_CSRM2ECCCTL,
                                                MCU_CSRM3ECCCTL,
                                                MCU_CSRM4ECCCTL,
                                                MCU_CSRM5ECCCTL};

    /* Calculate the area used by Code SRAM. */
    bus_num = ((boot_addr  & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);
    set_num = ((size & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);

    /* Check ECC error and Address parity error for CodeSRAM. */
    for (loop = 0U; loop < set_num; loop++)
    {
        reg      = mem_read32(eccctl_reg[bus_num + loop]);
        err_chk  = reg;
        err_chk &= (CSRM_ECCCTL_ECER2F | CSRM_ECCCTL_ECER1F);
        if(err_chk != CSRM_NO_ERROR)
        {
            /* ECC error occurred. */
            ERROR("CodeSRAM ECC error detected !!\n");
            panic;
        }
        err_chk  = reg;
        err_chk &= CSRM_ECCCTL_APERR;
        if(err_chk != CSRM_NO_ERROR)
        {
            /* Address parity error occurred. */
            ERROR("CodeSRAM Address parity error detected !!\n");
            panic;
        }
    }
}
/* End of function chk_codesram_ecc_parity */

void initialize_codesram_ecc_parity(uint32_t boot_addr, uint32_t size)
{
    uint32_t loop;
    uint32_t bus_num;
    uint32_t set_num;
    uint32_t reg;

    /* Code-SRAMn ECC Control Register */
    const uint32_t eccctl_reg[MCU_CSRM_MAX] = { MCU_CSRM0ECCCTL,
                                                MCU_CSRM1ECCCTL,
                                                MCU_CSRM2ECCCTL,
                                                MCU_CSRM3ECCCTL,
                                                MCU_CSRM4ECCCTL,
                                                MCU_CSRM5ECCCTL};

    /* Code-SRAMn Address Parity Control Register */
    const uint32_t apctl_reg[MCU_CSRM_MAX] = {  MCU_CSRM0APCTL,
                                                MCU_CSRM1APCTL,
                                                MCU_CSRM2APCTL,
                                                MCU_CSRM3APCTL,
                                                MCU_CSRM4APCTL,
                                                MCU_CSRM5APCTL};

    /* Calculate the area used by Code SRAM. */
    bus_num = ((boot_addr  & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);
    set_num = ((size & CODESRAM_BUS_NUM_MASK) >> CODESRAM_BUS_NUM_SHIFT);

    for (loop = 0U; loop < set_num; loop++)
    {
        /* Initialize ECC error detection and error correction setting for CodeSRAM. */
        reg  = mem_read32(eccctl_reg[bus_num + loop]);
        reg &= ~(CSRM_ECCCTL_EC1ECP | CSRM_ECCCTL_ECERVF);
        reg |= CSRM_ECCCTL_EMCA_EN_MOD;
        mem_write32(eccctl_reg[bus_num + loop], reg);
        /* Initialize Address parity check setting for CodeSRAM. */
        reg  = mem_read32(apctl_reg[bus_num + loop]);
        reg |= CSRM_APCTL_APCEN;
        mem_write32(apctl_reg[bus_num + loop], reg);
    }
}
/* End of function initialize_codesram_ecc_parity */

