summaryrefslogtreecommitdiffstats
path: root/drivers/mci/imx-esdhc-pbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mci/imx-esdhc-pbl.c')
-rw-r--r--drivers/mci/imx-esdhc-pbl.c625
1 files changed, 250 insertions, 375 deletions
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index f93ddfa0d5..5b1d9a3cf4 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -1,13 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; version 2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "xload-esdhc: " fmt
@@ -15,14 +6,22 @@
#include <io.h>
#include <mci.h>
#include <linux/sizes.h>
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
#include <asm/cache.h>
-#include <mach/xload.h>
+#include <mach/imx/xload.h>
+#include <firmware.h>
+#include <asm/atf_common.h>
#ifdef CONFIG_ARCH_IMX
-#include <mach/atf.h>
-#include <mach/imx6-regs.h>
-#include <mach/imx8mq-regs.h>
-#include <mach/imx-header.h>
+#include <mach/imx/atf.h>
+#include <mach/imx/imx6-regs.h>
+#include <mach/imx/imx7-regs.h>
+#include <mach/imx/imx8mq-regs.h>
+#include <mach/imx/imx8mm-regs.h>
+#include <mach/imx/imx-header.h>
+#endif
+#ifdef CONFIG_ARCH_LAYERSCAPE
+#include <mach/layerscape/xload.h>
+#include <mach/layerscape/layerscape.h>
#endif
#include "sdhci.h"
#include "imx-esdhc.h"
@@ -30,206 +29,58 @@
#define SECTOR_SIZE 512
#define SECTOR_WML (SECTOR_SIZE / sizeof(u32))
-struct esdhc {
- void __iomem *regs;
- bool is_mx6;
- bool is_be;
- bool wrap_wml;
-};
+#define esdhc_send_cmd __esdhc_send_cmd
-static uint32_t esdhc_read32(struct esdhc *esdhc, int reg)
-{
- if (esdhc->is_be)
- return in_be32(esdhc->regs + reg);
- else
- return readl(esdhc->regs + reg);
-}
+static u8 ext_csd[512] __aligned(64);
-static void esdhc_write32(struct esdhc *esdhc, int reg, uint32_t val)
+static int esdhc_send_ext_csd(struct fsl_esdhc_host *host)
{
- if (esdhc->is_be)
- out_be32(esdhc->regs + reg, val);
- else
- writel(val, esdhc->regs + reg);
-}
+ struct mci_cmd cmd;
+ struct mci_data data;
-static void __udelay(int us)
-{
- volatile int i;
+ cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
- for (i = 0; i < us * 4; i++);
-}
+ data.dest = ext_csd;
+ data.blocks = 1;
+ data.blocksize = sizeof(ext_csd);
+ data.flags = MMC_DATA_READ;
-static u32 esdhc_xfertyp(struct mci_cmd *cmd, struct mci_data *data)
-{
- u32 xfertyp = 0;
-
- if (data)
- xfertyp |= COMMAND_DPSEL | TRANSFER_MODE_MSBSEL |
- TRANSFER_MODE_BCEN |TRANSFER_MODE_DTDSEL;
-
- if (cmd->resp_type & MMC_RSP_CRC)
- xfertyp |= COMMAND_CCCEN;
- if (cmd->resp_type & MMC_RSP_OPCODE)
- xfertyp |= COMMAND_CICEN;
- if (cmd->resp_type & MMC_RSP_136)
- xfertyp |= COMMAND_RSPTYP_136;
- else if (cmd->resp_type & MMC_RSP_BUSY)
- xfertyp |= COMMAND_RSPTYP_48_BUSY;
- else if (cmd->resp_type & MMC_RSP_PRESENT)
- xfertyp |= COMMAND_RSPTYP_48;
-
- return COMMAND_CMD(cmd->cmdidx) | xfertyp;
+ return esdhc_send_cmd(host, &cmd, &data);
}
-static int esdhc_do_data(struct esdhc *esdhc, struct mci_data *data)
+static bool __maybe_unused esdhc_bootpart_active(struct fsl_esdhc_host *host)
{
- char *buffer;
- u32 databuf;
- u32 size;
- u32 irqstat;
- u32 present;
-
- buffer = data->dest;
-
- size = data->blocksize * data->blocks;
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
-
- while (size) {
- int i;
- int timeout = 1000000;
-
- while (1) {
- present = esdhc_read32(esdhc, SDHCI_PRESENT_STATE) & PRSSTAT_BREN;
- if (present)
- break;
- if (!--timeout) {
- pr_err("read time out\n");
- return -ETIMEDOUT;
- }
- }
-
- for (i = 0; i < SECTOR_WML; i++) {
- databuf = esdhc_read32(esdhc, SDHCI_BUFFER);
- *((u32 *)buffer) = databuf;
- buffer += 4;
- size -= 4;
- }
- }
+ unsigned bootpart;
- return 0;
-}
-
-static int
-esdhc_send_cmd(struct esdhc *esdhc, struct mci_cmd *cmd, struct mci_data *data)
-{
- u32 xfertyp, mixctrl;
- u32 irqstat;
- int ret;
- int timeout;
-
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
-
- /* Wait at least 8 SD clock cycles before the next command */
- __udelay(1);
-
- if (data) {
- unsigned long dest = (unsigned long)data->dest;
-
- if (dest > 0xffffffff)
- return -EINVAL;
-
- /* Set up for a data transfer if we have one */
- esdhc_write32(esdhc, SDHCI_DMA_ADDRESS, (u32)dest);
- esdhc_write32(esdhc, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | SECTOR_SIZE);
- }
-
- /* Figure out the transfer arguments */
- xfertyp = esdhc_xfertyp(cmd, data);
-
- /* Send the command */
- esdhc_write32(esdhc, SDHCI_ARGUMENT, cmd->cmdarg);
-
- if (esdhc->is_mx6) {
- /* write lower-half of xfertyp to mixctrl */
- mixctrl = xfertyp & 0xFFFF;
- /* Keep the bits 22-25 of the register as is */
- mixctrl |= (esdhc_read32(esdhc, IMX_SDHCI_MIXCTRL) & (0xF << 22));
- esdhc_write32(esdhc, IMX_SDHCI_MIXCTRL, mixctrl);
- }
-
- esdhc_write32(esdhc, SDHCI_TRANSFER_MODE__COMMAND, xfertyp);
-
- /* Wait for the command to complete */
- timeout = 10000;
- while (!(esdhc_read32(esdhc, SDHCI_INT_STATUS) & IRQSTAT_CC)) {
- __udelay(1);
- if (!timeout--)
- return -ETIMEDOUT;
- }
-
- irqstat = esdhc_read32(esdhc, SDHCI_INT_STATUS);
- esdhc_write32(esdhc, SDHCI_INT_STATUS, irqstat);
-
- if (irqstat & CMD_ERR)
- return -EIO;
-
- if (irqstat & IRQSTAT_CTOE)
- return -ETIMEDOUT;
-
- /* Copy the response to the response buffer */
- cmd->response[0] = esdhc_read32(esdhc, SDHCI_RESPONSE_0);
-
- /* Wait until all of the blocks are transferred */
- if (data) {
- ret = esdhc_do_data(esdhc, data);
- if (ret)
- return ret;
- }
-
- esdhc_write32(esdhc, SDHCI_INT_STATUS, -1);
+ int ret = esdhc_send_ext_csd(host);
+ if (ret)
+ return false;
- /* Wait for the bus to be idle */
- timeout = 10000;
- while (esdhc_read32(esdhc, SDHCI_PRESENT_STATE) &
- (PRSSTAT_CICHB | PRSSTAT_CIDHB | PRSSTAT_DLA)) {
- __udelay(1);
- if (!timeout--)
- return -ETIMEDOUT;
- }
+ bootpart = (ext_csd[EXT_CSD_PARTITION_CONFIG] >> 3) & 0x7;
+ if (bootpart == 1 || bootpart == 2)
+ return true;
- return 0;
+ return false;
}
-static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
+static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len)
{
struct mci_cmd cmd;
struct mci_data data;
- u32 val, wml;
+ u32 val;
int ret;
- esdhc_write32(esdhc, SDHCI_INT_ENABLE,
- IRQSTATEN_CC | IRQSTATEN_TC | IRQSTATEN_CINT | IRQSTATEN_CTOE |
- IRQSTATEN_CCE | IRQSTATEN_CEBE | IRQSTATEN_CIE |
- IRQSTATEN_DTOE | IRQSTATEN_DCE | IRQSTATEN_DEBE |
- IRQSTATEN_DINT);
-
- wml = FIELD_PREP(WML_WR_BRST_LEN, 16) |
- FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) |
- FIELD_PREP(WML_RD_BRST_LEN, 16) |
- FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML);
- /*
- * Some SoCs intrpret 0 as MAX value so for those cases the
- * above value translates to zero
- */
- if (esdhc->wrap_wml)
- wml = 0;
-
- esdhc_write32(esdhc, IMX_SDHCI_WML, wml);
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+ SDHCI_INT_CMD_COMPLETE | SDHCI_INT_XFER_COMPLETE |
+ SDHCI_INT_CARD_INT | SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
+ SDHCI_INT_END_BIT | SDHCI_INT_INDEX | SDHCI_INT_DATA_TIMEOUT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT | SDHCI_INT_DMA);
- val = esdhc_read32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val = sdhci_read32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
val |= SYSCTL_HCKEN | SYSCTL_IPGEN;
- esdhc_write32(esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
@@ -240,7 +91,7 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
data.blocksize = SECTOR_SIZE;
data.flags = MMC_DATA_READ;
- ret = esdhc_send_cmd(esdhc, &cmd, &data);
+ ret = esdhc_send_cmd(host, &cmd, &data);
if (ret) {
pr_debug("send command failed with %d\n", ret);
return ret;
@@ -250,120 +101,67 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len)
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
- esdhc_send_cmd(esdhc, &cmd, NULL);
+ esdhc_send_cmd(host, &cmd, NULL);
return 0;
}
#ifdef CONFIG_ARCH_IMX
-static int esdhc_search_header(struct esdhc *esdhc,
- struct imx_flash_header_v2 **header_pointer,
- void *buffer, u32 *offset)
+static int imx_read_blocks(void *dest, size_t len, void *priv)
{
- int ret;
- int i, header_count = 1;
- void *buf = buffer;
- struct imx_flash_header_v2 *hdr;
-
- for (i = 0; i < header_count; i++) {
- ret = esdhc_read_blocks(esdhc, buf,
- *offset + SZ_1K + SECTOR_SIZE);
- if (ret)
- return ret;
-
- hdr = buf + *offset + SZ_1K;
-
- if (!is_imx_flash_header_v2(hdr)) {
- pr_debug("IVT header not found on SD card. "
- "Found tag: 0x%02x length: 0x%04x "
- "version: %02x\n",
- hdr->header.tag, hdr->header.length,
- hdr->header.version);
- return -EINVAL;
- }
-
- if (IS_ENABLED(CONFIG_ARCH_IMX8MQ) &&
- hdr->boot_data.plugin & PLUGIN_HDMI_IMAGE) {
- /*
- * In images that include signed HDMI
- * firmware, first v2 header would be
- * dedicated to that and would not contain any
- * useful for us information. In order for us
- * to pull the rest of the bootloader image
- * in, we need to re-read header from SD/MMC,
- * this time skipping anything HDMI firmware
- * related.
- */
- *offset += hdr->boot_data.size + hdr->header.length;
- header_count++;
- }
- }
- *header_pointer = hdr;
- return 0;
+ return esdhc_read_blocks(priv, dest, len);
}
static int
-esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
- u32 offset)
+esdhc_load_image(struct fsl_esdhc_host *host, ptrdiff_t address,
+ ptrdiff_t entry, u32 offset, u32 ivt_offset, bool start)
{
+ return imx_load_image(address, entry, offset, ivt_offset, start,
+ SECTOR_SIZE, imx_read_blocks, host);
+}
- void *buf = (void *)address;
- struct imx_flash_header_v2 *hdr = NULL;
- int ret, len;
- void __noreturn (*bb)(void);
- unsigned int ofs;
+static void imx_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data)
+{
+ u32 mixctrl;
- len = imx_image_size();
- len = ALIGN(len, SECTOR_SIZE);
+ data->flags = ESDHC_FLAG_USDHC;
+ host->socdata = data;
+ esdhc_populate_sdhci(host);
- ret = esdhc_search_header(esdhc, &hdr, buf, &offset);
- if (ret)
- return ret;
+ sdhci_write32(&host->sdhci, IMX_SDHCI_WML,
+ FIELD_PREP(WML_WR_BRST_LEN, 16) |
+ FIELD_PREP(WML_WR_WML_MASK, SECTOR_WML) |
+ FIELD_PREP(WML_RD_BRST_LEN, 16) |
+ FIELD_PREP(WML_RD_WML_MASK, SECTOR_WML));
- pr_debug("Check ok, loading image\n");
-
- ofs = offset + hdr->entry - hdr->boot_data.start;
-
- if (entry != address) {
- /*
- * Passing entry different from address is interpreted
- * as a request to place the image such that its entry
- * point would be exactly at 'entry', that is:
- *
- * buf + ofs = entry
- *
- * solving the above for 'buf' gvies us the
- * adjustement that needs to be made:
- *
- * buf = entry - ofs
- *
- */
- if (WARN_ON(entry - ofs < address)) {
- /*
- * We want to make sure we won't try to place
- * the start of the image before the beginning
- * of the memory buffer we were given in
- * address.
- */
- return -EINVAL;
- }
-
- buf = (void *)(entry - ofs);
- }
+ mixctrl = sdhci_read32(&host->sdhci, IMX_SDHCI_MIXCTRL);
+ if (mixctrl & MIX_CTRL_DDREN)
+ host->sdhci.timing = MMC_TIMING_MMC_DDR52;
+}
- ret = esdhc_read_blocks(esdhc, buf, offset + len);
- if (ret) {
- pr_err("Loading image failed with %d\n", ret);
- return ret;
+static int imx8m_esdhc_init(struct fsl_esdhc_host *host,
+ struct esdhc_soc_data *data,
+ int instance)
+{
+ switch (instance) {
+ case 0:
+ host->sdhci.base = IOMEM(MX8M_USDHC1_BASE_ADDR);
+ break;
+ case 1:
+ host->sdhci.base = IOMEM(MX8M_USDHC2_BASE_ADDR);
+ break;
+ case 2:
+ /* Only exists on i.MX8MM, not on i.MX8MQ */
+ host->sdhci.base = IOMEM(MX8MM_USDHC3_BASE_ADDR);
+ break;
+ default:
+ return -EINVAL;
}
- pr_debug("Image loaded successfully\n");
-
- bb = buf + ofs;
+ imx_esdhc_init(host, data);
- sync_caches_for_execution();
-
- bb();
+ return 0;
}
/**
@@ -380,34 +178,33 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry,
*/
int imx6_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host = { 0 };
switch (instance) {
case 0:
- esdhc.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC1_BASE_ADDR);
break;
case 1:
- esdhc.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC2_BASE_ADDR);
break;
case 2:
- esdhc.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC3_BASE_ADDR);
break;
case 3:
- esdhc.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC4_BASE_ADDR);
break;
default:
return -EINVAL;
}
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ imx_esdhc_init(&host, &data);
- return esdhc_start_image(&esdhc, 0x10000000, 0x10000000, 0);
+ return esdhc_load_image(&host, 0x10000000, 0x10000000, 0, SZ_1K, true);
}
/**
- * imx8_esdhc_start_image - Load and start an image from USDHC controller
+ * imx7_esdhc_start_image - Load and start an image from USDHC controller
* @instance: The USDHC controller instance (0..2)
*
* This uses esdhc_start_image() to load an image from SD/MMC. It is
@@ -418,83 +215,126 @@ int imx6_esdhc_start_image(int instance)
* Return: If successful, this function does not return. A negative error
* code is returned when this function fails.
*/
-int imx8_esdhc_start_image(int instance)
+int imx7_esdhc_start_image(int instance)
{
- struct esdhc esdhc;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host = { 0 };
switch (instance) {
case 0:
- esdhc.regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX7_USDHC1_BASE_ADDR);
break;
case 1:
- esdhc.regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX7_USDHC2_BASE_ADDR);
+ break;
+ case 2:
+ host.sdhci.base = IOMEM(MX7_USDHC3_BASE_ADDR);
break;
default:
return -EINVAL;
}
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ imx_esdhc_init(&host, &data);
- return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR,
- MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K);
+ return esdhc_load_image(&host, 0x80000000, 0x80000000, 0, SZ_1K, true);
}
-int imx8_esdhc_load_piggy(int instance)
+/**
+ * imx8m_esdhc_load_image - Load and optionally start an image from USDHC controller
+ * @instance: The USDHC controller instance (0..2)
+ * @bl33: Where to load the bl33 barebox image
+ *
+ * This uses esdhc_start_image() to load an image from SD/MMC. It is
+ * assumed that the image is the currently running barebox image (This
+ * information is used to calculate the length of the image). The
+ * image is not started afterwards.
+ *
+ * Return: If image successfully loaded, returns 0.
+ * A negative error code is returned when this function fails.
+ */
+int imx8m_esdhc_load_image(int instance, void *bl33)
{
- void *buf, *piggy;
- struct imx_flash_header_v2 *hdr = NULL;
- struct esdhc esdhc;
- int ret, len;
- int offset = SZ_32K;
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host = { 0 };
+ int ret;
- switch (instance) {
- case 0:
- esdhc.regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR);
- break;
- case 1:
- esdhc.regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR);
- break;
- default:
- return -EINVAL;
- }
+ ret = imx8m_esdhc_init(&host, &data, instance);
+ if (ret)
+ return ret;
- esdhc.is_be = 0;
- esdhc.is_mx6 = 1;
- esdhc.wrap_wml = false;
+ return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR,
+ (ptrdiff_t)bl33, SZ_32K, SZ_1K,
+ false);
+}
- /*
- * We expect to be running at MX8MQ_ATF_BL33_BASE_ADDR where the atf
- * has jumped to. Use a temporary buffer where we won't overwrite
- * ourselves.
- */
- buf = (void *)MX8MQ_ATF_BL33_BASE_ADDR + SZ_32M;
+/**
+ * imx8mp_esdhc_load_image - Load and optionally start an image from USDHC controller
+ * @instance: The USDHC controller instance (0..2)
+ * @bl33: Where to load the bl33 barebox image
+ *
+ * This uses esdhc_start_image() to load an image from SD/MMC. It is
+ * assumed that the image is the currently running barebox image (This
+ * information is used to calculate the length of the image). The
+ * image is not started afterwards.
+ *
+ * Return: If image successfully loaded, returns 0.
+ * A negative error code is returned when this function fails.
+ */
+int imx8mp_esdhc_load_image(int instance, void *bl33)
+{
+ struct esdhc_soc_data data;
+ struct fsl_esdhc_host host = { 0 };
+ u32 offset;
+ int ret;
- ret = esdhc_search_header(&esdhc, &hdr, buf, &offset);
+ ret = imx8m_esdhc_init(&host, &data, instance);
if (ret)
return ret;
- len = offset + hdr->boot_data.size + piggydata_size();
- len = ALIGN(len, SECTOR_SIZE);
+ offset = esdhc_bootpart_active(&host)? 0 : SZ_32K;
- ret = esdhc_read_blocks(&esdhc, buf, len);
+ return esdhc_load_image(&host, MX8M_DDR_CSD1_BASE_ADDR,
+ (ptrdiff_t)bl33, offset, 0, false);
+}
- /*
- * Calculate location of the piggydata at the offset loaded into RAM
- */
- piggy = buf + offset + hdr->boot_data.size;
+int imx8mn_esdhc_load_image(int instance, void *bl33)
+ __alias(imx8mp_esdhc_load_image);
+#endif
+
+#ifdef CONFIG_ARCH_LAYERSCAPE
+
+static int layerscape_esdhc_load_image(struct fsl_esdhc_host *host, void *adr, unsigned long size,
+ uint32_t div_val)
+{
+ uint32_t val;
+ int ret;
+
+ esdhc_populate_sdhci(host);
+ sdhci_write32(&host->sdhci, IMX_SDHCI_WML, 0);
/*
- * Copy the piggydata where the uncompressing code expects it
+ * The ROM leaves us here with a clock frequency of around 400kHz. Speed
+ * this up a bit. FIXME: The resulting frequency has not yet been verified
+ * to work on all cards.
*/
- memcpy(input_data, piggy, piggydata_size());
+ val = sdhci_read32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
+ val &= ~0x0000fff0;
+ val |= div_val;
+ sdhci_write32(&host->sdhci, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
- return ret;
-}
-#endif
+ sdhci_write32(&host->sdhci, ESDHC_DMA_SYSCTL,
+ ESDHC_SYSCTL_DMA_SNOOP | ESDHC_SYSCTL_PERIPHERAL_CLK_SEL);
-#ifdef CONFIG_ARCH_LS1046
+ ret = esdhc_read_blocks(host, adr, size);
+ if (ret) {
+ pr_err("%s: reading blocks failed with: %d\n", __func__, ret);
+ return ret;
+ }
+
+ sync_caches_for_execution();
+
+ return 0;
+}
/*
* The image on the SD card starts at 0x1000. We reserved 128KiB for the PBL,
@@ -515,41 +355,76 @@ int imx8_esdhc_load_piggy(int instance)
int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long r2)
{
int ret;
- uint32_t val;
- struct esdhc esdhc = {
- .regs = IOMEM(0x01560000),
- .is_be = true,
- .wrap_wml = true,
+ struct esdhc_soc_data data = {
+ .flags = ESDHC_FLAG_MULTIBLK_NO_INT | ESDHC_FLAG_BIGENDIAN,
+ };
+ struct fsl_esdhc_host host = {
+ .sdhci.base = IOMEM(0x01560000),
+ .socdata = &data,
};
- unsigned long sdram = 0x80000000;
+ void *sdram = (void *)0x80000000;
+ unsigned long size = ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512);
void (*barebox)(unsigned long, unsigned long, unsigned long) =
- (void *)(sdram + LS1046A_SD_IMAGE_OFFSET);
+ (sdram + LS1046A_SD_IMAGE_OFFSET);
- /*
- * The ROM leaves us here with a clock frequency of around 400kHz. Speed
- * this up a bit. FIXME: The resulting frequency has not yet been verified
- * to work on all cards.
- */
- val = esdhc_read32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET);
- val &= ~0x0000fff0;
- val |= (8 << 8) | (3 << 4);
- esdhc_write32(&esdhc, SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET, val);
+ ret = layerscape_esdhc_load_image(&host, sdram, size, (8 << 8) | (3 << 4));
+ if (ret)
+ return ret;
- esdhc_write32(&esdhc, ESDHC_DMA_SYSCTL, ESDHC_SYSCTL_DMA_SNOOP);
+ printf("Starting barebox\n");
- ret = esdhc_read_blocks(&esdhc, (void *)sdram,
- ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512));
- if (ret) {
- pr_err("%s: reading blocks failed with: %d\n", __func__, ret);
+ barebox(r0, r1, r2);
+
+ return -EINVAL;
+}
+
+static int ls1028a_esdhc_start_image(void __iomem *base, struct dram_regions_info *dram_info)
+{
+ struct esdhc_soc_data data = {
+ .flags = ESDHC_FLAG_MULTIBLK_NO_INT,
+ };
+ struct fsl_esdhc_host host = {
+ .sdhci.base = base,
+ .socdata = &data,
+ };
+ void *sdram = (void *)0x80000000;
+ void (*bl31)(void) = (void *)LS1028A_TFA_RESERVED_START;
+ size_t bl31_size;
+ void *bl31_image;
+ struct bl2_to_bl31_params_mem_v2 *params;
+ unsigned long size = ALIGN(barebox_image_size + LS1046A_SD_IMAGE_OFFSET, 512);
+ void (*barebox)(unsigned long, unsigned long, unsigned long) =
+ (sdram + LS1046A_SD_IMAGE_OFFSET);
+ int ret;
+
+ ret = layerscape_esdhc_load_image(&host, sdram, size, 8 << 4);
+ if (ret)
return ret;
- }
- sync_caches_for_execution();
+ get_builtin_firmware_ext(ls1028a_bl31_bin, barebox, &bl31_image, &bl31_size);
+ memcpy(bl31, bl31_image, bl31_size);
- printf("Starting barebox\n");
+ /* Setup an initial stack for EL2 */
+ asm volatile("msr sp_el2, %0" : : "r" ((unsigned long)barebox - 16) : "cc");
- barebox(r0, r1, r2);
+ params = bl2_plat_get_bl31_params_v2(0, (uintptr_t)barebox, 0);
+ params->bl31_ep_info.args.arg3 = (unsigned long)dram_info;
+
+ printf("Starting bl31\n");
+
+ bl31_entry_v2((uintptr_t)bl31, &params->bl_params, NULL);
return -EINVAL;
}
+
+int ls1028a_esdhc1_start_image(struct dram_regions_info *dram_info)
+{
+ return ls1028a_esdhc_start_image(IOMEM(0x2140000), dram_info);
+}
+
+int ls1028a_esdhc2_start_image(struct dram_regions_info *dram_info)
+{
+ return ls1028a_esdhc_start_image(IOMEM(0x2150000), dram_info);
+}
+
#endif