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

/*******************************************************************************
 * DESCRIPTION   : ECC initialize function
 ******************************************************************************/
/******************************************************************************
 * @file          ecc_enable_v4h.c
 * - Version      : 0.06
 * @brief         Enable setting process of ECC for DRAM.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 09.08.2022 0.01     First Release
 *         : 16.11.2022 0.02     Change ecc_enable to ecc_sdram_enable
 *         : 04.04.2023 0.03     Removed stdio.h and string.h.
 *         : 20.09.2023 0.04     Update the ecc_sdram_enable function according to HWSAN rev0.82.
 *         : 13.06.2024 0.05     Fix register setting for EDC_CFG, and revise
 *         :                     the ecm_lock()/ecm_unlock() process.
 *         : 27.01.2025 0.06     Remove unused functions.
 *****************************************************************************/

#include <stdint.h>

#if (ECC_ENABLE == 1)
#include "ecc_enable_v4h.h"
#include "ecm_enable_v4h.h"
#include "mem_io.h"
#include "v4h/lpddr5/boot_init_dram_regdef.h"

/* Reference:"ECC for DRAM and System RAM" in R19AN0083EJ0082_R-CarV4H_SAN_for_Customer.pdf*/
void ecc_sdram_enable(void)
{
    NOTICE("ECC for DRAM is enable.\n");

    uint32_t ecm_tmp;

    /* Before writing to DBSC register, it shall be set to "0x00001234" for the following registers.
    After writing to DBSC register, it shall be set to a value other than "0x00001234" for the following registers. */
    mem_write32(DB0SYSCNT0, 0x00001234U);
    mem_write32(DB1SYSCNT0, 0x00001234U);
    mem_write32(DB0SYSCNT0A, 0x00001234U);
    mem_write32(DB1SYSCNT0A, 0x00001234U);

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

    /* (1) Set the corresponding bits of the ECMERRTGTR and ECMERRCTLR registers
                to inform the external device of the error via the ERROROUT# pin. */
    /* Set bit 3, 1 of ECMERRTGTR0 to 0 and bit 3, 1 of ECMERRCTLR0 to 1.  */
    ecm_tmp = mem_read32(ECMERRTGTR0);
    ecm_tmp &= ~(0xAU);
    ecm_write(ECMERRTGTR0, ecm_tmp);

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

    /* (B) Setting ECC protection area */
    /* Set the bottom row address of the ECC protection area */
    mem_write32(DB0FSDRAMECCAREA00, ECC_PROT_SIZE00);
    mem_write32(DB1FSDRAMECCAREA00, ECC_PROT_SIZE10);

    /* (C) Initialization for DRAM */
    mem_write32(DBSC_DB0ACEN, 0x00000000U);
    mem_write32(DBSC_DB1ACEN, 0x00000000U);

    /*** Initialization for DRAM connected to DBS0 Initialize RANK0 in according with the following procedure.***/
    /* [Step1] Specify RANK0 as the initialization target. Set 0x0 to DB0FSCONF00A[1:0]. */
    mem_write32(DB0FSCONF00A, 0x0U);

    /* [Step2] Set the start row address of the initialization area in DB0FSCONF01A[31:0]. */
    mem_write32(DB0FSCONF01A, START_ECC_INIT_AREA00);

    /* [Step3] Set the end row address of the initialization area in DB0FSCONF02A[31:0]. */
    mem_write32(DB0FSCONF02A, END_ECC_INIT_AREA00);

    /* [Step4] Set 0x1 to DB0FSCTRL01A[0] to start initialization. */
    mem_write32(DB0FSCTRL01A, 0x01U);

    /*** Initialization for DRAM connected to DBS1 Initialize RANK0 in according with the following procedure.***/
    /* [Step1] Specify RANK0 as the initialization target. Set 0x0 to DB1FSCONF00A[1:0]. */
    mem_write32(DB1FSCONF00A, 0x0U);

    /* [Step2] Set the start row address of the initialization area in DB1FSCONF01A[31:0]. */
    mem_write32(DB1FSCONF01A, START_ECC_INIT_AREA10);

    /* [Step3] Set the end row address of the initialization area in DB1FSCONF02A[31:0]. */
    mem_write32(DB1FSCONF02A, END_ECC_INIT_AREA10);

    /* [Step4] Set 0x1 to DB1FSCTRL01A[0] to start initialization. */
    mem_write32(DB1FSCTRL01A, 0x01U);

    /* [Step5] When DB0FSSTAT01A[0] is set to 0x1, DBS0/RANK1 initialization is complete. */
    /* [Step5] When DB1FSSTAT01A[0] is set to 0x1, DBS1/RANK0 initialization is complete.*/
    NOTICE("DRAM rank 0 of DBSC0/1 is initializing.......\n");
    do
    {
        ecm_tmp = 0x01U;
        ecm_tmp &= mem_read32(DB0FSSTAT01A);
        ecm_tmp &= mem_read32(DB1FSSTAT01A);
    } while ((ecm_tmp & 0x01U) != 0x01U);

    /* (D) Setting ECC protection enable */
    /* Enable ECC protection for dbs0/rank0 by setting 0x1 in DB0FSCONFAXI0[8]. */
    ecm_tmp = mem_read32(DB0FSCONFAXI0);
    ecm_tmp |= (0x1U << 8U);
    mem_write32(DB0FSCONFAXI0, ecm_tmp);

    /* Enable ECC protection for dbs1/rank0 by setting 0x1 in DB1FSCONFAXI0[8]. */
    ecm_tmp = mem_read32(DB1FSCONFAXI0);
    ecm_tmp |= (0x1U << 8U);
    mem_write32(DB1FSCONFAXI0, ecm_tmp);

    /* (E) System RAM initialization */
    NOTICE("System RAM of DBSC0 is initializing.......\n");
    do
    {
        ecm_tmp = 0x01U;
        ecm_tmp &= mem_read32(DB0FSSTAT00A);
    } while (ecm_tmp != 0x1U);

    NOTICE("System RAM of DBSC1 is initializing.......\n");
    do
    {
        ecm_tmp = 0x01U;
        ecm_tmp &= mem_read32(DB1FSSTAT00A);
    } while (ecm_tmp != 0x1U);

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

    /* (2) Set the ECC error interrupt during RMW operation for System RAM. */
    ecm_tmp = mem_read32(DB0FSINTENB02A);
    ecm_tmp |= 0xFF000000U;
    mem_write32(DB0FSINTENB02A, ecm_tmp);
    ecm_tmp = mem_read32(DB1FSINTENB02A);
    ecm_tmp |= 0xFF000000U;
    mem_write32(DB1FSINTENB02A, ecm_tmp);

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

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

    /* Enable the write protect of ECM registers */
    mem_write32(DBSC_DB0ACEN, 0x00000001U);
    mem_write32(DBSC_DB1ACEN, 0x00000001U);

    /* Enable the access protect for DBSC registers */
    mem_write32(DB0SYSCNT0, 0x00000000U);
    mem_write32(DB1SYSCNT0, 0x00000000U);
    mem_write32(DB0SYSCNT0A, 0x00000000U);
    mem_write32(DB1SYSCNT0A, 0x00000000U);
}
#endif /* ECC_ENABLE == 1 */

