/*******************************************************************************
 * Copyright (c) 2023-2025 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 initialize function
 ******************************************************************************/
/******************************************************************************
 * @file          ecc_enable_v4m.c
 * - Version      : 0.05
 * @brief         Enable setting process of ECC for DRAM.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 21.08.2023 0.01     First Release
 *         : 21.08.2023 0.02     Update the ecc setting according to HW SAN rev0.82.
 *         : 08.04.2024 0.03     Update the ecc register setting.
 *         : 13.06.2024 0.04     Fix register setting for EDC_CFG, and revise
 *         :                     the ecm_lock()/ecm_unlock() process.
 *         : 27.01.2025 0.05     Add ECM setting process.
 *                               Remove unused functions.
 *****************************************************************************/

#include <stdint.h>

#if (ECC_ENABLE == 1)
#include "ecc_enable_v4m.h"
#include "ecm_enable_v4m.h"
#include "mem_io.h"
#include "v4m/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(DB0SYSCNT0A, 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 1 of ECMERRTGTR0 to 0 and bit 1 of ECMERRCTLR0 to 1.  */
    ecm_tmp = mem_read32(ECMERRTGTR0);
    ecm_tmp &= ~(0x2U);
    ecm_write(ECMERRTGTR0, ecm_tmp);

    ecm_tmp = mem_read32(ECMERRCTLR0);
    ecm_tmp |= (0x2U);
    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(DB0FSDRAMECCAREA01, ECC_PROT_SIZE01);

    /* (C) Initialization for DRAM */
    mem_write32(DBSC_DB0ACEN, 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);

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

    /*** If DRAM is connected to RANK1, Initialize RANK1 by the following procedure ***/
    /* [Step1] Specify RANK1 as the initialization target. Set 0x1 to DB0FSCONF00A[1:0]. */
    mem_write32(DB0FSCONF00A, 0x1U);

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

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

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

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

    /* (D) Setting ECC protection enable */
    ecm_tmp = mem_read32(DB0FSCONFAXI0);
    ecm_tmp |= (0x3U << 8U);
    mem_write32(DB0FSCONFAXI0, ecm_tmp);

    /* (E) System RAM initialization */
    /* Read DB0FSSTAT00A and wait until its value changes to 0x1. */
    /* When DB0FSSTAT00A changes to 0x1, the System RAM area initialization is complete of dbs0 */
    NOTICE("System RAM is initializing.......\n");
    do
    {
        ecm_tmp = 0x01U;
        ecm_tmp &= mem_read32(DB0FSSTAT00A);
    } while (ecm_tmp != 0x1U);

    /* (F) Setting for ECC error interrupt */
    /* (1) Set the ECC error interrupt for read data */
    mem_write32(DB0FSINTENB02A, 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);

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

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

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

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

