diff options
Diffstat (limited to 'drivers/mci/imx-esdhc-pbl.c')
-rw-r--r-- | drivers/mci/imx-esdhc-pbl.c | 625 |
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, ¶ms->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 |