Skip to content

Commit

Permalink
mmc: Add support for boot from MMC/eMMC/SDIO
Browse files Browse the repository at this point in the history
	- Support boot from SDIO with variables located
	  on MMC/eMMC/SD raw (unpartitioned) space
	- SD:
	  on SD, assumed to have a regular MBR on LBA-0, since
	  recent SD cards don't reach volumes requiring usage of GPT.
	  Therefore the u-boot image should be placed on SD card starting LBA-1.
	- MMC/eMMC:
	  om MMC, detection for image is started at LBA-0
	  (on either Boot0/Boot1/Data partitions).
	- The space reserved for u-boot image is 1MB followed
	  by the environment region. The MMC/eMMC card can use either
	  Boot-0, Boot-1 or Data partitions, while it will be a
	  gap of one sector between u-boot image and the environment.
	- Add delay for SD command 12 (stop transmission)
	  on Marvell platforms, since the transaction completion
	  status obtained from SDIO interrupt status register
	  is delayed for this particular command in DMA mode.
	- Use write zeros to u-boot configuration area on
	  "reset environment" request instead of erase operation
	  since the last does not always succeeds from the interrupt
	  status point of view.

Change-Id: I596889aa5883c8aeb6c361513c21dd82fe6093e1
Signed-off-by: kostap <kostap@marvell.com>
Reviewed-on: http://vgitil04.il.marvell.com:8080/15693
Reviewed-by: Omri Itach <omrii@marvell.com>
Tested-by: Star_Automation <star@marvell.com>
Reviewed-on: http://vgitil04.il.marvell.com:8080/16308
  • Loading branch information
kostap authored and rabeeh committed Sep 7, 2015
1 parent a7b64b5 commit 7cfc5f3
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 23 deletions.
2 changes: 2 additions & 0 deletions board/mv_ebu/a38x/mv_main_a38x.c
Expand Up @@ -158,6 +158,8 @@ void mv_print_map(void)
printf("(NAND)\n\n");
#elif defined(MV_SPI_BOOT)
printf("(SPI)\n\n");
#elif defined(MV_MMC_BOOT)
printf("(MMC)\n\n");
#endif
}

Expand Down
106 changes: 106 additions & 0 deletions board/mv_ebu/common/USP/cmd_bubt.c
Expand Up @@ -46,6 +46,11 @@ extern struct spi_flash *flash;
extern flash_info_t flash_info[]; /* info for FLASH chips */
#endif

#if defined(MV_MMC_BOOT)
#include <mmc.h>
extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src);
#endif

#if 0 /* def MV_NOR_BOOT */
static unsigned int flash_in_which_sec(flash_info_t *fl,unsigned int offset)
{
Expand Down Expand Up @@ -468,3 +473,104 @@ U_BOOT_CMD(
"\tsource can be tftp or usb, default is tftp.\n"
);
#endif /* MV_NOR_BOOT */

#if defined(MV_MMC_BOOT)

/* Boot from SD/MMC/eMMC */
/* Write u-boot image into SD/MMC/eMMC device */
int mmc_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int filesize = 0;
extern char console_buffer[];
load_addr = CONFIG_SYS_LOAD_ADDR;
MV_U32 loadfrom = 0; /* 0 - from tftp, 1 - from USB */
lbaint_t start_lba;
lbaint_t blk_count;
ulong blk_written;
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct mmc *mmc;

start_lba = CONFIG_ENV_ADDR / CONFIG_ENV_SECT_SIZE;
blk_count = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;

mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc) {
printf("No SD/MMC/eMMC card found\n");
return 1;
}

if (mmc_init(mmc)) {
printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC", CONFIG_SYS_MMC_ENV_DEV);
return 1;
}

#ifdef CONFIG_SYS_MMC_ENV_PART
if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) {
if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, CONFIG_SYS_MMC_ENV_PART)) {
printf("MMC partition switch failed\n");
return 1;
}
}
#endif

/* verify requested source is valid */
if (fetch_bubt_cmd_args(argc, argv, &loadfrom) != MV_OK)
return 0;

if ((filesize = fetch_uboot_file (loadfrom)) <= 0)
return 0;

printf("\t\t[Done]\n");
printf("Override Env parameters to default? [y/N]");
readline(" ");

if( strcmp(console_buffer,"Y") == 0 ||
strcmp(console_buffer,"yes") == 0 ||
strcmp(console_buffer,"y") == 0 ) {

printf("Erasing 0x"LBAF" blocks starting at sector 0x"LBAF" :", blk_count, start_lba);
memset(buf, 0, CONFIG_ENV_SIZE);
blk_written = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, buf);
if (blk_written != blk_count) {
printf("\t[FAIL] - erased %#lx blocks\n", blk_written);
return 0;
} else
printf("\t[Done]\n");
}
if (filesize > CONFIG_ENV_OFFSET) {
printf("Error: Image size (%x) exceeds environment variables offset (%x). ", filesize, CONFIG_ENV_OFFSET);
return 0;
}

/* SD reserves LBA-0 for MBR and boots from LBA-1, MMC/eMMC boots from LBA-0 */
start_lba = IS_SD(mmc) ? 1 : 0;
blk_count = filesize / CONFIG_ENV_SECT_SIZE;
if (filesize % CONFIG_ENV_SECT_SIZE)
blk_count += 1;

printf("Writing image to %s(%d) at LBA 0x"LBAF" (0x"LBAF" blocks):",
IS_SD(mmc) ? "SD" : "MMC", CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count);
blk_written = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, (char *)CONFIG_SYS_LOAD_ADDR);
if (blk_written != blk_count) {
printf("\t[FAIL] - written %#lx blocks\n", blk_written);
return 0;
} else
printf("\t[Done]\n");

#ifdef CONFIG_SYS_MMC_ENV_PART
if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, mmc->part_num);
#endif

return 1;
}

U_BOOT_CMD(
bubt, 3, 1, mmc_burn_uboot_cmd,
"bubt - Burn an image on the Boot SD/MMC/eMMC device.\n",
" file-name \n"
"[file-name] [source] \n"
"\tBurn a binary image on the Boot Device, default file-name is u-boot.bin .\n"
"\tsource can be tftp or usb, default is tftp.\n"
);
#endif
69 changes: 66 additions & 3 deletions board/mv_ebu/common/USP/cmd_resetenv.c
Expand Up @@ -43,15 +43,27 @@ extern flash_info_t flash_info[]; /* info for FLASH chips */
#if defined(CONFIG_ENV_IS_IN_NAND)
int nand_get_env_offs(void);
#endif
#if defined(CONFIG_ENV_IS_IN_MMC)
#include <mmc.h>
extern unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt);
extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src);
#endif

/*******************************************************************************
Reset environment variables.
********************************************************************************/
int resetenv_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#if defined(CONFIG_ENV_IS_IN_FLASH )
ulong stop_addr;
ulong start_addr;

ulong stop_addr;
ulong start_addr;
#elif defined(CONFIG_ENV_IS_IN_MMC)
lbaint_t start_lba;
lbaint_t blk_count;
ulong blk_erased;
ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
struct mmc *mmc;
int err;
#endif

#if defined(CONFIG_ENV_IS_IN_NAND)
Expand Down Expand Up @@ -109,6 +121,57 @@ int resetenv_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
flash_sect_protect (1, start_addr, stop_addr);
printf("\t[Done]\n");

#elif defined(CONFIG_ENV_IS_IN_MMC)

start_lba = CONFIG_ENV_ADDR / CONFIG_ENV_SECT_SIZE;
blk_count = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;

mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc) {
printf("No MMC card found\n");
return 1;
}

if (mmc_init(mmc)) {
printf("MMC(%d) init failed\n", CONFIG_SYS_MMC_ENV_DEV);
return 1;
}

#ifdef CONFIG_SYS_MMC_ENV_PART /* Valid for MMC/eMMC only - switch to ENV partition */
if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) {
if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, CONFIG_SYS_MMC_ENV_PART)) {
printf("MMC partition switch failed\n");
return 1;
}
}
#endif

printf("Erasing 0x"LBAF" blocks starting at sector 0x"LBAF" :", blk_count, start_lba);
/* For some unknown reason the mmc_berase() fails with timeout if called
before any futher write to MMC/SD (for instance, right after u-boot bring up).
However the mmc_bwrite() always succeds.
Writing zeroes into SD/MMC blocks is similar operation as doing so to IDE/SATA
disk and therefore can be used for erasing the imformation stored on the media.
blk_erased = mmc_berase(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count);
*/
memset(buf, 0, CONFIG_ENV_SIZE);
blk_erased = mmc_bwrite(CONFIG_SYS_MMC_ENV_DEV, start_lba, blk_count, buf);
if (blk_erased != blk_count) {
printf("\t[FAIL] - erased %#lx blocks\n", blk_erased);
err = 1;
} else {
printf("\t[Done]\n");
err = 0;
}

#ifdef CONFIG_SYS_MMC_ENV_PART /* Valid for MMC/eMMC only - restore current partition */
if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num)
mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, mmc->part_num);
#endif

if (err)
return err;

#endif
printf("Warning: Default Environment Variables will take effect Only after RESET\n");
return 0;
Expand Down
8 changes: 7 additions & 1 deletion build.pl
Expand Up @@ -11,7 +11,7 @@ sub HELP_MESSAGE
print "Example: ./build.pl -f spi -v 14T2 -b avanta_lp -i spi:nand -c\n";
print "\n";
print "Options:\n";
print "\t-f\tBoot device. Accepts spi, nor, nand\n";
print "\t-f\tBoot device. Accepts spi, nor, nand, mmc\n";
print "\t-b\tBoard type. Accepts:\tavanta_lp , avanta_lp_customer0 , avanta_lp_customer1\n";
print "\t\t\t\t\tarmada_38x, armada_38x_customer0, armada_38x_customer1\n";
print "\t\t\t\t\tarmada_39x, armada_39x_customer0, armada_39x_customer1\n";
Expand Down Expand Up @@ -200,6 +200,12 @@ sub HELP_MESSAGE
}
print "Image options = $img_opts\n\n";
}
elsif ($opt_f eq "mmc"){
system("echo \"#define MV_MMC_BOOT\" >> include/config.h");
print "Boot from MMC/eMMC/SD\n";
$flash_name = "mmc";
$img_type = "mmc";
}
else
{
if (defined $opt_f) {
Expand Down
22 changes: 7 additions & 15 deletions common/cmd_mmc.c
Expand Up @@ -24,9 +24,8 @@
#include <common.h>
#include <command.h>
#include <mmc.h>
extern void mvSysSDmmcWinInit(void);

static int mmc_initiated = 0;
extern int mmc_initiated;
static int curr_device = -1;
#ifndef CONFIG_GENERIC_MMC
int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Expand Down Expand Up @@ -156,14 +155,12 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (argc < 2)
return CMD_RET_USAGE;

if (mmc_initiated == 0)
{ /* If this is not a call to rescan !!!! */
if (!((argc==2)&&(strncmp(argv[1],"rescan",6) == 0)))
{
puts ("\nWarning: Please run 'mmc rescan' before running other mmc commands \n\n");
return 1;
}
}
if (mmc_initiated == 0) { /* If this is not a call to rescan !!!! */
if (!((argc == 2) && (strncmp(argv[1], "rescan", 6) == 0))) {
puts ("\nWarning: Please run 'mmc rescan' before running other mmc commands \n\n");
return 1;
}
}

if (curr_device < 0) {
if (get_mmc_num() > 0)
Expand All @@ -175,11 +172,6 @@ int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}

if (strcmp(argv[1], "rescan") == 0) {
if (mmc_initiated==0)
{
mvSysSDmmcWinInit();
mmc_initiated=1;
}
struct mmc *mmc = find_mmc_device(curr_device);

if (!mmc) {
Expand Down
6 changes: 3 additions & 3 deletions common/env_mmc.c
Expand Up @@ -157,13 +157,13 @@ int saveenv(void)
static inline int read_env(struct mmc *mmc, unsigned long size,
unsigned long offset, const void *buffer)
{
uint blk_start, blk_cnt, n;
lbaint_t blk_start, blk_cnt;
ulong n;

blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len;

n = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV, blk_start,
blk_cnt, (uchar *)buffer);
n = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV, blk_start, blk_cnt, (uchar *)buffer);

return (n == blk_cnt) ? 0 : -1;
}
Expand Down
13 changes: 12 additions & 1 deletion drivers/mmc/mmc.c
Expand Up @@ -39,8 +39,11 @@
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
#endif

extern void mvSysSDmmcWinInit(void);

static struct list_head mmc_devices;
static int cur_dev_num = -1;
int mmc_initiated = 0;

/* buffer to SDIO/MMC DMA must be aligned to 128 */

Expand Down Expand Up @@ -99,7 +102,10 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
#ifdef CONFIG_MMC_TRACE
printf("CMD_SEND:%d\n", cmd->cmdidx);
printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
printf("\t\tdata\t\t\t 0x%x\n", data);
printf("\t\tdata->dest/src\t\t 0x%p\n", data->dest);
printf("\t\tdata->flags\t\t 0x%x\n", data->flags);
printf("\t\tdata->blocks\t\t 0x%x\n", data->blocks);
printf("\t\tdata->blocksize\t\t 0x%x\n", data->blocksize);
#endif
ret = mmc->send_cmd(mmc, cmd, data);
/* copy back to original dest address */
Expand Down Expand Up @@ -1325,6 +1331,11 @@ int mmc_init(struct mmc *mmc)
int err = IN_PROGRESS;
unsigned start = get_timer(0);

if (mmc_initiated == 0) {
mvSysSDmmcWinInit();
mmc_initiated=1;
}

if (mmc->has_init)
return 0;
if (!mmc->init_in_progress)
Expand Down
7 changes: 7 additions & 0 deletions drivers/mmc/sdhci.c
Expand Up @@ -240,6 +240,13 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
stat = sdhci_readl(host, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
break;
#ifdef CONFIG_MV_SDHCI
/* Some commands om MRVL controller are not updating the SDHCI interrupt status
register fast enough. Adding small polling interval solves the problem */
if (/* cmd->cmdidx == MMC_CMD_ERASE || $$ Currently not used $$ */
cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
udelay(5);
#endif
if (--retry == 0)
break;
} while ((stat & mask) != mask);
Expand Down
27 changes: 27 additions & 0 deletions include/configs/armada_38x.h
Expand Up @@ -517,6 +517,33 @@ extern unsigned int mvTclkGet(void);
#endif
#define CONFIG_SYS_MMC_BASE (INTER_REGS_BASE + MV_SDMMC_REGS_OFFSET)

/* MMC configuration */
/*****************************/
//#define CONFIG_MMC_TRACE
/* Boot from MMC settings */
#if defined(MV_MMC_BOOT)
#define CONFIG_ENV_IS_IN_MMC /* Environment is at absolute location (RAW) */
// #define CONFIG_ENV_IS_IN_FAT /* Environment is in file on FAT partition */
// #define CONFIG_FAT_WRITE
// #define FAT_ENV_INTERFACE "mmc"
// #define FAT_ENV_DEVICE 0
// #define FAT_ENV_PART 1
// #define FAT_ENV_FILE "u-boot.env"

// #define CONFIG_SYS_MMC_ENV_PART 1 /* Valid for MMC/eMMC for separating boot image and env */
#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_ENV_SECT_SIZE 0x200
#define CONFIG_ENV_SIZE 0x80000
/* For SD - reserve 1 LBA for MBR + 1M for u-boot image. The MMC/eMMC boot image starts @ LBA-0.
As result in MMC/eMMC case it will be a 1 sector gap between u-boot image and environment */
#define CONFIG_ENV_OFFSET (_1M + CONFIG_ENV_SECT_SIZE)
#define CONFIG_ENV_ADDR CONFIG_ENV_OFFSET
#define MONITOR_HEADER_LEN 0x200
#define CONFIG_SYS_MONITOR_BASE 0
#define CONFIG_SYS_MONITOR_LEN 0x80000 /*(512 << 10) Reserve 512 kB for Monitor */

#endif /* #if defined(MV_MMC_BOOT) */


/*
* Linux boot and other
Expand Down

0 comments on commit 7cfc5f3

Please sign in to comment.