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

/*******************************************************************************
 * DESCRIPTION   : eMMC initialze
 ******************************************************************************/
/******************************************************************************
 * @file          emmc_init.c
 * - Version      : 0.05
 * @brief         initialize of SDHI driver.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 22.02.2022 0.01     First Release
 *         : 22.10.2021 0.02     Remove unnecessary code
 *         : 22.12.2021 0.03     Support static analysis
 *         : 06.01.2022 0.04     Modify SDHI access from DMA to PIO.
 *         : 06.04/2022 0.05     Del SDnH clock & SDn=200MHz(Duplicate settings)
 *****************************************************************************/

/* ************************ HEADER (INCLUDE) SECTION *********************** */
#include "emmc_config.h"
#include "emmc_hal.h"
#include "emmc_std.h"
#include "emmc_registers.h"
#include "emmc_def.h"

/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */

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

/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
st_mmc_base mmc_drv_obj;

/* ************************** FUNCTION PROTOTYPES ************************** */
static void emmc_drv_init(void);
static EMMC_ERROR_CODE emmc_dev_init(void);
static EMMC_ERROR_CODE emmc_dev_finalize(void);
static void emmc_memset(void *buff, uint8_t data, uint32_t cnt);
static EMMC_ERROR_CODE emmc_reset_controller(void);
static void emmc_driver_config(void);
static void emmc_set_data_timeout(uint32_t data_timeout);

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

/** brief eMMC initialize.
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * .
 *
 * retval EMMC_SUCCESS successful.
 * retval EMMC_ERR error from interrupt API.
 */
EMMC_ERROR_CODE emmc_init(void)
{
	/* initialize H/W */
	(void)emmc_reset_controller();

	/* Configuration */
	emmc_driver_config();

	return EMMC_SUCCESS;
}

/** terminate emmc driver
 *
 * EMMC H/W and S/W resource is released.
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * .
 *
 * return None.
 */
EMMC_ERROR_CODE emmc_terminate(void)
{
	EMMC_ERROR_CODE result = EMMC_ERR;

	/* H/W finalize */
	result = emmc_dev_finalize();

	/* driver finalize */
	emmc_memset((uint8_t *)(&mmc_drv_obj), 0U, sizeof(st_mmc_base));  /* clear global variable */

	return result;
}

/** Function executes full reset to MMC host controller without taking power out from the memory card.
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * Reset MMC host controller without taking power out from the memory card.
 * Memory card preserves its state.
 *
 * return None
 */
static EMMC_ERROR_CODE emmc_reset_controller(void)
{
	EMMC_ERROR_CODE result = EMMC_ERR;

	/* initialize mmc driver */
	emmc_drv_init();

	mmc_drv_obj.base_address = MMC0_SD_BASE;

	/* initialize H/W */
	result = emmc_dev_init();

	mmc_drv_obj.initialize = TRUE;

	return result;

}

/** Configuration eMMC driver
 *
 * - Pre-conditions:<BR>
 * initialized eMMC driver.
 * - Post-conditions:<BR>
 * .
 *
 * return None
 */
static void emmc_driver_config(void)
{
	/* Read/Write data timeout */
	emmc_set_data_timeout(EMMC_RW_DATA_TIMEOUT);
}

/** Sets data timeout
 *
 * Sets the data timeout value for read and write operations.
 *
 * - Pre-conditions:<BR>
 * initialized eMMC driver.
 *
 * - Post-conditions:<BR>
 * After this function is called, the timeout value is set according to argument.
 *
 * param[in] time_out The desired timeout value in milliseconds.
 * return None
 */
static void emmc_set_data_timeout(uint32_t data_timeout)
{
	mmc_drv_obj.data_timeout = data_timeout;
}

/** eMMC driver initialize. (software)
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * .
 *
 * return None.
 */
static void emmc_drv_init(void)
{
	/* initialize */
	emmc_memset((uint8_t *)(&mmc_drv_obj), 0U, sizeof(st_mmc_base));

	mmc_drv_obj.data_timeout = EMMC_RW_DATA_TIMEOUT;

	mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
}

/** eMMC driver initialize. (H/W)
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * .
 *
 * return None.
 */
static EMMC_ERROR_CODE emmc_dev_init(void)
{

	/* MMCIF initialize */
	mem_write32(SD_INFO1, 0x00000000U); /* all interrupt clear */
	mem_write32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */
	mem_write32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */
	mem_write32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */

	mem_write32(HOST_MODE, 0x00000000U); /* SD_BUF access width = 64-bit */
	mem_write32(SD_OPTION, 0x0000C0EEU); /* Bus width = 1bit, timeout=MAX */
	mem_write32(SD_CLK_CTRL, 0x00000000U); /* Automatic Control=Disable, Clock Output=Disable */

	return EMMC_SUCCESS;
}

/** EMMC H/W finalize
 *
 * EMMC Host and Card hardware resource is released.
 *
 * - Pre-conditions:<BR>
 * .
 *
 * - Post-conditions:<BR>
 * .
 * return None.
 */
static EMMC_ERROR_CODE emmc_dev_finalize(void)
{
	EMMC_ERROR_CODE result = EMMC_ERR;

	/* MMC power off
	 * the power supply of eMMC device is always turning on.
	 * RST_n : Hi --> Low level.
	 */
	result = emmc_memcard_power(FALSE);

	mem_write32(SD_INFO1, 0x00000000U);
	mem_write32(SD_INFO2, 0x00000800U);
	mem_write32(DM_CM_INFO1, 0x00000000U);
	mem_write32(DM_CM_INFO2, 0x00000000U);

	mem_write32(SD_CLK_CTRL, 0x00000020U);
	mem_write32(CC_EXT_MODE, 0x00000000U);
	mem_write32(SD_STOP, 0x00000000U);
	mem_write32(SD_SECCNT, 0x00000000U);
	mem_write32(DM_CM_DTRAN_MODE, 0x00000000U);
	mem_write32(DM_DTRAN_ADDR, 0x00000000U);
	mem_write32(SD_OPTION, 0x00000000U);
	mem_write32(DM_CM_DTRAN_CTRL, 0x00000000U);

	return result;
}

/** Set power to memory card IF.
 * This function control Vcc and Vccq and RST_n.
 *
 * attention
 * CPU cannot control Vcc&Vccq.
 * The power supply of eMMC device is always turning on.
 *
 * param[in] mode TRUE = power on, FALSE = power off
 *
 * retval EMMC_SUCCESS powering succeeded
 * retval EMMC_ERR_CARD_POWER powering failed
 */
EMMC_ERROR_CODE emmc_memcard_power(uint32_t mode)
{
	if (mode == TRUE) {
		/* power on (Vcc&Vccq is always power on) */
		mmc_drv_obj.card_power_enable = TRUE;
	} else {
		/* power off (Vcc&Vccq is always power on) */
		mmc_drv_obj.card_power_enable = FALSE;
		mmc_drv_obj.mount = FALSE;
		mmc_drv_obj.selected = FALSE;
	}

	return EMMC_SUCCESS;
}

/** memset(). no use C standard library.
 *
 * - Pre-conditions:<BR>
 * .
 * - Post-conditions:<BR>
 * .
 *
 * param[in,out] buff pointer to buffer (virtual)
 * param[in] data fill data.
 * param[in] cnt fill size (number of bytes)
 * return None.
 */
static void emmc_memset(void *buff, uint8_t data, uint32_t cnt)
{
	uint8_t *tmp = NULL;
	tmp = (uint8_t *)buff;

	if (buff == NULL) {
		return;
	}

	while (cnt > 0U) {
		*tmp = data;
		tmp++;
		cnt--;
	}
}

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

