i2S6ULY2: support update eMMC partition

This function reference by Digi U-Boot.
This commit is contained in:
SteveChen
2018-04-30 11:00:48 +08:00
parent a39b446324
commit 731900fa3c
3 changed files with 927 additions and 0 deletions

View File

@ -11,3 +11,4 @@ obj-$(CONFIG_CMD_BOOTSTREAM) += cmd_bootstream/bch.o \
cmd_bootstream/cmd_bootstream.o \
cmd_bootstream/mxsboot.o
obj-$(CONFIG_CMD_UPDATE_NAND) += cmd_update_nand.o helper.o
obj-$(CONFIG_CMD_UPDATE_MMC) += cmd_update_mmc.o helper.o helper_mmc.o

View File

@ -0,0 +1,753 @@
/*
* Copyright (C) 2014 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version2 as published by
* the Free Software Foundation.
*/
#include <common.h>
#include <asm/imx-common/boot_mode.h>
#include <otf_update.h>
#include <part.h>
#include <mmc.h>
#include "helper.h"
DECLARE_GLOBAL_DATA_PTR;
static block_dev_desc_t *mmc_dev;
static int mmc_dev_index;
static int mmc_get_bootdevindex(void);
static int board_update_chunk(otf_data_t *oftd);
extern void register_tftp_otf_update_hook(int (*hook)(otf_data_t *oftd),
disk_partition_t*);
extern void unregister_tftp_otf_update_hook(void);
extern void register_fs_otf_update_hook(int (*hook)(otf_data_t *oftd),
disk_partition_t*);
extern void unregister_fs_otf_update_hook(void);
int register_otf_hook(int src, int (*hook)(otf_data_t *oftd),
disk_partition_t *partition)
{
switch (src) {
case SRC_MMC:
case SRC_USB:
case SRC_SATA:
register_fs_otf_update_hook(hook, partition);
return 1;
case SRC_NFS:
//TODO
break;
}
return 0;
}
void unregister_otf_hook(int src)
{
switch (src) {
case SRC_MMC:
unregister_fs_otf_update_hook();
break;
case SRC_USB:
case SRC_SATA:
case SRC_NFS:
//TODO
break;
}
}
enum {
ERR_WRITE = 1,
ERR_READ,
ERR_VERIFY,
};
static int write_firmware(char *partname, unsigned long loadaddr,
unsigned long filesize, disk_partition_t *info)
{
char cmd[CONFIG_SYS_CBSIZE] = "";
unsigned long size_blks, verifyaddr, u, m;
size_blks = (filesize / mmc_dev->blksz) + (filesize % mmc_dev->blksz != 0);
if (size_blks > info->size) {
printf("File size (%lu bytes) exceeds partition size (%lu bytes)!\n",
filesize,
info->size * mmc_dev->blksz);
return -1;
}
/* Prepare command to change to storage device */
sprintf(cmd, "%s dev %d", CONFIG_SYS_STORAGE_MEDIA, mmc_dev_index);
/*
* If updating U-Boot on eMMC
* append the hardware partition where U-Boot lives.
*/
if (!strcmp(partname, "uboot") &&
!strcmp(CONFIG_SYS_STORAGE_MEDIA, "mmc") &&
(mmc_dev_index == 0))
strcat(cmd, " $mmcbootpart");
/* Change to storage device */
if (run_command(cmd, 0)) {
debug("Cannot change to storage device\n");
return -1;
}
/* Write firmware command */
sprintf(cmd, "%s write %lx %lx %lx", CONFIG_SYS_STORAGE_MEDIA,
loadaddr, info->start, size_blks);
if (run_command(cmd, 0))
return ERR_WRITE;
/* If there is enough RAM to hold two copies of the firmware,
* verify written firmware.
* +--------|---------------------|------------------|--------------+
* | L V | U-Boot+Stack |
* +--------|---------------------|------------------|--------------+
* P U M
*
* P = PHYS_SDRAM (base address of SDRAM)
* L = $loadaddr
* V = $verifyaddr
* M = last address of SDRAM (CONFIG_DDR_SIZE (size of SDRAM) + P)
* U = SDRAM address where U-Boot is located (plus margin)
*/
verifyaddr = getenv_ulong("verifyaddr", 16, 0);
m = PHYS_SDRAM + (CONFIG_DDR_SIZE * 1024LU * 1024LU);
u = m - CONFIG_UBOOT_RESERVED;
/* ($loadaddr + firmware size) must not exceed $verifyaddr
* ($verifyaddr + firmware size) must not exceed U
*/
if ((loadaddr + size_blks * mmc_dev->blksz) < verifyaddr &&
(verifyaddr + size_blks * mmc_dev->blksz) < u) {
unsigned long filesize_padded;
int i;
/* Read back data... */
printf("Reading back firmware...\n");
sprintf(cmd, "%s read %lx %lx %lx", CONFIG_SYS_STORAGE_MEDIA,
verifyaddr, info->start, size_blks);
if (run_command(cmd, 0))
return ERR_READ;
/* ...then compare by 32-bit words (faster than by bytes)
* padding with zeros any bytes at the end to make the size
* be a multiple of 4.
*
* Reference: http://stackoverflow.com/a/2022252
*/
printf("Verifying firmware...\n");
filesize_padded = (filesize + (4 - 1)) & ~(4 - 1);
for (i = filesize; i < filesize_padded; i++) {
*((char *)loadaddr + i) = 0;
*((char *)verifyaddr + i) = 0;
}
sprintf(cmd, "cmp.l %lx %lx %lx", loadaddr, verifyaddr,
(filesize_padded / 4));
if (run_command(cmd, 0))
return ERR_VERIFY;
printf("Update was successful\n");
} else {
printf("Firmware updated but not verified "
"(not enough available RAM to verify)\n");
}
return 0;
}
static int write_file(char *targetfilename, char *targetfs, int part)
{
char cmd[CONFIG_SYS_CBSIZE] = "";
unsigned long loadaddr, filesize;
loadaddr = getenv_ulong("loadaddr", 16, CONFIG_LOADADDR);
filesize = getenv_ulong("filesize", 16, 0);
/* Change to storage device */
sprintf(cmd, "%s dev %d", CONFIG_SYS_STORAGE_MEDIA, mmc_dev_index);
if (run_command(cmd, 0)) {
debug("Cannot change to storage device\n");
return -1;
}
/* Prepare write command */
sprintf(cmd, "%swrite %s %d:%d %lx %s %lx", targetfs,
CONFIG_SYS_STORAGE_MEDIA, mmc_dev_index, part,
loadaddr, targetfilename, filesize);
return run_command(cmd, 0);
}
#define ECSD_PARTITION_CONFIG 179
#define BOOT_ACK (1 << 6)
#define BOOT_PARTITION_ENABLE_OFF 3
static int emmc_bootselect(void)
{
char cmd[CONFIG_SYS_CBSIZE] = "";
int bootpart;
/* Prepare command to change to storage device */
sprintf(cmd, "mmc dev %d", mmc_dev_index);
/* Change to storage device */
if (run_command(cmd, 0)) {
debug("Cannot change to storage device\n");
return -1;
}
/* Select boot partition and enable boot acknowledge */
bootpart = getenv_ulong("mmcbootpart", 16, CONFIG_SYS_BOOT_PART_EMMC);
sprintf(cmd, "mmc ecsd write %x %x", ECSD_PARTITION_CONFIG,
BOOT_ACK | (bootpart << BOOT_PARTITION_ENABLE_OFF));
return run_command(cmd, 0);
}
/*
* This function returns the size of available RAM holding a firmware transfer.
* This size depends on:
* - The total RAM available
* - The loadaddr
* - The RAM occupied by U-Boot and its location
*/
static unsigned int get_available_ram_for_update(void)
{
unsigned int loadaddr;
unsigned int la_off;
loadaddr = getenv_ulong("loadaddr", 16, CONFIG_LOADADDR);
la_off = loadaddr - gd->bd->bi_dram[0].start;
return (gd->bd->bi_dram[0].size - CONFIG_UBOOT_RESERVED - la_off);
}
static int init_mmc_globals(void)
{
/* Use the device in $mmcdev or else, the boot media */
mmc_dev_index = getenv_ulong("mmcdev", 16, mmc_get_bootdevindex());
mmc_dev = mmc_get_dev(mmc_dev_index);
if (NULL == mmc_dev) {
debug("Cannot determine sys storage device\n");
return -1;
}
return 0;
}
static int do_update(cmd_tbl_t* cmdtp, int flag, int argc, char * const argv[])
{
disk_partition_t info;
int ret;
int otf = 0;
int otf_enabled = 0;
char cmd[CONFIG_SYS_CBSIZE] = "";
unsigned long loadaddr;
unsigned long verifyaddr;
unsigned long filesize = 0;
struct load_fw fwinfo;
if (argc < 2)
return CMD_RET_USAGE;
memset(&fwinfo, 0, sizeof(fwinfo));
if (init_mmc_globals())
return CMD_RET_FAILURE;
/* Get data of partition to be updated */
if (!strcmp(argv[1], "uboot")) {
/* Simulate partition data for U-Boot */
info.start = CONFIG_SYS_BOOT_PART_OFFSET / mmc_dev->blksz;
info.size = CONFIG_SYS_BOOT_PART_SIZE / mmc_dev->blksz;
strcpy((char *)info.name, argv[1]);
} else {
/* Not a reserved name. Must be a partition name or index */
char dev_index_str[2];
/* Look up partition on the device */
sprintf(dev_index_str, "%d", mmc_dev_index);
if (get_partition_bynameorindex(CONFIG_SYS_STORAGE_MEDIA,
dev_index_str, argv[1], &info) < 0) {
printf("Error: partition '%s' not found\n", argv[1]);
return CMD_RET_FAILURE;
}
}
/* Ask for confirmation if needed */
if (getenv_yesno("forced_update") != 1) {
/* Confirm programming */
if (!strcmp((char *)info.name, "uboot") &&
!confirm_msg("Do you really want to program "
"the boot loader? <y/N> "))
return CMD_RET_FAILURE;
}
/* Get source of update firmware file */
if (get_source(argc, argv, &fwinfo))
return CMD_RET_FAILURE;
loadaddr = getenv_ulong("loadaddr", 16, CONFIG_LOADADDR);
/*
* If undefined, calculate 'verifyaddr' as halfway through the RAM
* from $loadaddr.
*/
if (NULL == getenv("verifyaddr")) {
verifyaddr = loadaddr +
((gd->ram_size - (loadaddr - PHYS_SDRAM)) / 2);
if (verifyaddr > loadaddr &&
verifyaddr < (PHYS_SDRAM + gd->ram_size))
setenv_hex("verifyaddr", verifyaddr);
}
if (fwinfo.src == SRC_RAM) {
/* Get address in RAM where firmware file is */
if (argc > 3)
loadaddr = simple_strtol(argv[3], NULL, 16);
/* Get filesize */
if (argc > 4)
filesize = simple_strtol(argv[4], NULL, 16);
} else {
if (getenv_yesno("otf-update") == -1) {
/*
* If otf-update is undefined, check if there is enough
* RAM to hold the largest possible file that fits into
* the destiny partition.
*/
unsigned long avail = get_available_ram_for_update();
if (avail <= info.size * mmc_dev->blksz) {
printf("Partition to update is larger (%d MiB) than the\n"
"available RAM memory (%d MiB, starting at $loadaddr=0x%08x).\n",
(int)(info.size * mmc_dev->blksz / (1024 * 1024)),
(int)(avail / (1024 * 1024)),
(unsigned int)loadaddr);
printf("Activating On-the-fly update mechanism.\n");
otf_enabled = 1;
}
}
/* Get firmware file name */
ret = get_fw_filename(argc, argv, &fwinfo);
if (ret) {
/* Filename was not provided. Look for default one */
fwinfo.filename = get_default_filename(argv[1],
CMD_UPDATE);
if (!fwinfo.filename) {
printf("Error: need a filename\n");
return CMD_RET_USAGE;
}
}
}
/* Activate on-the-fly update if needed */
if (otf_enabled || (getenv_yesno("otf-update") == 1)) {
if (!strcmp((char *)info.name, "uboot")) {
/* Do not activate on-the-fly update for U-Boot */
printf("On-the-fly mechanism disabled for U-Boot "
"for security reasons\n");
} else {
/* register on-the-fly update mechanism */
otf = register_otf_hook(fwinfo.src, board_update_chunk,
&info);
}
}
if (otf) {
/* Prepare command to change to storage device */
sprintf(cmd, CONFIG_SYS_STORAGE_MEDIA " dev %d", mmc_dev_index);
/* Change to storage device */
if (run_command(cmd, 0)) {
printf("Error: cannot change to storage device\n");
ret = CMD_RET_FAILURE;
goto _ret;
}
}
if (fwinfo.src != SRC_RAM) {
/*
* Load firmware file to RAM (this process may write the file
* to the target media if OTF mechanism is enabled).
*/
fwinfo.loadaddr = "$loadaddr";
ret = load_firmware(&fwinfo);
if (ret == LDFW_ERROR) {
printf("Error loading firmware file to RAM\n");
ret = CMD_RET_FAILURE;
goto _ret;
} else if (ret == LDFW_LOADED && otf) {
ret = CMD_RET_SUCCESS;
goto _ret;
}
}
/* Write firmware file from RAM to storage */
if (!filesize)
filesize = getenv_ulong("filesize", 16, 0);
ret = write_firmware(argv[1], loadaddr, filesize, &info);
if (ret) {
if (ret == ERR_READ)
printf("Error while reading back written firmware!\n");
else if (ret == ERR_VERIFY)
printf("Error while verifying written firmware!\n");
else
printf("Error writing firmware!\n");
ret = CMD_RET_FAILURE;
goto _ret;
}
/*
* If updating U-Boot into eMMC, instruct the eMMC to boot from
* special hardware partition.
*/
if (!strcmp(argv[1], "uboot") &&
!strcmp(CONFIG_SYS_STORAGE_MEDIA, "mmc") &&
(mmc_dev_index == 0)) {
ret = emmc_bootselect();
if (ret) {
printf("Error changing eMMC boot partition\n");
ret = CMD_RET_FAILURE;
goto _ret;
}
}
_ret:
unregister_otf_hook(fwinfo.src);
return ret;
}
U_BOOT_CMD(
update, 6, 0, do_update,
"i2SOM modules update command",
"<partition> [source] [extra-args...]\n"
" Description: updates (raw writes) <partition> in $mmcdev via <source>\n"
" Arguments:\n"
" - partition: a partition index, a GUID partition name, or one\n"
" of the reserved names: uboot\n"
" - [source]: " CONFIG_UPDATE_SUPPORTED_SOURCES_LIST "\n"
" - [extra-args]: extra arguments depending on 'source'\n"
"\n"
CONFIG_UPDATE_SUPPORTED_SOURCES_ARGS_HELP
);
/* Certain command line arguments of 'update' command may be at different
* index depending on the selected <source>. This function returns in 'arg'
* the argument at <index> plus an offset that depends on the selected <source>
* Upon calling, the <index> must be given as if <source> was SRC_RAM.
*/
static int get_arg_src(int argc, char * const argv[], int src, int index,
char **arg)
{
switch (src) {
case SRC_TFTP:
case SRC_NFS:
index += 1;
break;
case SRC_MMC:
case SRC_USB:
case SRC_SATA:
index += 3;
break;
case SRC_RAM:
break;
default:
return -1;
}
if (argc > index) {
*arg = (char *)argv[index];
return 0;
}
return -1;
}
int mmc_get_bootdevindex(void)
{
switch(get_boot_device()) {
case SD1_BOOT ... SD4_BOOT:
return 1;
#if 0
/* SD card */
if (board_has_emmc())
return 1; /* index of USDHC2 if SOM has eMMC */
else
return 0; /* index of USDHC2 if SOM has no eMMC */
#endif
case MMC4_BOOT:
return 0; /* index of SDHC4 (eMMC) */
default:
/* return default value otherwise */
return CONFIG_SYS_MMC_ENV_DEV;
}
}
static int write_chunk(struct mmc *mmc, otf_data_t *otfd, unsigned int dstblk,
unsigned int chunklen)
{
int sectors;
unsigned long written, read, verifyaddr;
printf("\nWriting chunk...");
/* Check WP */
if (mmc_getwp(mmc) == 1) {
printf("[Error]: card is write protected!\n");
return -1;
}
/* We can only write whole sectors (multiples of mmc_dev->blksz bytes)
* so we need to check if the chunk is a whole multiple or else add 1
*/
sectors = chunklen / mmc_dev->blksz;
if (chunklen % mmc_dev->blksz)
sectors++;
/* Check if chunk fits */
if (sectors + dstblk > otfd->part->start + otfd->part->size) {
printf("[Error]: length of data exceeds partition size\n");
return -1;
}
/* Write chunklen bytes of chunk to media */
debug("writing chunk of 0x%x bytes (0x%x sectors) "
"from 0x%x to block 0x%x\n",
chunklen, sectors, otfd->loadaddr, dstblk);
written = mmc->block_dev.block_write(mmc_dev_index, dstblk, sectors,
(const void *)otfd->loadaddr);
if (written != sectors) {
printf("[Error]: written sectors != sectors to write\n");
return -1;
}
printf("[OK]\n");
/* Verify written chunk if $loadaddr + chunk size does not overlap
* $verifyaddr (where the read-back copy will be placed)
*/
verifyaddr = getenv_ulong("verifyaddr", 16, 0);
if (otfd->loadaddr + sectors * mmc_dev->blksz < verifyaddr) {
/* Read back data... */
printf("Reading back chunk...");
read = mmc->block_dev.block_read(mmc_dev_index, dstblk, sectors,
(void *)verifyaddr);
if (read != sectors) {
printf("[Error]: read sectors != sectors to read\n");
return -1;
}
printf("[OK]\n");
/* ...then compare */
printf("Verifying chunk...");
if (memcmp((const void *)otfd->loadaddr,
(const void *)verifyaddr,
sectors * mmc_dev->blksz)) {
printf("[Error]\n");
return -1;
} else {
printf("[OK]\n");
return 0;
}
} else {
printf("[Warning]: Cannot verify chunk. "
"It overlaps $verifyaddr!\n");
return 0;
}
}
/* writes a chunk of data from RAM to main storage media (eMMC) */
int board_update_chunk(otf_data_t *otfd)
{
static unsigned int chunk_len = 0;
static unsigned int dstblk = 0;
struct mmc *mmc;
if (mmc_dev_index == -1)
mmc_dev_index = getenv_ulong("mmcdev", 16,
mmc_get_bootdevindex());
mmc = find_mmc_device(mmc_dev_index);
if (NULL == mmc)
return -1;
/*
* There are two variants:
* - otfd.buf == NULL
* In this case, the data is already waiting on the correct
* address in RAM, waiting to be written to the media.
* - otfd.buf != NULL
* In this case, the data is on the buffer and must still be
* copied to an address in RAM, before it is written to media.
*/
if (otfd->buf && otfd->len) {
/*
* If data is in the otfd->buf buffer, copy it to the loadaddr
* in RAM until we have a chunk that is at least as large as
* CONFIG_OTF_CHUNK, to write it to media.
*/
memcpy((void *)(otfd->loadaddr + otfd->offset), otfd->buf,
otfd->len);
}
/* Initialize dstblk and local variables */
if (otfd->flags & OTF_FLAG_INIT) {
chunk_len = 0;
dstblk = otfd->part->start;
otfd->flags &= ~OTF_FLAG_INIT;
}
chunk_len += otfd->len;
/* The flush flag is set when the download process has finished
* meaning we must write the remaining bytes in RAM to the storage
* media. After this, we must quit the function. */
if (otfd->flags & OTF_FLAG_FLUSH) {
/* Write chunk with remaining bytes */
if (chunk_len) {
if (write_chunk(mmc, otfd, dstblk, chunk_len))
return -1;
}
/* Reset all static variables if offset == 0 (starting chunk) */
chunk_len = 0;
dstblk = 0;
return 0;
}
if (chunk_len >= CONFIG_OTF_CHUNK) {
unsigned int remaining;
/* We have CONFIG_OTF_CHUNK (or more) bytes in RAM.
* Let's proceed to write as many as multiples of blksz
* as possible.
*/
remaining = chunk_len % mmc_dev->blksz;
chunk_len -= remaining; /* chunk_len is now multiple of blksz */
if (write_chunk(mmc, otfd, dstblk, chunk_len))
return -1;
/* increment destiny block */
dstblk += (chunk_len / mmc_dev->blksz);
/* copy excess of bytes from previous chunk to offset 0 */
if (remaining) {
memcpy((void *)otfd->loadaddr,
(void *)(otfd->loadaddr + chunk_len),
remaining);
debug("Copying excess of %d bytes to offset 0\n",
remaining);
}
/* reset chunk_len to excess of bytes from previous chunk
* (or zero, if that's the case) */
chunk_len = remaining;
}
/* Set otfd offset pointer to offset in RAM where new bytes would
* be written. This offset may be reused by caller */
otfd->offset = chunk_len;
return 0;
}
#if 0
static int do_updatefile(cmd_tbl_t* cmdtp, int flag, int argc,
char * const argv[])
{
disk_partition_t info;
char *targetfilename = NULL;
char *targetfs = NULL;
const char *default_fs = "fat";
int part;
int i;
char *supported_fs[] = {
#ifdef CONFIG_FAT_WRITE
"fat",
#endif
#ifdef CONFIG_EXT4_WRITE
"ext4",
#endif
};
char dev_index_str[2];
struct load_fw fwinfo;
if (argc < 2)
return CMD_RET_USAGE;
memset(&fwinfo, 0, sizeof(fwinfo));
if (init_mmc_globals())
return CMD_RET_FAILURE;
/* Get data of partition to be updated */
sprintf(dev_index_str, "%d", mmc_dev_index);
part = get_partition_bynameorindex(CONFIG_SYS_STORAGE_MEDIA,
dev_index_str, argv[1], &info);
if (part < 0) {
printf("Error: partition '%s' not found\n", argv[1]);
return CMD_RET_FAILURE;
}
/* Get source of update firmware file */
if (get_source(argc, argv, &fwinfo))
return CMD_RET_FAILURE;
/* Get file name */
if (get_arg_src(argc, argv, fwinfo.src, 2, &fwinfo.filename)) {
printf("Error: need a filename\n");
return CMD_RET_USAGE;
}
/* Get target file name. If not provided use fwinfo.filename by default */
if (get_arg_src(argc, argv, fwinfo.src, 3, &targetfilename))
targetfilename = fwinfo.filename;
/* Get target filesystem. If not provided use 'fat' by default */
if (get_arg_src(argc, argv, fwinfo.src, 4, &targetfs))
targetfs = (char *)default_fs;
/* Check target fs is supported */
for (i = 0; i < ARRAY_SIZE(supported_fs); i++)
if (!strcmp(targetfs, supported_fs[i]))
break;
if (i >= ARRAY_SIZE(supported_fs)) {
printf("Error: target file system '%s' is unsupported for "
"write operation.\n"
"Valid file systems are: ", targetfs);
for (i = 0; i < ARRAY_SIZE(supported_fs); i++)
printf("%s ", supported_fs[i]);
printf("\n");
return CMD_RET_FAILURE;
}
/* Load firmware file to RAM */
fwinfo.loadaddr = "$loadaddr";
if (LDFW_ERROR == load_firmware(&fwinfo)) {
printf("Error loading firmware file to RAM\n");
return CMD_RET_FAILURE;
}
/* Write file from RAM to storage partition */
if (write_file(targetfilename, targetfs, part)) {
printf("Error writing file\n");
return CMD_RET_FAILURE;
}
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
updatefile, 8, 0, do_updatefile,
"i2SOM modules updatefile command",
"<partition> [source] [extra-args...]\n"
" Description: updates/writes a file in <partition> in $mmcdev via\n"
" <source>\n"
" Arguments:\n"
" - partition: a partition index or a GUID partition name where\n"
" to upload the file\n"
" - [source]: " CONFIG_UPDATE_SUPPORTED_SOURCES_LIST "\n"
" - [extra-args]: extra arguments depending on 'source'\n"
"\n"
CONFIG_UPDATEFILE_SUPPORTED_SOURCES_ARGS_HELP
);
#endif

View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2017 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version2 as published by
* the Free Software Foundation.
*/
#include <common.h>
#include <mmc.h>
#include <environment.h>
#include <malloc.h>
extern int mmc_get_bootdevindex(void);
/*
* Common function to get the block size of the storage media.
*/
size_t media_get_block_size(void)
{
size_t block_size = 0;
struct mmc *mmc;
mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (mmc)
block_size = mmc->block_dev.blksz;
return block_size;
}
/*
* Get the offset of a partition in the mmc
* @in: Partition name
* @in: Offset of the partition in mmc block units
* return 0 if success
*/
int get_partition_offset(char *part_name, u32 *offset)
{
disk_partition_t info;
char dev_index_str[2];
int r;
sprintf(dev_index_str, "%d", mmc_get_bootdevindex());
r = get_partition_bynameorindex(CONFIG_SYS_STORAGE_MEDIA,
dev_index_str,
part_name,
&info);
if (r < 0)
return r;
*offset = info.start;
return 0;
}
/*
* Read a data block from the storage media.
* This function only reads one mmc block
* @in: Address in media (must be aligned to block size)
* @in: Read buffer
* @in: Partition index, only applies for MMC
* The function returns:
* 0 if success and data in readbuf.
* -1 on error
*/
int media_read_block(u32 addr, unsigned char *readbuf, uint hwpart)
{
size_t len;
size_t nbytes;
int ret = -1;
struct mmc *mmc;
uint orig_part;
u32 loadaddr = getenv_ulong("loadaddr", 16, load_addr);
len = media_get_block_size();
if (len <= 0)
return ret;
mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc)
return ret;
//orig_part = mmc->part_num;
if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, hwpart))
return ret;
nbytes = mmc->block_dev.block_read(CONFIG_SYS_MMC_ENV_DEV,
addr,
1,
(void *)loadaddr);
if (nbytes == 1) {
memcpy(readbuf, (const void *)loadaddr, len);
ret = 0;
}
//mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, orig_part);
return ret;
}
/*
* Write a data block to the storage media.
* This function only writes the minimum required amount of data:
* for mmc: one block (probably 512 bytes)
* @in: Address in media (must be aligned to block size)
* @in: Write buffer
* @in: Partition index, only applies for MMC
* The function returns:
* 0 if success
* -1 on error
*/
int media_write_block(u32 addr, unsigned char *writebuf, uint hwpart)
{
size_t len;
int ret = -1;
struct mmc *mmc;
unsigned long written;
uint orig_part;
len = media_get_block_size();
if (len <= 0)
return ret;
mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc)
return ret;
//orig_part = mmc->part_num;
if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, hwpart))
return ret;
written = mmc->block_dev.block_write(CONFIG_SYS_MMC_ENV_DEV,
addr,
1,
writebuf);
if (written == 1)
ret = 0;
//mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, orig_part);
return ret;
}
/*
* Erase data in the storage media.
* This function only erases the minimum required amount of data:
* for mmc: one block (probably 512 bytes)
* @in: Address in media (must be aligned to block size)
* @in: Partition index, only applies for MMC
*/
void media_erase_fskey(u32 addr, uint hwpart)
{
struct mmc *mmc;
unsigned char *zero_buf;
uint orig_part = 0;
zero_buf = calloc(1, media_get_block_size());
if (!zero_buf)
return;
mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
if (!mmc)
return;
//orig_part = mmc->part_num;
if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, hwpart))
return;
/*
* Do not use block_erase, it uses different erase ranges
* and will erase the full environment.
*/
media_write_block(addr, zero_buf, mmc_get_env_part(mmc));
//mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, orig_part);
}
uint get_env_hwpart(void)
{
struct mmc *mmc;
mmc = find_mmc_device(mmc_get_bootdevindex());
return mmc_get_env_part(mmc);
}