/*******************************************************************************
 * Copyright (c) 2022-2023 Renesas Electronics Corporation. All rights reserved.
 *
 *     RENESAS ELECTRONICS CONFIDENTIAL AND PROPRIETARY
 *
 * This software is provided as reference/sample code under the license
 * agreement between Renesas Electronics Corporation and licensee (the
 * "License Agreement") and shall be treated as specified in the License
 * Agreement.
 * These instructions, statements, and software are the confidential
 * information of Renesas Electronics Corporation. They must be used and
 * modified solely for the purpose for which it was furnished by Renesas
 * Electronics Corporation. All or part of these instructions, statements and
 * software must not be reproduced nor disclosed to any third party in any
 * form, unless permitted by the License Agreement.
 *
 * THIS SOFTWARE IS PROVIDED BY RENESAS ELEOCTRONICS CORPORATION "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * SATISFACTORY QUALITY, ACCURACY, TITLE AND NON-INFRINGEMENT ARE DISCLAIMED.
 * IN NO EVENT SHALL RENESAS ELECTRONICS CORPORATION BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * 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.
 ******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : ECC setting function
 ******************************************************************************/
/******************************************************************************
 * @file          ecc_enable_s4.c
 * - Version      : 0.02
 * @brief         Enable setting process of ECC for DRAM.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 09.08.2022 0.01     First Release
 *         : 04.04.2023 0.02     Removed stdio.h and string.h.
 *****************************************************************************/


#include <stdint.h>

static void ecm_unlock(void);
static void ecm_write(uint32_t adr, uint32_t val);
static void ecm_lock(void);

#include "boot_init_dram_regdef.h"
#include "ecc_enable_s4.h"

static void ecm_unlock(void)
{
    uint32_t tmp_adr;
    tmp_adr = ((0xACCEU << 16U) | (ECMWPCNTR & 0xffffU));
    mem_write32(ECMWACNTR, tmp_adr);
    mem_write32(ECMWPCNTR, 0xACCE0001);
}

static void ecm_write(uint32_t adr, uint32_t val)
{
    mem_write32(ECMWACNTR, ((0xACCEU << 16U) | (adr & 0xffffU)));
    mem_write32(adr, val);
}

static void ecm_lock(void)
{
    mem_write32(ECMWACNTR, ((0xACCEU << 16U) | (ECMWACNTR & 0xffffU)));
    mem_write32(ECMWPCNTR, 0xACCE0000U);
}

void enable_ecc(void)
{
    NOTICE("ECC for DRAM is enable.\n");
    uint32_t ecm_tmp;

    /* Unlock the access protect for DBSC registers */
    mem_write32(DBSC_DBSYSCNT0, 0x00001234U);
    mem_write32(DBSC_DBSYSCNT0A, 0x00001234U);

    /* (A) Initialization for DRAM */
    mmio_write_32(DBSC_DBACEN, 0x00000000U);

    /* Unlock the write protect of ECM registers */
    ecm_unlock();

    /* (1) Set the corresponding bits of the ECMERRTGTR, ECMERRCTLR and ECMERRFATALR registers to inform
        the control domain of the fatal error. */
    ecm_tmp = mem_read32(ECMERRTGTR0);
    ecm_tmp &= ~(0x3U);
    ecm_write(ECMERRTGTR0, ecm_tmp);

    ecm_tmp = mem_read32(ECMERRCTLR0);
    ecm_tmp |= 0x3U;
    ecm_write(ECMERRCTLR0, ecm_tmp);

    ecm_tmp = mem_read32(ECMERRFATALR0);
    ecm_tmp |= 0x3U;
    ecm_write(ECMERRFATALR0, ecm_tmp);

    /* (B) Setting ECC protection area */
    /* Set the bottom row address of the ECC protection area */
    mem_write32(DBFSDRAMECCAREA00, ECC_PROT_SIZE0);
    mem_write32(DBFSDRAMECCAREA01, ECC_PROT_SIZE1);

    /* (2) Initialization for DRAM connected to DBSCCORE */
    /* Specify RANK0 as the initialization target */
    ecm_tmp = mem_read32(DBFSCONF00A);
    ecm_tmp = 0x0U;
    mem_write32(DBFSCONF00A, ecm_tmp);

    /* Set the start and end row address of the initialization area */
    mem_write32(DBFSCONF01A, START_ECC_INIT_AREA0);
    mem_write32(DBFSCONF05A, END_ECC_INIT_AREA0);

    /* Set 0x1 to start initialization */
    ecm_tmp = mem_read32(DBFSCTRL01A);
    ecm_tmp |= 0x01U;
    mem_write32(DBFSCTRL01A, ecm_tmp);

    /* Wait until to DRAM initialization is complete */
    NOTICE("DRAM rank 0 is initializing.......\n");
    do
    {
        ecm_tmp = mem_read32(DBFSSTAT01A);
    } while ((ecm_tmp & 0x01U) != 0x01U);

    /* If DRAM is connected to RANK1, Initialize RANK1 */
    /* Specify RANK0 as the initialization target */
    ecm_tmp = mem_read32(DBFSCONF00A);
    ecm_tmp |= 0x1U;
    mem_write32(DBFSCONF00A, ecm_tmp);

    /* Set the start and end row address of the initialization area */
    mem_write32(DBFSCONF01A, START_ECC_INIT_AREA1);
    mem_write32(DBFSCONF05A, END_ECC_INIT_AREA1);

    /* Set 0x1 to start initialization */
    ecm_tmp = mem_read32(DBFSCTRL01A);
    ecm_tmp |= 0x01U;
    mem_write32(DBFSCTRL01A, ecm_tmp);

    /* Wait until to DRAM initialization is complete */
    NOTICE("DRAM rank 1 is initializing.......\n");
    do
    {
        ecm_tmp = mem_read32(DBFSSTAT01A);
    } while ((ecm_tmp & 0x01U) != 0x01U);

    /* (C) Setting ECC protection enable */
    ecm_tmp = mem_read32(DBFSCONFAXI0);
    ecm_tmp |= (0x3 << 8U);
    mem_write32(DBFSCONFAXI0, ecm_tmp);

    /* (D) System RAM initialization */
    /* Wait for initialization of System RAM */
    NOTICE("System RAM is initializing.......\n");
    do
    {
        ;
    } while ((mem_read32(DBFSSTAT00A) & 0x1U) != 0x1U);

    /* (E) Setting for ECC error interrupt */
    /* (1) Set the ECC error interrupt for read data. */
    mem_write32(DBFSINTENB02A, 0xFF00U);

    /* (2) Set the ECC error interrupt during RMW operation for System RAM. */
    ecm_tmp = mem_read32(DBFSINTENB02A);
    ecm_tmp |= (0xFFU << 24U);
    mem_write32(DBFSINTENB02A, ecm_tmp);

    /* (3) Set the ECC error interrupt during RMW operation for DRAM. */
    mem_write32(DBFSINTENB04A, 0xFFFFU);

    /* Lock the ECM registers */
    ecm_lock();

    /* Enable the write protect of ECM registers */
    mmio_write_32(DBSC_DBACEN, 0x00000001U);

    /* Enable the access protect for DBSC registers */
    mem_write32(DBSC_DBSYSCNT0, 0x00000000U);
    mem_write32(DBSC_DBSYSCNT0A, 0x00000000U);
}

void ecc_rtsram_enable(void)
{
    uint32_t ecc_tmp;

    /* Unlock the write protect of ECM registers */
    ecm_unlock();

    /* (1) Set the corresponding bits of the ECMERRTGTR, ECMERRCTLR and
        ECMERRFATALR registers to inform the control domain of the fatal error. */

    /* Set bit 29 of ECMERRTGTR7 to 0 and bit 29 of ECMERRCTLR7 to 1.
                                                        (RT-SRAM ecc 2-bit error) */
    ecc_tmp = mem_read32(ECMERRTGTR7);
    ecc_tmp |= (1U << 29U) ;
    ecm_write(ECMERRTGTR7, ecc_tmp);

    ecc_tmp = mem_read32(ECMERRCTLR7);
    ecc_tmp |= (1U << 29U);
    ecm_write(ECMERRCTLR7, ecc_tmp);

    /* Set bit 19 of ECMERRTGTR7 to 0 and bit 19 of ECMERRCTLR7 to 1.
                                            (RT-SRAM ecc 2-bit error (for ICUMX)) */
    ecc_tmp = mem_read32(ECMERRTGTR7);
    ecc_tmp |= (1U << 19U);
    ecm_write(ECMERRTGTR7, ecc_tmp);

    ecc_tmp = mem_read32(ECMERRCTLR7);
    ecc_tmp |= (1U << 19U);
    ecm_write(ECMERRCTLR7, ecc_tmp);

    /* Set bit 29 and 19 of ECMERRFATALR7 to 1. (Notification of fatal error) */
    ecc_tmp = mem_read32(ECMERRFATALR7);
    ecc_tmp |= ((1U << 29U) | (1U << 19U));
    ecm_write(ECMERRFATALR7, ecc_tmp);

    /* (2) Set the corresponding bits of the ECMERRTGTR and ECMERRCTLR registers to
                                        notify the correctable error to software. */

    /* Set bit 30 of ECMERRTGTR7 to 1 and bit 30 of ECMERRCTLR7 to 1.
                                                        (RT-SRAM ecc 1-bit error) */
    ecc_tmp = mem_read32(ECMERRTGTR7);
    ecc_tmp |= (1U << 30U);
    ecm_write(ECMERRTGTR7, ecc_tmp);

    ecc_tmp = mem_read32(ECMERRCTLR7);
    ecc_tmp |= (1U << 30U);
    ecm_write(ECMERRCTLR7, ecc_tmp);

    /* Set bit 20 of ECMERRTGTR7 to 1 and bit 20 of ECMERRCTLR7 to 1.
                                (RT-SRAM ecc 1-bit error (for ICUMX)) */
    ecc_tmp = mem_read32(ECMERRTGTR7);
    ecc_tmp |= (1U << 20U);
    ecm_write(ECMERRTGTR7, ecc_tmp);

    ecc_tmp = mem_read32(ECMERRCTLR7);
    ecc_tmp |= (1U << 20U);
    ecm_write(ECMERRCTLR7, ecc_tmp);

    /* Lock the ECM registers */
    ecm_lock();
}

void edc_axi_enable(void)
{
    uint32_t edc_tmp;

    /* Unlock the write protect of ECM registers */
    ecm_unlock();

    /* (1) Set the corresponding bits of the ECMERRTGTR, ECMERRCTLR
        and ECMERRFATALR registers to inform the control domain of the fatal error. */

    /* Set bit 10 - bit 6 of ECMERRTGTR7 to all 0 and bit 10 - bit 6 of
        ECMERRCTLR7 to 1. (Error of AXI-Bus ECM of each hierarchy) */
    edc_tmp = mem_read32(ECMERRTGTR7);
    edc_tmp &= ~(0x1fU << 6U);
    ecm_write(ECMERRTGTR7, edc_tmp);

    edc_tmp = mem_read32(ECMERRCTLR7);
    edc_tmp |= (0x1fU << 6U);
    ecm_write(ECMERRCTLR7, edc_tmp);

    /* Set bit 23 - bit 16 of ECMERRTGTR39 to all 0 and bit 23 - bit 16 of
        ECMERRCTLR39 to 1. (Error of AXI-Bus ECM of each hierarchy) */
    edc_tmp = mem_read32(ECMERRTGTR39);
    edc_tmp &= ~(0xffU << 16U);
    ecm_write(ECMERRTGTR39, edc_tmp);

    edc_tmp = mem_read32(ECMERRCTLR39);
    edc_tmp |= (0xffU << 6U);
    ecm_write(ECMERRCTLR39, edc_tmp);

    /* Set bit 26 of ECMERRTGTR1 to 0 and bit 26 of
        ECMERRCTLR1 to 1. (CCI bus EDC error) */
    edc_tmp = mem_read32(ECMERRTGTR1);
    edc_tmp &= ~(0x1U << 26U);
    ecm_write(ECMERRTGTR1, edc_tmp);

    edc_tmp = mem_read32(ECMERRCTLR1);
    edc_tmp |= (0x1U << 26U);
    ecm_write(ECMERRCTLR1, edc_tmp);

    /* Set bit 10 - bit 6 of ECMERRFATALR7 to 1.
        (Notification of fatal error) */
    edc_tmp = mem_read32(ECMERRFATALR7);
    edc_tmp |= (0x1fU << 6U);
    ecm_write(ECMERRFATALR7, edc_tmp);

    /* Set bit 23 - bit 16 of ECMERRFATALR39 to 1.
        (Notification of fatal error) */
    edc_tmp = mem_read32(ECMERRFATALR39);
    edc_tmp |= (0xffU << 16U);
    ecm_write(ECMERRFATALR39, edc_tmp);

    /* Set bit 26 of ECMERRFATALR1 to 1.
        (Notification of fatal error) */
    edc_tmp = mem_read32(ECMERRFATALR1);
    edc_tmp |= (0x1U << 26U);
    ecm_write(ECMERRFATALR1, edc_tmp);

    /* Lock the ECM registers */
    ecm_lock();
}

void edc_vram_enable(void)
{
    uint32_t edc_tmp;

    /* Unlock the write protect of ECM registers */
    ecm_unlock();

    /* (1) Set the corresponding bits of the ECMERRTGTR, ECMERRCTLR and
        ECMERRFATALR registers to inform the control domain of the fatal error. */

    /* Set bit 19 of ECMERRTGTR17 to 0 and bit 19 of ECMERRCTLR17 to 1.
                                                    (RT-VRAM edc 1-bit error) */
    edc_tmp = mem_read32(ECMERRTGTR17);
    edc_tmp &= ~(0x1U << 19U);
    ecm_write(ECMERRTGTR17, edc_tmp);

    edc_tmp = mem_read32(ECMERRCTLR17);
    edc_tmp |= (0x1U << 19U);
    ecm_write(ECMERRCTLR17, edc_tmp);

    /* Set bit 18 of ECMERRTGTR17 to 0 and bit 18 of ECMERRCTLR17 to 1.
                                                (RT-VRAM edc multi-bit error) */
    edc_tmp = mem_read32(ECMERRTGTR17);
    edc_tmp &= ~(0x1U << 18U);
    ecm_write(ECMERRTGTR17, edc_tmp);

    edc_tmp = mem_read32(ECMERRCTLR17);
    edc_tmp |= (0x1U << 18U);
    ecm_write(ECMERRCTLR17, edc_tmp);

    /* Set bit 19, 18 of ECMERRFATALR17 to 1. (Notification of fatal error) */
    edc_tmp = mem_read32(ECMERRFATALR17);
    edc_tmp |= (0x3U << 18U);
    ecm_write(ECMERRFATALR17, edc_tmp);

    /* Set bit 0 of EDC_CFG to 1. (EDC Error Control) */
    edc_tmp = mem_read32(EDC_CFG);
    edc_tmp |= (0x1U << 0U);
    ecm_write(EDC_CFG, edc_tmp);

    /* Lock the ECM registers */
    ecm_lock();
}
