nxp:add driver support for sd and emmc

SD & eMMC driver support for NXP SoC.

Signed-off-by: Ruchika Gupta <ruchika.gupta@nxp.com>
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Change-Id: I245fecd2c791697238b5667c46bf5466379695ce
diff --git a/drivers/nxp/sd/sd_mmc.c b/drivers/nxp/sd/sd_mmc.c
new file mode 100644
index 0000000..f7f48e7
--- /dev/null
+++ b/drivers/nxp/sd/sd_mmc.c
@@ -0,0 +1,1496 @@
+/*
+ * Copyright 2021 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ */
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include "nxp_timer.h"
+#include "sd_mmc.h"
+#include <utils.h>
+#include <utils_def.h>
+
+
+/* Private structure for MMC driver data */
+static struct mmc mmc_drv_data;
+
+#ifndef NXP_POLICY_OTA
+/*
+ * For NXP_POLICY_OTA, SD needs to do R/W on OCRAM. OCRAM is secure memory at
+ * default. SD can only do non-secure DMA. Configuring SD to work in PIO mode
+ * instead of DMA mode will make SD R/W on OCRAM available.
+ */
+/* To debug without dma comment this MACRO */
+#define NXP_SD_DMA_CAPABILITY
+#endif
+#define SD_TIMEOUT        1000 /* ms */
+#define SD_TIMEOUT_HIGH   20000 /* ms */
+#define SD_BLOCK_TIMEOUT  8 /* ms */
+
+#define ERROR_ESDHC_CARD_DETECT_FAIL	-1
+#define ERROR_ESDHC_UNUSABLE_CARD	-2
+#define ERROR_ESDHC_COMMUNICATION_ERROR	-3
+#define ERROR_ESDHC_BLOCK_LENGTH	-4
+#define ERROR_ESDHC_DMA_ERROR		-5
+#define ERROR_ESDHC_BUSY		-6
+
+/***************************************************************
+ * Function    :    set_speed
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  clock - Clock Value to be set
+ * Return      :    void
+ * Description :    Calculates the value of SDCLKFS and DVS to be set
+ *                  for getting the required clock assuming the base_clk
+ *                  as a fixed value (MAX_PLATFORM_CLOCK)
+ *****************************************************************/
+static void set_speed(struct mmc *mmc, uint32_t clock)
+{
+	/* sdhc_clk = (base clock) / [(SDCLKFS × 2) × (DVS +1)] */
+
+	uint32_t dvs = 1U;
+	uint32_t sdclkfs = 2U;
+	/* TBD - Change this to actual platform clock by reading via RCW */
+	uint32_t base_clk = MAX_PLATFORM_CLOCK;
+
+	if (base_clk / 16 > clock) {
+		for (sdclkfs = 2U; sdclkfs < 256U; sdclkfs *= 2U) {
+			if ((base_clk / sdclkfs) <= (clock * 16)) {
+				break;
+			}
+		}
+	}
+
+	for (dvs = 1U; dvs <= 16U; dvs++) {
+		if ((base_clk / (dvs * sdclkfs)) <= clock) {
+			break;
+		}
+	}
+
+	sdclkfs >>= 1U;
+	dvs -= 1U;
+
+	esdhc_out32(&mmc->esdhc_regs->sysctl,
+			(ESDHC_SYSCTL_DTOCV(TIMEOUT_COUNTER_SDCLK_2_27) |
+			 ESDHC_SYSCTL_SDCLKFS(sdclkfs) | ESDHC_SYSCTL_DVS(dvs) |
+			 ESDHC_SYSCTL_SDCLKEN));
+}
+
+/***************************************************************************
+ * Function    :    esdhc_init
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  card_detect - flag to indicate if card insert needs
+ *                  to be detected or not. For SDHC2 controller, Card detect
+ *                  is not present, so this field will be false
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Set Initial Clock Speed
+ *                  2. Card Detect if not eMMC
+ *                  3. Enable Controller Clock
+ *                  4. Send 80 ticks for card to power up
+ *                  5. Set LE mode and Bus Width as 1 bit.
+ ***************************************************************************/
+static int esdhc_init(struct mmc *mmc, bool card_detect)
+{
+	uint32_t val;
+	uint64_t start_time;
+
+	/* Reset the entire host controller */
+	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_RSTA;
+	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+	/* Wait until the controller is available */
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_RSTA;
+		if (val == 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->sysctl) &
+		(ESDHC_SYSCTL_RSTA);
+	if (val != 0U) {
+		ERROR("SD Reset failed\n");
+		return ERROR_ESDHC_BUSY;
+	}
+
+	/* Set initial clock speed */
+	set_speed(mmc, CARD_IDENTIFICATION_FREQ);
+
+	if (card_detect) {
+		/* Check CINS in prsstat register */
+		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+			ESDHC_PRSSTAT_CINS;
+		if (val == 0) {
+			ERROR("CINS not set in prsstat\n");
+			return ERROR_ESDHC_CARD_DETECT_FAIL;
+		}
+	}
+
+	/* Enable controller clock */
+	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_SDCLKEN;
+	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+	/* Send 80 clock ticks for the card to power up */
+	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_INITA;
+	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
+
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT) {
+		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
+		if (val != 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
+	if (val == 0U) {
+		ERROR("Failed to power up the card\n");
+		return ERROR_ESDHC_CARD_DETECT_FAIL;
+	}
+
+	INFO("Card detected successfully\n");
+
+	val = esdhc_in32(&mmc->esdhc_regs->proctl);
+	val = val | (ESDHC_PROCTL_EMODE_LE | ESDHC_PROCTL_DTW_1BIT);
+
+	/* Set little endian mode, set bus width as 1-bit */
+	esdhc_out32(&mmc->esdhc_regs->proctl, val);
+
+	/* Enable cache snooping for DMA transactions */
+	val = esdhc_in32(&mmc->esdhc_regs->ctl) | ESDHC_DCR_SNOOP;
+	esdhc_out32(&mmc->esdhc_regs->ctl, val);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_send_cmd
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  cmd - Command Number
+ *                  args - Command Args
+ * Return      :    SUCCESS is 0, or Error Code ( < 0)
+ * Description :    Updates the eSDHC registers cmdargs and xfertype
+ ***************************************************************************/
+static int esdhc_send_cmd(struct mmc *mmc, uint32_t cmd, uint32_t args)
+{
+	uint32_t val;
+	uint64_t start_time;
+	uint32_t xfertyp = 0;
+
+	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+	/* Wait for the command line & data line to be free */
+	/* (poll the CIHB,CDIHB bit of the present state register) */
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+			(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
+		if (val == 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+		(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
+	if (val != 0U) {
+		ERROR("SD send cmd: Command Line or Data Line Busy cmd = %x\n",
+				cmd);
+		return ERROR_ESDHC_BUSY;
+	}
+
+	if (cmd == CMD2 || cmd == CMD9) {
+		xfertyp |= ESDHC_XFERTYP_RSPTYP_136;
+	} else  if (cmd == CMD7 || (cmd == CMD6 && mmc->card.type == MMC_CARD)) {
+		xfertyp |= ESDHC_XFERTYP_RSPTYP_48_BUSY;
+	} else if (cmd != CMD0) {
+		xfertyp |= ESDHC_XFERTYP_RSPTYP_48;
+	}
+
+	if (cmd == CMD2 || cmd == CMD9) {
+		xfertyp |= ESDHC_XFERTYP_CCCEN; /* Command index check enable */
+	} else if ((cmd != CMD0) && (cmd != ACMD41) && (cmd != CMD1)) {
+		xfertyp = xfertyp | ESDHC_XFERTYP_CCCEN | ESDHC_XFERTYP_CICEN;
+	}
+
+	if ((cmd == CMD8 || cmd == CMD14 || cmd == CMD19) &&
+			mmc->card.type == MMC_CARD) {
+		xfertyp |=  ESDHC_XFERTYP_DPSEL;
+		if (cmd != CMD19) {
+			xfertyp |= ESDHC_XFERTYP_DTDSEL;
+		}
+	}
+
+	if (cmd == CMD6 || cmd == CMD17 || cmd == CMD18 || cmd == CMD24 ||
+	    cmd == ACMD51) {
+		if (!(mmc->card.type == MMC_CARD && cmd == CMD6)) {
+			if (cmd == CMD24) {
+				xfertyp |= ESDHC_XFERTYP_DPSEL;
+			} else {
+				xfertyp |= (ESDHC_XFERTYP_DPSEL |
+					    ESDHC_XFERTYP_DTDSEL);
+			}
+		}
+
+		if (cmd == CMD18) {
+			xfertyp |= ESDHC_XFERTYP_BCEN;
+			if (mmc->dma_support != 0) {
+				/* Set BCEN of XFERTYP */
+				xfertyp |= ESDHC_XFERTYP_DMAEN;
+			}
+		}
+
+		if ((cmd == CMD17 || cmd == CMD24) && (mmc->dma_support != 0)) {
+			xfertyp |= ESDHC_XFERTYP_DMAEN;
+		}
+	}
+
+	xfertyp |= ((cmd & 0x3F) << 24);
+	esdhc_out32(&mmc->esdhc_regs->cmdarg, args);
+	esdhc_out32(&mmc->esdhc_regs->xfertyp, xfertyp);
+
+#ifdef NXP_SD_DEBUG
+	INFO("cmd = %d\n", cmd);
+	INFO("args = %x\n", args);
+	INFO("xfertyp: = %x\n", xfertyp);
+#endif
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_wait_response
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  response - Value updated
+ * Return      :    SUCCESS - Response Received
+ *                  COMMUNICATION_ERROR - Command not Complete
+ *                  COMMAND_ERROR - CIE, CCE or CEBE  error
+ *                  RESP_TIMEOUT - CTOE error
+ * Description :    Checks for successful command completion.
+ *                  Clears the CC bit at the end.
+ ***************************************************************************/
+static int esdhc_wait_response(struct mmc *mmc, uint32_t *response)
+{
+	uint32_t val;
+	uint64_t start_time;
+	uint32_t status = 0U;
+
+	/* Wait for the command to complete */
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
+		if (val != 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
+	if (val == 0U) {
+		ERROR("%s:IRQSTAT Cmd not complete(CC not set)\n", __func__);
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+	/* Check whether the interrupt is a CRC, CTOE or CIE error */
+	if ((status & (ESDHC_IRQSTAT_CIE | ESDHC_IRQSTAT_CEBE |
+				ESDHC_IRQSTAT_CCE)) != 0) {
+		ERROR("%s: IRQSTAT CRC, CEBE or CIE error = %x\n",
+							__func__, status);
+		return COMMAND_ERROR;
+	}
+
+	if ((status & ESDHC_IRQSTAT_CTOE) != 0) {
+		INFO("%s: IRQSTAT CTOE set = %x\n", __func__, status);
+		return RESP_TIMEOUT;
+	}
+
+	if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+		ERROR("%s: IRQSTAT DMAE set = %x\n", __func__, status);
+		return ERROR_ESDHC_DMA_ERROR;
+	}
+
+	if (response != NULL) {
+		/* Get response values from eSDHC CMDRSPx registers. */
+		response[0] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[0]);
+		response[1] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[1]);
+		response[2] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[2]);
+		response[3] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[3]);
+#ifdef NXP_SD_DEBUG
+		INFO("Resp R1 R2 R3 R4\n");
+		INFO("Resp R1 = %x\n", response[0]);
+		INFO("R2 = %x\n", response[1]);
+		INFO("R3 = %x\n", response[2]);
+		INFO("R4 = %x\n", response[3]);
+		INFO("\n");
+#endif
+	}
+
+	/* Clear the CC bit - w1c */
+	val = esdhc_in32(&mmc->esdhc_regs->irqstat) | ESDHC_IRQSTAT_CC;
+	esdhc_out32(&mmc->esdhc_regs->irqstat, val);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    mmc_switch_to_high_frquency
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    mmc card bellow ver 4.0 does not support high speed
+ *                  freq = 20 MHz
+ *                  Send CMD6 (CMD_SWITCH_FUNC) With args 0x03B90100
+ *                  Send CMD13 (CMD_SEND_STATUS)
+ *                  if SWITCH Error, freq = 26 MHz
+ *                  if no error, freq = 52 MHz
+ ***************************************************************************/
+static int mmc_switch_to_high_frquency(struct mmc *mmc)
+{
+	int error;
+	uint32_t response[4];
+	uint64_t start_time;
+
+	mmc->card.bus_freq = MMC_SS_20MHZ;
+	/* mmc card bellow ver 4.0 does not support high speed */
+	if (mmc->card.version < MMC_CARD_VERSION_4_X) {
+		return 0;
+	}
+
+	/* send switch cmd to change the card to High speed */
+	error = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SET_EXT_CSD_HS_TIMING);
+	if (error != 0) {
+		return error;
+	}
+	error = esdhc_wait_response(mmc, response);
+	if (error != 0) {
+		return error;
+	}
+
+	start_time = get_timer_val(0);
+	do {
+		/* check the status for which error */
+		error = esdhc_send_cmd(mmc,
+				CMD_SEND_STATUS, mmc->card.rca << 16);
+		if (error != 0) {
+			return error;
+		}
+
+		error = esdhc_wait_response(mmc, response);
+		if (error != 0) {
+			return error;
+		}
+	} while (((response[0] & SWITCH_ERROR) != 0) &&
+			(get_timer_val(start_time) < SD_TIMEOUT));
+
+	/* Check for the present state of card */
+	if ((response[0] & SWITCH_ERROR) != 0) {
+		mmc->card.bus_freq = MMC_HS_26MHZ;
+	} else {
+		mmc->card.bus_freq = MMC_HS_52MHZ;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_set_data_attributes
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  blkcnt
+ *                  blklen
+ * Return      :    SUCCESS or Error Code
+ * Description :    Set block attributes and watermark level register
+ ***************************************************************************/
+static int esdhc_set_data_attributes(struct mmc *mmc, uint32_t *dest_ptr,
+		uint32_t blkcnt, uint32_t blklen)
+{
+	uint32_t val;
+	uint64_t start_time;
+	uint32_t wml;
+	uint32_t wl;
+	uint32_t dst = (uint32_t)((uint64_t)(dest_ptr));
+
+	/* set blkattr when no transactions are executing */
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
+		if (val == 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
+	if (val != 0U) {
+		ERROR("%s: Data line active.Can't set attribute\n", __func__);
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	wml = esdhc_in32(&mmc->esdhc_regs->wml);
+	wml &= ~(ESDHC_WML_WR_BRST_MASK | ESDHC_WML_RD_BRST_MASK |
+			ESDHC_WML_RD_WML_MASK | ESDHC_WML_WR_WML_MASK);
+
+	if ((mmc->dma_support != 0) && (dest_ptr != NULL)) {
+		/* Set burst length to 128 bytes */
+		esdhc_out32(&mmc->esdhc_regs->wml,
+				wml | ESDHC_WML_WR_BRST(BURST_128_BYTES));
+		esdhc_out32(&mmc->esdhc_regs->wml,
+				wml | ESDHC_WML_RD_BRST(BURST_128_BYTES));
+
+		/* Set DMA System Destination Address */
+		esdhc_out32(&mmc->esdhc_regs->dsaddr, dst);
+	} else {
+		wl = (blklen >= BLOCK_LEN_512) ?
+			WML_512_BYTES : ((blklen + 3) / 4);
+		/* Set 'Read Water Mark Level' register */
+		esdhc_out32(&mmc->esdhc_regs->wml, wml | ESDHC_WML_RD_WML(wl));
+	}
+
+	/* Configure block Attributes register */
+	esdhc_out32(&mmc->esdhc_regs->blkattr,
+		ESDHC_BLKATTR_BLKCNT(blkcnt) | ESDHC_BLKATTR_BLKSZE(blklen));
+
+	mmc->block_len = blklen;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_read_data_nodma
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  dest_ptr - Bufffer where read data is to be copied
+ *                  len - Length of Data to be read
+ * Return      :    SUCCESS or Error Code
+ * Description :    Read data from the sdhc buffer without using DMA
+ *                  and using polling mode
+ ***************************************************************************/
+static int esdhc_read_data_nodma(struct mmc *mmc, void *dest_ptr, uint32_t len)
+{
+	uint32_t i = 0U;
+	uint32_t status;
+	uint32_t num_blocks;
+	uint32_t *dst = (uint32_t *)dest_ptr;
+	uint32_t val;
+	uint64_t start_time;
+
+	num_blocks = len / mmc->block_len;
+
+	while ((num_blocks--) != 0U) {
+
+		start_time = get_timer_val(0);
+		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+				ESDHC_PRSSTAT_BREN;
+			if (val != 0U) {
+				break;
+			}
+		}
+
+		val = esdhc_in32(&mmc->esdhc_regs->prsstat)
+			& ESDHC_PRSSTAT_BREN;
+		if (val == 0U) {
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+
+		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+				i < mmc->block_len / 4;    i++, dst++) {
+			/* get data from data port */
+			val = mmio_read_32(
+					(uintptr_t)&mmc->esdhc_regs->datport);
+			esdhc_out32(dst, val);
+			/* Increment destination pointer */
+			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+		}
+		/* Check whether the interrupt is an DTOE/DCE/DEBE */
+		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
+					ESDHC_IRQSTAT_DEBE)) != 0) {
+			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
+									status);
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+	}
+
+	/* Wait for TC */
+
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+		if (val != 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+	if (val == 0U) {
+		ERROR("SD read timeout: Transfer bit not set in IRQSTAT\n");
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_write_data_nodma
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  src_ptr - Buffer where data is copied from
+ *                  len - Length of Data to be written
+ * Return      :    SUCCESS or Error Code
+ * Description :    Write data to the sdhc buffer without using DMA
+ *                  and using polling mode
+ ***************************************************************************/
+static int esdhc_write_data_nodma(struct mmc *mmc, void *src_ptr, uint32_t len)
+{
+	uint32_t i = 0U;
+	uint32_t status;
+	uint32_t num_blocks;
+	uint32_t *src = (uint32_t *)src_ptr;
+	uint32_t val;
+	uint64_t start_time;
+
+	num_blocks = len / mmc->block_len;
+
+	while ((num_blocks--) != 0U) {
+		start_time = get_timer_val(0);
+		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+					 ESDHC_PRSSTAT_BWEN;
+			if (val != 0U) {
+				break;
+			}
+		}
+
+		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
+				 ESDHC_PRSSTAT_BWEN;
+		if (val == 0U) {
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+
+		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+		     i < mmc->block_len / 4; i++, src++) {
+			val = esdhc_in32(src);
+			/* put data to data port */
+			mmio_write_32((uintptr_t)&mmc->esdhc_regs->datport,
+				      val);
+			/* Increment source pointer */
+			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+		}
+		/* Check whether the interrupt is an DTOE/DCE/DEBE */
+		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
+					ESDHC_IRQSTAT_DEBE)) != 0) {
+			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
+			      status);
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+	}
+
+	/* Wait for TC */
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+		if (val != 0U) {
+			break;
+		}
+	}
+
+	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
+	if (val == 0U) {
+		ERROR("SD write timeout: Transfer bit not set in IRQSTAT\n");
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_read_data_dma
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  len - Length of Data to be read
+ * Return      :    SUCCESS or Error Code
+ * Description :    Read data from the sd card using DMA.
+ ***************************************************************************/
+static int esdhc_read_data_dma(struct mmc *mmc, uint32_t len)
+{
+	uint32_t status;
+	uint32_t tblk;
+	uint64_t start_time;
+
+	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
+
+	start_time = get_timer_val(0);
+
+	/* poll till TC is set */
+	do {
+		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
+					| ESDHC_IRQSTAT_DTOE)) != 0) {
+			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
+								 status);
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+
+		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+			ERROR("SD read error - DMA error = %x\n", status);
+			return ERROR_ESDHC_DMA_ERROR;
+		}
+
+	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
+		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
+		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
+
+	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
+		ERROR("SD read DMA timeout\n");
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_write_data_dma
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  len - Length of Data to be written
+ * Return      :    SUCCESS or Error Code
+ * Description :    Write data to the sd card using DMA.
+ ***************************************************************************/
+static int esdhc_write_data_dma(struct mmc *mmc, uint32_t len)
+{
+	uint32_t status;
+	uint32_t tblk;
+	uint64_t start_time;
+
+	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
+
+	start_time = get_timer_val(0);
+
+	/* poll till TC is set */
+	do {
+		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
+
+		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
+					| ESDHC_IRQSTAT_DTOE)) != 0) {
+			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
+			      status);
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+
+		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
+			ERROR("SD write error - DMA error = %x\n", status);
+			return ERROR_ESDHC_DMA_ERROR;
+		}
+	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
+		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
+		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
+
+	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
+		ERROR("SD write DMA timeout\n");
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_read_data
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  dest_ptr - Bufffer where read data is to be copied
+ *                  len - Length of Data to be read
+ * Return      :    SUCCESS or Error Code
+ * Description :    Calls esdhc_read_data_nodma and clear interrupt status
+ ***************************************************************************/
+int esdhc_read_data(struct mmc *mmc, void *dest_ptr, uint32_t len)
+{
+	int ret;
+
+	if (mmc->dma_support && len > 64) {
+		ret = esdhc_read_data_dma(mmc, len);
+	} else {
+		ret = esdhc_read_data_nodma(mmc, dest_ptr, len);
+	}
+
+	/* clear interrupt status */
+	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+	return ret;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_write_data
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  src_ptr - Buffer where data is copied from
+ *                  len - Length of Data to be written
+ * Return      :    SUCCESS or Error Code
+ * Description :    Calls esdhc_write_data_nodma and clear interrupt status
+ ***************************************************************************/
+int esdhc_write_data(struct mmc *mmc, void *src_ptr, uint32_t len)
+{
+	int ret;
+
+	if (mmc->dma_support && len > 64) {
+		ret = esdhc_write_data_dma(mmc, len);
+	} else {
+		ret = esdhc_write_data_nodma(mmc, src_ptr, len);
+	}
+
+	/* clear interrupt status */
+	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
+
+	return ret;
+}
+
+/***************************************************************************
+ * Function    :    sd_switch_to_high_freq
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Send ACMD51 (CMD_SEND_SCR)
+ *                  2. Read the SCR to check if card supports higher freq
+ *                  3. check version from SCR
+ *                  4. If SD 1.0, return (no Switch) freq = 25 MHz.
+ *                  5. Send CMD6 (CMD_SWITCH_FUNC) with args 0x00FFFFF1 to
+ *                     check the status of switch func
+ *                  6. Send CMD6 (CMD_SWITCH_FUNC) With args 0x80FFFFF1 to
+ *                     switch to high frequency = 50 Mhz
+ ***************************************************************************/
+static int sd_switch_to_high_freq(struct mmc *mmc)
+{
+	int err;
+	uint8_t scr[8];
+	uint8_t status[64];
+	uint32_t response[4];
+	uint32_t version;
+	uint32_t count;
+	uint32_t sd_versions[] = {SD_CARD_VERSION_1_0, SD_CARD_VERSION_1_10,
+		SD_CARD_VERSION_2_0};
+
+	mmc->card.bus_freq = SD_SS_25MHZ;
+	/* Send Application command */
+	err = esdhc_send_cmd(mmc, CMD_APP_CMD, mmc->card.rca << 16);
+	if (err != 0) {
+		return err;
+	}
+
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	esdhc_set_data_attributes(mmc, NULL, 1, 8);
+	/* Read the SCR to find out if this card supports higher speeds */
+	err = esdhc_send_cmd(mmc, CMD_SEND_SCR,  mmc->card.rca << 16);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	/* read 8 bytes of scr data */
+	err = esdhc_read_data(mmc, scr, 8U);
+	if (err != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	/* check version from SCR */
+	version = scr[0] & U(0xF);
+	if (version <= 2U) {
+		mmc->card.version = sd_versions[version];
+	} else {
+		mmc->card.version = SD_CARD_VERSION_2_0;
+	}
+
+	/* does not support switch func */
+	if (mmc->card.version == SD_CARD_VERSION_1_0) {
+		return 0;
+	}
+
+	/* read 64 bytes of status */
+	esdhc_set_data_attributes(mmc, NULL, 1U, 64U);
+
+	/* check the status of switch func */
+	for (count = 0U; count < 4U; count++) {
+		err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC,
+				SD_SWITCH_FUNC_CHECK_MODE);
+		if (err != 0) {
+			return err;
+		}
+		err = esdhc_wait_response(mmc, response);
+		if (err != 0) {
+			return err;
+		}
+		/* read 64 bytes of scr data */
+		err = esdhc_read_data(mmc, status, 64U);
+		if (err != 0) {
+			return ERROR_ESDHC_COMMUNICATION_ERROR;
+		}
+
+		if ((status[29] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
+			break;
+		}
+	}
+
+	if ((status[13] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
+		return 0;
+	}
+
+	/* SWITCH */
+	esdhc_set_data_attributes(mmc, NULL, 1, 64);
+	err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SD_SWITCH_FUNC_SWITCH_MODE);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	err = esdhc_read_data(mmc, status, 64U);
+	if (err != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	if ((status[16]) == U(0x01)) {
+		mmc->card.bus_freq = SD_HS_50MHZ;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    change_state_to_transfer_state
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Send CMD7 (CMD_SELECT_CARD) to toggles the card
+ *                     between stand-by and transfer state
+ *                  2. Send CMD13 (CMD_SEND_STATUS) to check state as
+ *                     Transfer State
+ ***************************************************************************/
+static int change_state_to_transfer_state(struct mmc *mmc)
+{
+	int error = 0;
+	uint32_t response[4];
+	uint64_t start_time;
+
+	/* Command CMD_SELECT_CARD/CMD7 toggles the card between stand-by
+	 * and transfer states
+	 */
+	error = esdhc_send_cmd(mmc, CMD_SELECT_CARD, mmc->card.rca << 16);
+	if (error != 0) {
+		return error;
+	}
+	error = esdhc_wait_response(mmc, response);
+	if (error != 0) {
+		return error;
+	}
+
+	start_time = get_timer_val(0);
+	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
+		/* send CMD13 to check card status */
+		error = esdhc_send_cmd(mmc,
+					CMD_SEND_STATUS, mmc->card.rca << 16);
+		if (error != 0) {
+			return error;
+		}
+		error = esdhc_wait_response(mmc, response);
+		if ((error != 0) || ((response[0] & R1_ERROR) != 0)) {
+			return error;
+		}
+
+		/* Check for the present state of card */
+		if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
+			break;
+		}
+	}
+	if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
+		return 0;
+	} else {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+}
+
+/***************************************************************************
+ * Function    :    get_cid_rca_csd
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Send CMD2 (CMD_ALL_SEND_CID)
+ *                  2. get RCA for SD cards, set rca for mmc cards
+ *                     Send CMD3 (CMD_SEND_RELATIVE_ADDR)
+ *                  3. Send CMD9 (CMD_SEND_CSD)
+ *                  4. Get MMC Version from CSD
+ ***************************************************************************/
+static int get_cid_rca_csd(struct mmc *mmc)
+{
+	int err;
+	uint32_t version;
+	uint32_t response[4];
+	uint32_t mmc_version[] = {MMC_CARD_VERSION_1_2, MMC_CARD_VERSION_1_4,
+		MMC_CARD_VERSION_2_X, MMC_CARD_VERSION_3_X,
+		MMC_CARD_VERSION_4_X};
+
+	err = esdhc_send_cmd(mmc, CMD_ALL_SEND_CID, 0);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	/* get RCA for SD cards, set rca for mmc cards */
+	mmc->card.rca = SD_MMC_CARD_RCA;
+
+	/* send RCA cmd */
+	err = esdhc_send_cmd(mmc, CMD_SEND_RELATIVE_ADDR, mmc->card.rca << 16);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	/* for SD, get the the RCA */
+	if (mmc->card.type == SD_CARD) {
+		mmc->card.rca = (response[0] >> 16) & 0xFFFF;
+	}
+
+	/* Get the CSD (card specific data) from card. */
+	err = esdhc_send_cmd(mmc, CMD_SEND_CSD, mmc->card.rca << 16);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, response);
+	if (err != 0) {
+		return err;
+	}
+
+	version = (response[3] >> 18U) & U(0xF);
+	if (mmc->card.type == MMC_CARD) {
+		if (version <= MMC_CARD_VERSION_4_X) {
+			mmc->card.version = mmc_version[version];
+		} else {
+			mmc->card.version = MMC_CARD_VERSION_4_X;
+		}
+	}
+
+	mmc->card.block_len = 1 << ((response[2] >> 8) & 0xF);
+
+	if (mmc->card.block_len > BLOCK_LEN_512) {
+		mmc->card.block_len = BLOCK_LEN_512;
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    identify_mmc_card
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Send Reset Command
+ *                  2. Send CMD1 with args to set voltage range and Sector
+ *                     Mode. (Voltage Args = 0xFF8)
+ *                  3. Check the OCR Response
+ ***************************************************************************/
+static int identify_mmc_card(struct mmc *mmc)
+{
+	uint64_t start_time;
+	uint32_t resp[4];
+	int ret;
+	uint32_t args;
+
+	/* card reset */
+	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = esdhc_wait_response(mmc, resp);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Send CMD1 to get the ocr value repeatedly till the card */
+	/* busy is clear. timeout = 20sec */
+
+	start_time = get_timer_val(0);
+	do {
+		/* set the bits for the voltage ranges supported by host */
+		args = mmc->voltages_caps | MMC_OCR_SECTOR_MODE;
+		ret = esdhc_send_cmd(mmc, CMD_MMC_SEND_OP_COND, args);
+		if (ret != 0) {
+			return ret;
+		}
+		ret = esdhc_wait_response(mmc, resp);
+		if (ret != 0) {
+			return ERROR_ESDHC_UNUSABLE_CARD;
+		}
+	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
+			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
+
+	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
+		return ERROR_ESDHC_UNUSABLE_CARD;
+	}
+
+	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
+		mmc->card.is_high_capacity = 1;
+	}
+
+	return MMC_CARD;
+}
+
+/***************************************************************************
+ * Function    :    check_for_sd_card
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    1. Send Reset Command
+ *                  2. Send CMD8 with pattern 0xAA (to check for SD 2.0)
+ *                  3. Send ACMD41 with args to set voltage range and HCS
+ *                     HCS is set only for SD Card > 2.0
+ *                     Voltage Caps = 0xFF8
+ *                  4. Check the OCR Response
+ ***************************************************************************/
+static int check_for_sd_card(struct mmc *mmc)
+{
+	uint64_t start_time;
+	uint32_t args;
+	int  ret;
+	uint32_t resp[4];
+
+	/* Send reset command */
+	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = esdhc_wait_response(mmc, resp);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* send CMD8 with  pattern 0xAA */
+	args = MMC_VDD_HIGH_VOLTAGE | 0xAA;
+	ret = esdhc_send_cmd(mmc, CMD_SEND_IF_COND, args);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = esdhc_wait_response(mmc, resp);
+	if (ret == RESP_TIMEOUT) { /* sd ver 1.x or not sd */
+		mmc->card.is_high_capacity = 0;
+	} else if ((resp[0] & U(0xFF)) == U(0xAA)) { /* ver 2.0 or later */
+		mmc->card.version = SD_CARD_VERSION_2_0;
+	} else {
+		return  NOT_SD_CARD;
+	}
+	/* Send Application command-55 to get the ocr value repeatedly till
+	 * the card busy is clear. timeout = 20sec
+	 */
+
+	start_time = get_timer_val(0);
+	do {
+		ret = esdhc_send_cmd(mmc, CMD_APP_CMD, 0U);
+		if (ret != 0) {
+			return ret;
+		}
+		ret = esdhc_wait_response(mmc, resp);
+		if (ret == COMMAND_ERROR) {
+			return ERROR_ESDHC_UNUSABLE_CARD;
+		}
+
+		/* set the bits for the voltage ranges supported by host */
+		args = mmc->voltages_caps;
+		if (mmc->card.version == SD_CARD_VERSION_2_0) {
+			args |= SD_OCR_HCS;
+		}
+
+		/* Send ACMD41 to set voltage range */
+		ret = esdhc_send_cmd(mmc, CMD_SD_SEND_OP_COND, args);
+		if (ret != 0) {
+			return ret;
+		}
+		ret = esdhc_wait_response(mmc, resp);
+		if (ret == COMMAND_ERROR) {
+			return ERROR_ESDHC_UNUSABLE_CARD;
+		} else if (ret == RESP_TIMEOUT) {
+			return NOT_SD_CARD;
+		}
+	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
+			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
+
+	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
+		INFO("SD_TIMEOUT_HIGH\n");
+		return ERROR_ESDHC_UNUSABLE_CARD;
+	}
+
+	/* bit set in card capacity status */
+	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
+		mmc->card.is_high_capacity = 1;
+	}
+
+	return SD_CARD;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_emmc_init
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  src_emmc - Flag to Indicate SRC as emmc
+ * Return      :    SUCCESS or Error Code (< 0)
+ * Description :    Base Function called from sd_mmc_init or emmc_init
+ ***************************************************************************/
+int esdhc_emmc_init(struct mmc *mmc, bool card_detect)
+{
+	int error = 0;
+	int ret = 0;
+
+	error = esdhc_init(mmc, card_detect);
+	if (error != 0) {
+		return error;
+	}
+
+	mmc->card.bus_freq = CARD_IDENTIFICATION_FREQ;
+	mmc->card.rca = 0;
+	mmc->card.is_high_capacity = 0;
+	mmc->card.type = ERROR_ESDHC_UNUSABLE_CARD;
+
+	/* Set Voltage caps as FF8 i.e all supported */
+	/* high voltage bits 2.7 - 3.6 */
+	mmc->voltages_caps = MMC_OCR_VDD_FF8;
+
+#ifdef NXP_SD_DMA_CAPABILITY
+	/* Getting host DMA capabilities. */
+	mmc->dma_support = esdhc_in32(&mmc->esdhc_regs->hostcapblt) &
+					ESDHC_HOSTCAPBLT_DMAS;
+#else
+	mmc->dma_support = 0;
+#endif
+
+	ret = NOT_SD_CARD;
+	/* If SRC is not EMMC, check for SD or MMC */
+	ret = check_for_sd_card(mmc);
+	switch (ret) {
+	case SD_CARD:
+		mmc->card.type = SD_CARD;
+		break;
+
+	case NOT_SD_CARD:
+		/* try for MMC card */
+		if (identify_mmc_card(mmc) == MMC_CARD) {
+			mmc->card.type = MMC_CARD;
+		} else {
+			return ERROR_ESDHC_UNUSABLE_CARD;
+		}
+		break;
+
+	default:
+		return ERROR_ESDHC_UNUSABLE_CARD;
+	}
+
+	/* get CID, RCA and CSD. For MMC, set the rca */
+	error = get_cid_rca_csd(mmc);
+	if (error != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	/* change state to Transfer mode */
+	error = change_state_to_transfer_state(mmc);
+	if (error != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	/* change to high frequency if supported */
+	if (mmc->card.type == SD_CARD) {
+		error = sd_switch_to_high_freq(mmc);
+	} else {
+		error = mmc_switch_to_high_frquency(mmc);
+	}
+	if (error != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	/* mmc: 20000000, 26000000, 52000000 */
+	/* sd: 25000000, 50000000 */
+	set_speed(mmc, mmc->card.bus_freq);
+
+	INFO("init done:\n");
+	return 0;
+}
+
+/***************************************************************************
+ * Function    :    sd_mmc_init
+ * Arguments   :    mmc - Pointer to mmc struct
+ * Return      :    SUCCESS or Error Code
+ * Description :    Base Function called via hal_init for SD/MMC
+ *                  initialization
+ ***************************************************************************/
+int sd_mmc_init(uintptr_t nxp_esdhc_addr, bool card_detect)
+{
+	struct mmc *mmc = NULL;
+	int ret;
+
+	mmc = &mmc_drv_data;
+	memset(mmc, 0, sizeof(struct mmc));
+	mmc->esdhc_regs = (struct esdhc_regs *)nxp_esdhc_addr;
+
+	INFO("esdhc_emmc_init\n");
+	ret = esdhc_emmc_init(mmc, card_detect);
+	return ret;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_read_block
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  dst - Destination Pointer
+ *                  block - Block Number
+ * Return      :    SUCCESS or Error Code
+ * Description :    Read a Single block to Destination Pointer
+ *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
+ *                  2. Send CMD17 (CMD_READ_SINGLE_BLOCK) with args offset
+ ***************************************************************************/
+static int esdhc_read_block(struct mmc *mmc, void *dst, uint32_t block)
+{
+	uint32_t offset;
+	int err;
+
+	/* send cmd16 to set the block size. */
+	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, NULL);
+	if (err != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	if (mmc->card.is_high_capacity != 0) {
+		offset = block;
+	} else {
+		offset = block * mmc->card.block_len;
+	}
+
+	esdhc_set_data_attributes(mmc, dst, 1, mmc->card.block_len);
+	err = esdhc_send_cmd(mmc, CMD_READ_SINGLE_BLOCK, offset);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, NULL);
+	if (err != 0) {
+		return err;
+	}
+
+	err = esdhc_read_data(mmc, dst, mmc->card.block_len);
+
+	return err;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_write_block
+ * Arguments   :    mmc - Pointer to mmc struct
+ *                  src - Source Pointer
+ *                  block - Block Number
+ * Return      :    SUCCESS or Error Code
+ * Description :    Write a Single block from Source Pointer
+ *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
+ *                  2. Send CMD24 (CMD_WRITE_SINGLE_BLOCK) with args offset
+ ***************************************************************************/
+static int esdhc_write_block(struct mmc *mmc, void *src, uint32_t block)
+{
+	uint32_t offset;
+	int err;
+
+	/* send cmd16 to set the block size. */
+	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, NULL);
+	if (err != 0) {
+		return ERROR_ESDHC_COMMUNICATION_ERROR;
+	}
+
+	if (mmc->card.is_high_capacity != 0) {
+		offset = block;
+	} else {
+		offset = block * mmc->card.block_len;
+	}
+
+	esdhc_set_data_attributes(mmc, src, 1, mmc->card.block_len);
+	err = esdhc_send_cmd(mmc, CMD_WRITE_SINGLE_BLOCK, offset);
+	if (err != 0) {
+		return err;
+	}
+	err = esdhc_wait_response(mmc, NULL);
+	if (err != 0) {
+		return err;
+	}
+
+	err = esdhc_write_data(mmc, src, mmc->card.block_len);
+
+	return err;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_read
+ * Arguments   :    src_offset - offset on sd/mmc to read from. Should be block
+ *		    size aligned
+ *                  dst - Destination Pointer
+ *                  size - Length of Data ( Multiple of block size)
+ * Return      :    SUCCESS or Error Code
+ * Description :    Calls esdhc_read_block repeatedly for reading the
+ *                  data.
+ ***************************************************************************/
+int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst, size_t size)
+{
+	int error = 0;
+	uint32_t blk, num_blocks;
+	uint8_t *buff = (uint8_t *)dst;
+
+#ifdef NXP_SD_DEBUG
+	INFO("sd mmc read\n");
+	INFO("src = %x, dst = %lxsize = %lu\n", src_offset, dst, size);
+#endif
+
+	/* check for size */
+	if (size == 0) {
+		return 0;
+	}
+
+	if ((size % mmc->card.block_len) != 0) {
+		ERROR("Size is not block aligned\n");
+		return -1;
+	}
+
+	if ((src_offset % mmc->card.block_len) != 0) {
+		ERROR("Size is not block aligned\n");
+		return -1;
+	}
+
+	/* start block */
+	blk = src_offset / mmc->card.block_len;
+#ifdef NXP_SD_DEBUG
+	INFO("blk = %x\n", blk);
+#endif
+
+	/* Number of blocks to be read */
+	num_blocks = size / mmc->card.block_len;
+
+	while (num_blocks) {
+		error = esdhc_read_block(mmc, buff, blk);
+		if (error != 0) {
+			ERROR("Read error = %x\n", error);
+			return error;
+		}
+
+		buff = buff + mmc->card.block_len;
+		blk++;
+		num_blocks--;
+	}
+
+	INFO("sd-mmc read done.\n");
+	return error;
+}
+
+/***************************************************************************
+ * Function    :    esdhc_write
+ * Arguments   :    src - Source Pointer
+ *                  dst_offset - offset on sd/mmc to write to. Should be block
+ *		    size aligned
+ *                  size - Length of Data (Multiple of block size)
+ * Return      :    SUCCESS or Error Code
+ * Description :    Calls esdhc_write_block repeatedly for writing the
+ *                  data.
+ ***************************************************************************/
+int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
+		size_t size)
+{
+	int error = 0;
+	uint32_t blk, num_blocks;
+	uint8_t *buff = (uint8_t *)src;
+
+#ifdef NXP_SD_DEBUG
+	INFO("sd mmc write\n");
+	INFO("src = %x, dst = %lxsize = %lu\n", src, dst_offset, size);
+#endif
+
+	/* check for size */
+	if (size == 0) {
+		return 0;
+	}
+
+	if ((size % mmc->card.block_len) != 0) {
+		ERROR("Size is not block aligned\n");
+		return -1;
+	}
+
+	if ((dst_offset % mmc->card.block_len) != 0) {
+		ERROR("Size is not block aligned\n");
+		return -1;
+	}
+
+	/* start block */
+	blk = dst_offset / mmc->card.block_len;
+#ifdef NXP_SD_DEBUG
+	INFO("blk = %x\n", blk);
+#endif
+
+	/* Number of blocks to be written */
+	num_blocks = size / mmc->card.block_len;
+
+	while (num_blocks != 0U) {
+		error = esdhc_write_block(mmc, buff, blk);
+		if (error != 0U) {
+			ERROR("Write error = %x\n", error);
+			return error;
+		}
+
+		buff = buff + mmc->card.block_len;
+		blk++;
+		num_blocks--;
+	}
+
+	INFO("sd-mmc write done.\n");
+	return error;
+}
+
+static size_t ls_sd_emmc_read(int lba, uintptr_t buf, size_t size)
+{
+	struct mmc *mmc = NULL;
+	int ret;
+
+	mmc = &mmc_drv_data;
+	lba *= BLOCK_LEN_512;
+	ret = esdhc_read(mmc, lba, buf, size);
+	return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec ls_emmc_dev_spec = {
+	.buffer = {
+		.offset = 0,
+		.length = 0,
+	},
+	.ops = {
+		.read = ls_sd_emmc_read,
+	},
+	.block_size = BLOCK_LEN_512,
+};
+
+int sd_emmc_init(uintptr_t *block_dev_spec,
+			uintptr_t nxp_esdhc_addr,
+			size_t nxp_sd_block_offset,
+			size_t nxp_sd_block_size,
+			bool card_detect)
+{
+	int ret;
+
+	ret = sd_mmc_init(nxp_esdhc_addr, card_detect);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ls_emmc_dev_spec.buffer.offset = nxp_sd_block_offset;
+	ls_emmc_dev_spec.buffer.length = nxp_sd_block_size;
+	*block_dev_spec = (uintptr_t)&ls_emmc_dev_spec;
+
+	return 0;
+}
diff --git a/drivers/nxp/sd/sd_mmc.h b/drivers/nxp/sd/sd_mmc.h
new file mode 100644
index 0000000..29ad328
--- /dev/null
+++ b/drivers/nxp/sd/sd_mmc.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2015, 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef SD_MMC_H
+#define SD_MMC_H
+
+#include <lib/mmio.h>
+
+/* operating freq */
+#define CARD_IDENTIFICATION_FREQ	400000
+#define SD_SS_25MHZ	20000000
+#define SD_HS_50MHZ	40000000
+#define MMC_SS_20MHZ	15000000
+#define MMC_HS_26MHZ	20000000
+#define MMC_HS_52MHZ	40000000
+
+/* Need to check this value ? */
+#define MAX_PLATFORM_CLOCK	800000000
+
+/* eSDHC system control register defines */
+#define ESDHC_SYSCTL_DTOCV(t)		(((t) & 0xF) << 16)
+#define ESDHC_SYSCTL_SDCLKFS(f)		(((f) & 0xFF) << 8)
+#define ESDHC_SYSCTL_DVS(d)		(((d) & 0xF) << 4)
+#define ESDHC_SYSCTL_SDCLKEN		(0x00000008)
+#define ESDHC_SYSCTL_RSTA		(0x01000000)
+
+/* Data timeout counter value. SDHC_CLK x 227 */
+#define TIMEOUT_COUNTER_SDCLK_2_27	0xE
+#define ESDHC_SYSCTL_INITA	0x08000000
+
+/* eSDHC interrupt status enable register defines */
+#define ESDHC_IRQSTATEN_CINS	0x00000040
+#define ESDHC_IRQSTATEN_BWR	0x00000010
+
+/* eSDHC interrupt status register defines */
+#define ESDHC_IRQSTAT_DMAE	(0x10000000)
+#define ESDHC_IRQSTAT_AC12E	(0x01000000)
+#define ESDHC_IRQSTAT_DEBE	(0x00400000)
+#define ESDHC_IRQSTAT_DCE	(0x00200000)
+#define ESDHC_IRQSTAT_DTOE	(0x00100000)
+#define ESDHC_IRQSTAT_CIE	(0x00080000)
+#define ESDHC_IRQSTAT_CEBE	(0x00040000)
+#define ESDHC_IRQSTAT_CCE	(0x00020000)
+#define ESDHC_IRQSTAT_CTOE	(0x00010000)
+#define ESDHC_IRQSTAT_CINT	(0x00000100)
+#define ESDHC_IRQSTAT_CRM	(0x00000080)
+#define ESDHC_IRQSTAT_CINS	(0x00000040)
+#define ESDHC_IRQSTAT_BRR	(0x00000020)
+#define ESDHC_IRQSTAT_BWR	(0x00000010)
+#define ESDHC_IRQSTAT_DINT	(0x00000008)
+#define ESDHC_IRQSTAT_BGE	(0x00000004)
+#define ESDHC_IRQSTAT_TC	(0x00000002)
+#define ESDHC_IRQSTAT_CC	(0x00000001)
+#define ESDHC_IRQSTAT_CMD_ERR	(ESDHC_IRQSTAT_CIE |\
+			ESDHC_IRQSTAT_CEBE |\
+			ESDHC_IRQSTAT_CCE)
+#define ESDHC_IRQSTAT_DATA_ERR	(ESDHC_IRQSTAT_DEBE |\
+			ESDHC_IRQSTAT_DCE |\
+			ESDHC_IRQSTAT_DTOE)
+#define ESDHC_IRQSTAT_CLEAR_ALL	(0xFFFFFFFF)
+
+/* eSDHC present state register defines */
+#define ESDHC_PRSSTAT_CLSL	0x00800000
+#define ESDHC_PRSSTAT_WPSPL	0x00080000
+#define ESDHC_PRSSTAT_CDPL	0x00040000
+#define ESDHC_PRSSTAT_CINS	0x00010000
+#define ESDHC_PRSSTAT_BREN	0x00000800
+#define ESDHC_PRSSTAT_BWEN	0x00000400
+#define ESDHC_PRSSTAT_RTA	0x00000200
+#define ESDHC_PRSSTAT_WTA	0x00000100
+#define ESDHC_PRSSTAT_SDOFF	0x00000080
+#define ESDHC_PRSSTAT_PEROFF	0x00000040
+#define ESDHC_PRSSTAT_HCKOFF	0x00000020
+#define ESDHC_PRSSTAT_IPGOFF	0x00000010
+#define ESDHC_PRSSTAT_DLA	0x00000004
+#define ESDHC_PRSSTAT_CDIHB	0x00000002
+#define ESDHC_PRSSTAT_CIHB	0x00000001
+
+/* eSDHC protocol control register defines */
+#define ESDHC_PROCTL_EMODE_LE	0x00000020
+#define ESDHC_PROCTL_DTW_1BIT	0x00000000
+#define ESDHC_PROCTL_DTW_4BIT	0x00000002
+#define ESDHC_PROCTL_DTW_8BIT	0x00000004
+
+/* Watermark Level Register (WML) */
+#define ESDHC_WML_RD_WML(w)	((w) & 0x7F)
+#define ESDHC_WML_WR_WML(w)	(((w) & 0x7F) << 16)
+#define ESDHC_WML_RD_BRST(w)	(((w) & 0xF) << 8)
+#define ESDHC_WML_WR_BRST(w)	(((w) & 0xF) << 24)
+#define ESDHC_WML_WR_BRST_MASK	(0x0F000000)
+#define ESDHC_WML_RD_BRST_MASK	(0x00000F00)
+#define ESDHC_WML_RD_WML_MASK	(0x0000007F)
+#define ESDHC_WML_WR_WML_MASK	(0x007F0000)
+#define WML_512_BYTES		(0x0)
+#define BURST_128_BYTES	(0x0)
+
+/* eSDHC control register define */
+#define ESDHC_DCR_SNOOP		0x00000040
+
+/* ESDHC Block attributes register */
+#define ESDHC_BLKATTR_BLKCNT(c)	(((c) & 0xffff) << 16)
+#define ESDHC_BLKATTR_BLKSZE(s)	((s) & 0xfff)
+
+/* Transfer Type Register */
+#define ESDHC_XFERTYP_CMD(c)	(((c) & 0x3F) << 24)
+#define ESDHC_XFERTYP_CMDTYP_NORMAL	(0x0)
+#define ESDHC_XFERTYP_CMDTYP_SUSPEND	(0x00400000)
+#define ESDHC_XFERTYP_CMDTYP_RESUME	(0x00800000)
+#define ESDHC_XFERTYP_CMDTYP_ABORT	(0x00C00000)
+#define ESDHC_XFERTYP_DPSEL	(0x00200000)
+#define ESDHC_XFERTYP_CICEN	(0x00100000)
+#define ESDHC_XFERTYP_CCCEN	(0x00080000)
+#define ESDHC_XFERTYP_RSPTYP_NONE	(0x0)
+#define ESDHC_XFERTYP_RSPTYP_136	(0x00010000)
+#define ESDHC_XFERTYP_RSPTYP_48	(0x00020000)
+#define ESDHC_XFERTYP_RSPTYP_48_BUSY	(0x00030000)
+#define ESDHC_XFERTYP_MSBSEL	(0x00000020)
+#define ESDHC_XFERTYP_DTDSEL	(0x00000010)
+#define ESDHC_XFERTYP_AC12EN	(0x00000004)
+#define ESDHC_XFERTYP_BCEN	(0x00000002)
+#define ESDHC_XFERTYP_DMAEN	(0x00000001)
+
+#define MMC_VDD_HIGH_VOLTAGE	0x00000100
+
+/* command index */
+#define CMD0	0
+#define CMD1	1
+#define CMD2	2
+#define CMD3	3
+#define CMD5	5
+#define CMD6	6
+#define CMD7	7
+#define CMD8	8
+#define CMD9	9
+#define CMD12	12
+#define CMD13	13
+#define CMD14	14
+#define CMD16	16
+#define CMD17	17
+#define CMD18	18
+#define CMD19	19
+#define CMD24	24
+#define CMD41	41
+#define CMD42	42
+#define CMD51	51
+#define CMD55	55
+#define CMD56	56
+#define ACMD6	CMD6
+#define ACMD13	CMD13
+#define ACMD41	CMD41
+#define ACMD42	CMD42
+#define ACMD51	CMD51
+
+/* commands abbreviations */
+#define CMD_GO_IDLE_STATE	CMD0
+#define CMD_MMC_SEND_OP_COND	CMD1
+#define CMD_ALL_SEND_CID	CMD2
+#define CMD_SEND_RELATIVE_ADDR	CMD3
+#define CMD_SET_DSR	CMD4
+#define CMD_SWITCH_FUNC	CMD6
+#define CMD_SELECT_CARD	CMD7
+#define CMD_DESELECT_CARD	CMD7
+#define CMD_SEND_IF_COND	CMD8
+#define CMD_MMC_SEND_EXT_CSD	CMD8
+#define CMD_SEND_CSD	CMD9
+#define CMD_SEND_CID	CMD10
+#define CMD_STOP_TRANSMISSION	CMD12
+#define CMD_SEND_STATUS	CMD13
+#define CMD_BUS_TEST_R	CMD14
+#define CMD_GO_INACTIVE_STATE	CMD15
+#define CMD_SET_BLOCKLEN	CMD16
+#define CMD_READ_SINGLE_BLOCK	CMD17
+#define CMD_READ_MULTIPLE_BLOCK	CMD18
+#define CMD_WRITE_SINGLE_BLOCK	CMD24
+#define CMD_BUS_TEST_W	CMD19
+#define CMD_APP_CMD	CMD55
+#define CMD_GEN_CMD	CMD56
+#define CMD_SET_BUS_WIDTH	ACMD6
+#define CMD_SD_STATUS	ACMD13
+#define CMD_SD_SEND_OP_COND	ACMD41
+#define CMD_SET_CLR_CARD_DETECT	ACMD42
+#define CMD_SEND_SCR	ACMD51
+
+/* MMC card spec version */
+#define MMC_CARD_VERSION_1_2	0
+#define MMC_CARD_VERSION_1_4	1
+#define MMC_CARD_VERSION_2_X	2
+#define MMC_CARD_VERSION_3_X	3
+#define MMC_CARD_VERSION_4_X	4
+
+/* SD Card Spec Version */
+/* May need to add version 3 here? */
+#define SD_CARD_VERSION_1_0	0
+#define SD_CARD_VERSION_1_10	1
+#define SD_CARD_VERSION_2_0	2
+
+/* card types */
+#define MMC_CARD	0
+#define SD_CARD		1
+#define NOT_SD_CARD	MMC_CARD
+
+/* Card rca */
+#define SD_MMC_CARD_RCA	0x1
+#define BLOCK_LEN_512	512
+
+/* card state */
+#define STATE_IDLE	0
+#define STATE_READY	1
+#define STATE_IDENT	2
+#define STATE_STBY	3
+#define STATE_TRAN	4
+#define STATE_DATA	5
+#define STATE_RCV	6
+#define STATE_PRG	7
+#define STATE_DIS	8
+
+/* Card OCR register */
+/* VDD voltage window 1,65 to 1.95 */
+#define MMC_OCR_VDD_165_195	0x00000080
+/* VDD voltage window 2.7-2.8 */
+#define MMC_OCR_VDD_FF8	0x00FF8000
+#define MMC_OCR_CCS	0x40000000/* Card Capacity */
+#define MMC_OCR_BUSY	0x80000000/* busy bit */
+#define SD_OCR_HCS	0x40000000/* High capacity host */
+#define MMC_OCR_SECTOR_MODE	0x40000000/* Access Mode as Sector */
+
+/* mmc Switch function */
+#define SET_EXT_CSD_HS_TIMING	0x03B90100/* set High speed */
+
+/* check supports switching or not */
+#define SD_SWITCH_FUNC_CHECK_MODE	0x00FFFFF1
+#define SD_SWITCH_FUNC_SWITCH_MODE	0x80FFFFF1/* switch */
+#define SD_SWITCH_FUNC_HIGH_SPEED	0x02/* HIGH SPEED FUNC */
+#define SWITCH_ERROR		0x00000080
+
+/* errors in sending commands */
+#define RESP_TIMEOUT	0x1
+#define COMMAND_ERROR	0x2
+/* error in response */
+#define R1_ERROR	(1 << 19)
+#define R1_CURRENT_STATE(x)	(((x) & 0x00001E00) >> 9)
+
+/* Host Controller Capabilities */
+#define ESDHC_HOSTCAPBLT_DMAS           (0x00400000)
+
+
+/* SD/MMC memory map */
+struct esdhc_regs {
+	uint32_t dsaddr;	/* dma system address */
+	uint32_t blkattr;	/* Block attributes */
+	uint32_t cmdarg;	/* Command argument */
+	uint32_t xfertyp;	/* Command transfer type */
+	uint32_t cmdrsp[4];	/* Command response0,1,2,3 */
+	uint32_t datport;	/* Data buffer access port */
+	uint32_t prsstat;	/* Present state */
+	uint32_t proctl;	/* Protocol control */
+	uint32_t sysctl;	/* System control */
+	uint32_t irqstat;	/* Interrupt status */
+	uint32_t irqstaten;	/* Interrupt status enable */
+	uint32_t irqsigen;	/* Interrupt signal enable */
+	uint32_t autoc12err;	/* Auto CMD12 status */
+	uint32_t hostcapblt;	/* Host controller capabilities */
+	uint32_t wml;	/* Watermark level */
+	uint32_t res1[2];
+	uint32_t fevt;	/* Force event */
+	uint32_t res2;
+	uint32_t adsaddrl;
+	uint32_t adsaddrh;
+	uint32_t res3[39];
+	uint32_t hostver;	/* Host controller version */
+	uint32_t res4;
+	uint32_t dmaerr;	/* DMA error address */
+	uint32_t dmaerrh;	/* DMA error address high */
+	uint32_t dmaerrattr; /* DMA error atrribute */
+	uint32_t res5;
+	uint32_t hostcapblt2;/* Host controller capabilities2 */
+	uint32_t res6[2];
+	uint32_t tcr;	/* Tuning control */
+	uint32_t res7[7];
+	uint32_t dirctrl;	/* Direction control */
+	uint32_t ccr;	/* Clock control */
+	uint32_t res8[177];
+	uint32_t ctl;	/* Control register */
+};
+
+/* SD/MMC card attributes */
+struct card_attributes {
+	uint32_t type;	/* sd or mmc card */
+	uint32_t version;	/* version */
+	uint32_t block_len;	/* block length */
+	uint32_t bus_freq;	/* sdhc bus frequency */
+	uint16_t rca;	/* relative card address */
+	uint8_t is_high_capacity;	/* high capacity */
+};
+
+struct mmc {
+	struct esdhc_regs *esdhc_regs;
+	struct card_attributes card;
+
+	uint32_t block_len;
+	uint32_t voltages_caps;	/* supported voltaes */
+	uint32_t dma_support;	/* DMA support */
+};
+
+enum cntrl_num {
+	SDHC1 = 0,
+	SDHC2
+};
+
+int sd_emmc_init(uintptr_t *block_dev_spec,
+			uintptr_t nxp_esdhc_addr,
+			size_t nxp_sd_block_offset,
+			size_t nxp_sd_block_size,
+			bool card_detect);
+
+int esdhc_emmc_init(struct mmc *mmc, bool card_detect);
+int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst,
+	       size_t size);
+int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
+		size_t size);
+
+#ifdef NXP_ESDHC_BE
+#define esdhc_in32(a)           bswap32(mmio_read_32((uintptr_t)(a)))
+#define esdhc_out32(a, v)       mmio_write_32((uintptr_t)(a), bswap32(v))
+#elif defined(NXP_ESDHC_LE)
+#define esdhc_in32(a)           mmio_read_32((uintptr_t)(a))
+#define esdhc_out32(a, v)       mmio_write_32((uintptr_t)(a), (v))
+#else
+#error Please define CCSR ESDHC register endianness
+#endif
+
+#endif /*SD_MMC_H*/
diff --git a/drivers/nxp/sd/sd_mmc.mk b/drivers/nxp/sd/sd_mmc.mk
new file mode 100644
index 0000000..af91b1f
--- /dev/null
+++ b/drivers/nxp/sd/sd_mmc.mk
@@ -0,0 +1,28 @@
+#
+# Copyright 2020 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ADD_SD_MMC},)
+
+ADD_SD_MMC	:= 1
+
+SD_DRIVERS_PATH		:=  ${PLAT_DRIVERS_PATH}/sd
+
+SD_MMC_BOOT_SOURCES	+= ${SD_DRIVERS_PATH}/sd_mmc.c \
+			   drivers/io/io_block.c
+
+PLAT_INCLUDES		+= -I$(SD_DRIVERS_PATH)
+
+ifeq (${BL_COMM_SD_MMC_NEEDED},yes)
+BL_COMMON_SOURCES	+= ${SD_MMC_BOOT_SOURCES}
+else
+ifeq (${BL2_SD_MMC_NEEDED},yes)
+BL2_SOURCES		+= ${SD_MMC_BOOT_SOURCES}
+endif
+ifeq (${BL3_SD_MMC_NEEDED},yes)
+BL31_SOURCES		+= ${SD_MMC_BOOT_SOURCES}
+endif
+endif
+endif