1
0
Fork 0

Merge branch 'master' of git://git.denx.de/u-boot-mmc

utp
Tom Rini 2014-05-23 08:13:59 -04:00
commit 638b3e8342
19 changed files with 1045 additions and 401 deletions

10
README
View File

@ -1534,6 +1534,16 @@ The following options need to be configured:
CONFIG_SH_MMCIF_CLK
Define the clock frequency for MMCIF
CONFIG_GENERIC_MMC
Enable the generic MMC driver
CONFIG_SUPPORT_EMMC_BOOT
Enable some additional features of the eMMC boot partitions.
CONFIG_SUPPORT_EMMC_RPMB
Enable the commands for reading, writing and programming the
key for the Replay Protection Memory Block partition in eMMC.
- USB Device Firmware Update (DFU) class support:
CONFIG_DFU_FUNCTION
This enables the USB portion of the DFU USB class

View File

@ -19,6 +19,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/mmc_host_def.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <i2c.h>
@ -214,3 +215,9 @@ int board_eth_init(bd_t *bis)
return rv;
}
#endif /* CONFIG_DRIVER_TI_CPSW */
#if defined(CONFIG_GENERIC_MMC) && !defined(CONFIG_SPL_BUILD)
int board_mmc_init(bd_t *bis)
{
return omap_mmc_init(1, 0, 0, -1, -1);
}
#endif

View File

@ -33,15 +33,8 @@ static int confirm_prog(void)
"what you are doing!\n"
"\nReally perform this fuse programming? <y/N>\n");
if (getc() == 'y') {
int c;
putc('y');
c = getc();
putc('\n');
if (c == '\r')
return 1;
}
if (confirm_yesno())
return 1;
puts("Fuse programming aborted\n");
return 0;

View File

@ -71,12 +71,6 @@ U_BOOT_CMD(
);
#else /* !CONFIG_GENERIC_MMC */
enum mmc_state {
MMC_INVALID,
MMC_READ,
MMC_WRITE,
MMC_ERASE,
};
static void print_mmcinfo(struct mmc *mmc)
{
printf("Device: %s\n", mmc->cfg->name);
@ -98,7 +92,18 @@ static void print_mmcinfo(struct mmc *mmc)
printf("Bus Width: %d-bit\n", mmc->bus_width);
}
static struct mmc *init_mmc_device(int dev)
{
struct mmc *mmc;
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return NULL;
}
if (mmc_init(mmc))
return NULL;
return mmc;
}
static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct mmc *mmc;
@ -112,351 +117,537 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
}
mmc = find_mmc_device(curr_device);
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
if (mmc) {
mmc_init(mmc);
print_mmcinfo(mmc);
return 0;
} else {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
print_mmcinfo(mmc);
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
mmcinfo, 1, 0, do_mmcinfo,
"display MMC info",
"- display info of the current MMC device"
);
#ifdef CONFIG_SUPPORT_EMMC_RPMB
static int confirm_key_prog(void)
{
puts("Warning: Programming authentication key can be done only once !\n"
" Use this command only if you are sure of what you are doing,\n"
"Really perform the key programming? <y/N> ");
if (confirm_yesno())
return 1;
puts("Authentication key programming aborted\n");
return 0;
}
static int do_mmcrpmb_key(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
void *key_addr;
struct mmc *mmc = find_mmc_device(curr_device);
if (argc != 2)
return CMD_RET_USAGE;
key_addr = (void *)simple_strtoul(argv[1], NULL, 16);
if (!confirm_key_prog())
return CMD_RET_FAILURE;
if (mmc_rpmb_set_key(mmc, key_addr)) {
printf("ERROR - Key already programmed ?\n");
return CMD_RET_FAILURE;
}
return CMD_RET_SUCCESS;
}
static int do_mmcrpmb_read(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
u16 blk, cnt;
void *addr;
int n;
void *key_addr = NULL;
struct mmc *mmc = find_mmc_device(curr_device);
if (argc < 4)
return CMD_RET_USAGE;
addr = (void *)simple_strtoul(argv[1], NULL, 16);
blk = simple_strtoul(argv[2], NULL, 16);
cnt = simple_strtoul(argv[3], NULL, 16);
if (argc == 5)
key_addr = (void *)simple_strtoul(argv[4], NULL, 16);
printf("\nMMC RPMB read: dev # %d, block # %d, count %d ... ",
curr_device, blk, cnt);
n = mmc_rpmb_read(mmc, addr, blk, cnt, key_addr);
printf("%d RPMB blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
if (n != cnt)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
static int do_mmcrpmb_write(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
u16 blk, cnt;
void *addr;
int n;
void *key_addr;
struct mmc *mmc = find_mmc_device(curr_device);
if (argc != 5)
return CMD_RET_USAGE;
addr = (void *)simple_strtoul(argv[1], NULL, 16);
blk = simple_strtoul(argv[2], NULL, 16);
cnt = simple_strtoul(argv[3], NULL, 16);
key_addr = (void *)simple_strtoul(argv[4], NULL, 16);
printf("\nMMC RPMB write: dev # %d, block # %d, count %d ... ",
curr_device, blk, cnt);
n = mmc_rpmb_write(mmc, addr, blk, cnt, key_addr);
printf("%d RPMB blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
if (n != cnt)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
static int do_mmcrpmb_counter(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
unsigned long counter;
struct mmc *mmc = find_mmc_device(curr_device);
if (mmc_rpmb_get_counter(mmc, &counter))
return CMD_RET_FAILURE;
printf("RPMB Write counter= %lx\n", counter);
return CMD_RET_SUCCESS;
}
static cmd_tbl_t cmd_rpmb[] = {
U_BOOT_CMD_MKENT(key, 2, 0, do_mmcrpmb_key, "", ""),
U_BOOT_CMD_MKENT(read, 5, 1, do_mmcrpmb_read, "", ""),
U_BOOT_CMD_MKENT(write, 5, 0, do_mmcrpmb_write, "", ""),
U_BOOT_CMD_MKENT(counter, 1, 1, do_mmcrpmb_counter, "", ""),
};
static int do_mmcrpmb(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
cmd_tbl_t *cp;
struct mmc *mmc;
char original_part;
int ret;
cp = find_cmd_tbl(argv[1], cmd_rpmb, ARRAY_SIZE(cmd_rpmb));
/* Drop the rpmb subcommand */
argc--;
argv++;
if (cp == NULL || argc > cp->maxargs)
return CMD_RET_USAGE;
if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
return CMD_RET_SUCCESS;
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
if (!(mmc->version & MMC_VERSION_MMC)) {
printf("It is not a EMMC device\n");
return CMD_RET_FAILURE;
}
if (mmc->version < MMC_VERSION_4_41) {
printf("RPMB not supported before version 4.41\n");
return CMD_RET_FAILURE;
}
/* Switch to the RPMB partition */
original_part = mmc->part_num;
if (mmc->part_num != MMC_PART_RPMB) {
if (mmc_switch_part(curr_device, MMC_PART_RPMB) != 0)
return CMD_RET_FAILURE;
mmc->part_num = MMC_PART_RPMB;
}
ret = cp->cmd(cmdtp, flag, argc, argv);
/* Return to original partition */
if (mmc->part_num != original_part) {
if (mmc_switch_part(curr_device, original_part) != 0)
return CMD_RET_FAILURE;
mmc->part_num = original_part;
}
return ret;
}
#endif
static int do_mmc_read(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct mmc *mmc;
u32 blk, cnt, n;
void *addr;
if (argc != 4)
return CMD_RET_USAGE;
addr = (void *)simple_strtoul(argv[1], NULL, 16);
blk = simple_strtoul(argv[2], NULL, 16);
cnt = simple_strtoul(argv[3], NULL, 16);
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
printf("\nMMC read: dev # %d, block # %d, count %d ... ",
curr_device, blk, cnt);
n = mmc->block_dev.block_read(curr_device, blk, cnt, addr);
/* flush cache after read */
flush_cache((ulong)addr, cnt * 512); /* FIXME */
printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
static int do_mmc_write(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct mmc *mmc;
u32 blk, cnt, n;
void *addr;
if (argc != 4)
return CMD_RET_USAGE;
addr = (void *)simple_strtoul(argv[1], NULL, 16);
blk = simple_strtoul(argv[2], NULL, 16);
cnt = simple_strtoul(argv[3], NULL, 16);
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
printf("\nMMC write: dev # %d, block # %d, count %d ... ",
curr_device, blk, cnt);
if (mmc_getwp(mmc) == 1) {
printf("Error: card is write protected!\n");
return CMD_RET_FAILURE;
}
n = mmc->block_dev.block_write(curr_device, blk, cnt, addr);
printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
static int do_mmc_erase(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct mmc *mmc;
u32 blk, cnt, n;
if (argc != 3)
return CMD_RET_USAGE;
blk = simple_strtoul(argv[1], NULL, 16);
cnt = simple_strtoul(argv[2], NULL, 16);
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
printf("\nMMC erase: dev # %d, block # %d, count %d ... ",
curr_device, blk, cnt);
if (mmc_getwp(mmc) == 1) {
printf("Error: card is write protected!\n");
return CMD_RET_FAILURE;
}
n = mmc->block_dev.block_erase(curr_device, blk, cnt);
printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
}
static int do_mmc_rescan(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct mmc *mmc;
mmc = find_mmc_device(curr_device);
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return CMD_RET_FAILURE;
}
mmc->has_init = 0;
if (mmc_init(mmc))
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
static int do_mmc_part(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
block_dev_desc_t *mmc_dev;
struct mmc *mmc;
mmc = init_mmc_device(curr_device);
if (!mmc)
return CMD_RET_FAILURE;
mmc_dev = mmc_get_dev(curr_device);
if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
print_part(mmc_dev);
return CMD_RET_SUCCESS;
}
puts("get mmc type error!\n");
return CMD_RET_FAILURE;
}
static int do_mmc_dev(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int dev, part = -1, ret;
struct mmc *mmc;
if (argc == 1) {
dev = curr_device;
} else if (argc == 2) {
dev = simple_strtoul(argv[1], NULL, 10);
} else if (argc == 3) {
dev = (int)simple_strtoul(argv[1], NULL, 10);
part = (int)simple_strtoul(argv[2], NULL, 10);
if (part > PART_ACCESS_MASK) {
printf("#part_num shouldn't be larger than %d\n",
PART_ACCESS_MASK);
return CMD_RET_FAILURE;
}
} else {
return CMD_RET_USAGE;
}
mmc = init_mmc_device(dev);
if (!mmc)
return CMD_RET_FAILURE;
if (part != -1) {
ret = mmc_select_hwpart(dev, part);
printf("switch to partitions #%d, %s\n",
part, (!ret) ? "OK" : "ERROR");
if (ret)
return 1;
}
curr_device = dev;
if (mmc->part_config == MMCPART_NOAVAILABLE)
printf("mmc%d is current device\n", curr_device);
else
printf("mmc%d(part %d) is current device\n",
curr_device, mmc->part_num);
return CMD_RET_SUCCESS;
}
static int do_mmc_list(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
print_mmc_devices('\n');
return CMD_RET_SUCCESS;
}
#ifdef CONFIG_SUPPORT_EMMC_BOOT
static int do_mmc_bootbus(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int dev;
struct mmc *mmc;
u8 width, reset, mode;
if (argc != 5)
return CMD_RET_USAGE;
dev = simple_strtoul(argv[1], NULL, 10);
width = simple_strtoul(argv[2], NULL, 10);
reset = simple_strtoul(argv[3], NULL, 10);
mode = simple_strtoul(argv[4], NULL, 10);
mmc = init_mmc_device(dev);
if (!mmc)
return CMD_RET_FAILURE;
if (IS_SD(mmc)) {
puts("BOOT_BUS_WIDTH only exists on eMMC\n");
return CMD_RET_FAILURE;
}
/* acknowledge to be sent during boot operation */
return mmc_set_boot_bus_width(mmc, width, reset, mode);
}
static int do_mmc_boot_resize(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int dev;
struct mmc *mmc;
u32 bootsize, rpmbsize;
if (argc != 4)
return CMD_RET_USAGE;
dev = simple_strtoul(argv[1], NULL, 10);
bootsize = simple_strtoul(argv[2], NULL, 10);
rpmbsize = simple_strtoul(argv[3], NULL, 10);
mmc = init_mmc_device(dev);
if (!mmc)
return CMD_RET_FAILURE;
if (IS_SD(mmc)) {
printf("It is not a EMMC device\n");
return CMD_RET_FAILURE;
}
if (mmc_boot_partition_size_change(mmc, bootsize, rpmbsize)) {
printf("EMMC boot partition Size change Failed.\n");
return CMD_RET_FAILURE;
}
printf("EMMC boot partition Size %d MB\n", bootsize);
printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
return CMD_RET_SUCCESS;
}
static int do_mmc_partconf(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int dev;
struct mmc *mmc;
u8 ack, part_num, access;
if (argc != 5)
return CMD_RET_USAGE;
dev = simple_strtoul(argv[1], NULL, 10);
ack = simple_strtoul(argv[2], NULL, 10);
part_num = simple_strtoul(argv[3], NULL, 10);
access = simple_strtoul(argv[4], NULL, 10);
mmc = init_mmc_device(dev);
if (!mmc)
return CMD_RET_FAILURE;
if (IS_SD(mmc)) {
puts("PARTITION_CONFIG only exists on eMMC\n");
return CMD_RET_FAILURE;
}
/* acknowledge to be sent during boot operation */
return mmc_set_part_conf(mmc, ack, part_num, access);
}
static int do_mmc_rst_func(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
int dev;
struct mmc *mmc;
u8 enable;
/*
* Set the RST_n_ENABLE bit of RST_n_FUNCTION
* The only valid values are 0x0, 0x1 and 0x2 and writing
* a value of 0x1 or 0x2 sets the value permanently.
*/
if (argc != 3)
return CMD_RET_USAGE;
dev = simple_strtoul(argv[1], NULL, 10);
enable = simple_strtoul(argv[2], NULL, 10);
if (enable > 2 || enable < 0) {
puts("Invalid RST_n_ENABLE value\n");
return CMD_RET_USAGE;
}
mmc = init_mmc_device(dev);
if (!mmc)
return CMD_RET_FAILURE;
if (IS_SD(mmc)) {
puts("RST_n_FUNCTION only exists on eMMC\n");
return CMD_RET_FAILURE;
}
return mmc_set_rst_n_function(mmc, enable);
}
#endif
static int do_mmc_setdsr(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
struct mmc *mmc;
u32 val;
int ret;
if (argc != 2)
return CMD_RET_USAGE;
val = simple_strtoul(argv[2], NULL, 16);
mmc = find_mmc_device(curr_device);
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return CMD_RET_FAILURE;
}
ret = mmc_set_dsr(mmc, val);
printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
if (!ret) {
mmc->has_init = 0;
if (mmc_init(mmc))
return CMD_RET_FAILURE;
else
return CMD_RET_SUCCESS;
}
return ret;
}
static cmd_tbl_t cmd_mmc[] = {
U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""),
U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""),
U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""),
U_BOOT_CMD_MKENT(part, 1, 1, do_mmc_part, "", ""),
U_BOOT_CMD_MKENT(dev, 3, 0, do_mmc_dev, "", ""),
U_BOOT_CMD_MKENT(list, 1, 1, do_mmc_list, "", ""),
#ifdef CONFIG_SUPPORT_EMMC_BOOT
U_BOOT_CMD_MKENT(bootbus, 5, 0, do_mmc_bootbus, "", ""),
U_BOOT_CMD_MKENT(bootpart-resize, 3, 0, do_mmc_boot_resize, "", ""),
U_BOOT_CMD_MKENT(partconf, 5, 0, do_mmc_partconf, "", ""),
U_BOOT_CMD_MKENT(rst-function, 3, 0, do_mmc_rst_func, "", ""),
#endif
#ifdef CONFIG_SUPPORT_EMMC_RPMB
U_BOOT_CMD_MKENT(rpmb, CONFIG_SYS_MAXARGS, 1, do_mmcrpmb, "", ""),
#endif
U_BOOT_CMD_MKENT(setdsr, 2, 0, do_mmc_setdsr, "", ""),
};
static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
enum mmc_state state;
cmd_tbl_t *cp;
if (argc < 2)
cp = find_cmd_tbl(argv[1], cmd_mmc, ARRAY_SIZE(cmd_mmc));
/* Drop the mmc command */
argc--;
argv++;
if (cp == NULL || argc > cp->maxargs)
return CMD_RET_USAGE;
if (flag == CMD_FLAG_REPEAT && !cp->repeatable)
return CMD_RET_SUCCESS;
if (curr_device < 0) {
if (get_mmc_num() > 0)
if (get_mmc_num() > 0) {
curr_device = 0;
else {
} else {
puts("No MMC device available\n");
return 1;
return CMD_RET_FAILURE;
}
}
if (strcmp(argv[1], "rescan") == 0) {
struct mmc *mmc;
if (argc != 2)
return CMD_RET_USAGE;
mmc = find_mmc_device(curr_device);
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
mmc->has_init = 0;
if (mmc_init(mmc))
return 1;
else
return 0;
} else if (strcmp(argv[1], "part") == 0) {
block_dev_desc_t *mmc_dev;
struct mmc *mmc;
if (argc != 2)
return CMD_RET_USAGE;
mmc = find_mmc_device(curr_device);
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
mmc_init(mmc);
mmc_dev = mmc_get_dev(curr_device);
if (mmc_dev != NULL &&
mmc_dev->type != DEV_TYPE_UNKNOWN) {
print_part(mmc_dev);
return 0;
}
puts("get mmc type error!\n");
return 1;
} else if (strcmp(argv[1], "list") == 0) {
if (argc != 2)
return CMD_RET_USAGE;
print_mmc_devices('\n');
return 0;
} else if (strcmp(argv[1], "dev") == 0) {
int dev, part = -1;
struct mmc *mmc;
if (argc == 2)
dev = curr_device;
else if (argc == 3)
dev = simple_strtoul(argv[2], NULL, 10);
else if (argc == 4) {
dev = (int)simple_strtoul(argv[2], NULL, 10);
part = (int)simple_strtoul(argv[3], NULL, 10);
if (part > PART_ACCESS_MASK) {
printf("#part_num shouldn't be larger"
" than %d\n", PART_ACCESS_MASK);
return 1;
}
} else
return CMD_RET_USAGE;
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return 1;
}
mmc_init(mmc);
if (part != -1) {
int ret;
if (mmc->part_config == MMCPART_NOAVAILABLE) {
printf("Card doesn't support part_switch\n");
return 1;
}
if (part != mmc->part_num) {
ret = mmc_switch_part(dev, part);
if (!ret)
mmc->part_num = part;
printf("switch to partitions #%d, %s\n",
part, (!ret) ? "OK" : "ERROR");
}
}
curr_device = dev;
if (mmc->part_config == MMCPART_NOAVAILABLE)
printf("mmc%d is current device\n", curr_device);
else
printf("mmc%d(part %d) is current device\n",
curr_device, mmc->part_num);
return 0;
#ifdef CONFIG_SUPPORT_EMMC_BOOT
} else if (strcmp(argv[1], "partconf") == 0) {
int dev;
struct mmc *mmc;
u8 ack, part_num, access;
if (argc == 6) {
dev = simple_strtoul(argv[2], NULL, 10);
ack = simple_strtoul(argv[3], NULL, 10);
part_num = simple_strtoul(argv[4], NULL, 10);
access = simple_strtoul(argv[5], NULL, 10);
} else {
return CMD_RET_USAGE;
}
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return 1;
}
if (IS_SD(mmc)) {
puts("PARTITION_CONFIG only exists on eMMC\n");
return 1;
}
/* acknowledge to be sent during boot operation */
return mmc_set_part_conf(mmc, ack, part_num, access);
} else if (strcmp(argv[1], "bootbus") == 0) {
int dev;
struct mmc *mmc;
u8 width, reset, mode;
if (argc == 6) {
dev = simple_strtoul(argv[2], NULL, 10);
width = simple_strtoul(argv[3], NULL, 10);
reset = simple_strtoul(argv[4], NULL, 10);
mode = simple_strtoul(argv[5], NULL, 10);
} else {
return CMD_RET_USAGE;
}
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return 1;
}
if (IS_SD(mmc)) {
puts("BOOT_BUS_WIDTH only exists on eMMC\n");
return 1;
}
/* acknowledge to be sent during boot operation */
return mmc_set_boot_bus_width(mmc, width, reset, mode);
} else if (strcmp(argv[1], "bootpart-resize") == 0) {
int dev;
struct mmc *mmc;
u32 bootsize, rpmbsize;
if (argc == 5) {
dev = simple_strtoul(argv[2], NULL, 10);
bootsize = simple_strtoul(argv[3], NULL, 10);
rpmbsize = simple_strtoul(argv[4], NULL, 10);
} else {
return CMD_RET_USAGE;
}
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return 1;
}
if (IS_SD(mmc)) {
printf("It is not a EMMC device\n");
return 1;
}
if (0 == mmc_boot_partition_size_change(mmc,
bootsize, rpmbsize)) {
printf("EMMC boot partition Size %d MB\n", bootsize);
printf("EMMC RPMB partition Size %d MB\n", rpmbsize);
return 0;
} else {
printf("EMMC boot partition Size change Failed.\n");
return 1;
}
} else if (strcmp(argv[1], "rst-function") == 0) {
/*
* Set the RST_n_ENABLE bit of RST_n_FUNCTION
* The only valid values are 0x0, 0x1 and 0x2 and writing
* a value of 0x1 or 0x2 sets the value permanently.
*/
int dev;
struct mmc *mmc;
u8 enable;
if (argc == 4) {
dev = simple_strtoul(argv[2], NULL, 10);
enable = simple_strtoul(argv[3], NULL, 10);
} else {
return CMD_RET_USAGE;
}
if (enable > 2 || enable < 0) {
puts("Invalid RST_n_ENABLE value\n");
return CMD_RET_USAGE;
}
mmc = find_mmc_device(dev);
if (!mmc) {
printf("no mmc device at slot %x\n", dev);
return 1;
}
if (IS_SD(mmc)) {
puts("RST_n_FUNCTION only exists on eMMC\n");
return 1;
}
return mmc_set_rst_n_function(mmc, enable);
#endif /* CONFIG_SUPPORT_EMMC_BOOT */
}
else if (argc == 3 && strcmp(argv[1], "setdsr") == 0) {
struct mmc *mmc = find_mmc_device(curr_device);
u32 val = simple_strtoul(argv[2], NULL, 16);
int ret;
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
ret = mmc_set_dsr(mmc, val);
printf("set dsr %s\n", (!ret) ? "OK, force rescan" : "ERROR");
if (!ret) {
mmc->has_init = 0;
if (mmc_init(mmc))
return 1;
else
return 0;
}
return ret;
}
state = MMC_INVALID;
if (argc == 5 && strcmp(argv[1], "read") == 0)
state = MMC_READ;
else if (argc == 5 && strcmp(argv[1], "write") == 0)
state = MMC_WRITE;
else if (argc == 4 && strcmp(argv[1], "erase") == 0)
state = MMC_ERASE;
if (state != MMC_INVALID) {
struct mmc *mmc = find_mmc_device(curr_device);
int idx = 2;
u32 blk, cnt, n;
void *addr;
if (state != MMC_ERASE) {
addr = (void *)simple_strtoul(argv[idx], NULL, 16);
++idx;
} else
addr = NULL;
blk = simple_strtoul(argv[idx], NULL, 16);
cnt = simple_strtoul(argv[idx + 1], NULL, 16);
if (!mmc) {
printf("no mmc device at slot %x\n", curr_device);
return 1;
}
printf("\nMMC %s: dev # %d, block # %d, count %d ... ",
argv[1], curr_device, blk, cnt);
mmc_init(mmc);
if ((state == MMC_WRITE || state == MMC_ERASE)) {
if (mmc_getwp(mmc) == 1) {
printf("Error: card is write protected!\n");
return 1;
}
}
switch (state) {
case MMC_READ:
n = mmc->block_dev.block_read(curr_device, blk,
cnt, addr);
/* flush cache after read */
flush_cache((ulong)addr, cnt * 512); /* FIXME */
break;
case MMC_WRITE:
n = mmc->block_dev.block_write(curr_device, blk,
cnt, addr);
break;
case MMC_ERASE:
n = mmc->block_dev.block_erase(curr_device, blk, cnt);
break;
default:
BUG();
}
printf("%d blocks %s: %s\n",
n, argv[1], (n == cnt) ? "OK" : "ERROR");
return (n == cnt) ? 0 : 1;
}
return CMD_RET_USAGE;
return cp->cmd(cmdtp, flag, argc, argv);
}
U_BOOT_CMD(
mmc, 6, 1, do_mmcops,
mmc, 7, 1, do_mmcops,
"MMC sub system",
"read addr blk# cnt\n"
"info - display info of the current MMC device\n"
"mmc read addr blk# cnt\n"
"mmc write addr blk# cnt\n"
"mmc erase blk# cnt\n"
"mmc rescan\n"
@ -474,6 +665,20 @@ U_BOOT_CMD(
" - Change the RST_n_FUNCTION field of the specified device\n"
" WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.\n"
#endif
"mmc setdsr - set DSR register value\n"
#ifdef CONFIG_SUPPORT_EMMC_RPMB
"mmc rpmb read addr blk# cnt [address of auth-key] - block size is 256 bytes\n"
"mmc rpmb write addr blk# cnt <address of auth-key> - block size is 256 bytes\n"
"mmc rpmb key <address of auth-key> - program the RPMB authentication key.\n"
"mmc rpmb counter - read the value of the write counter\n"
#endif
"mmc setdsr <value> - set DSR register value\n"
);
/* Old command kept for compatibility. Same as 'mmc info' */
U_BOOT_CMD(
mmcinfo, 1, 0, do_mmcinfo,
"display MMC info",
"- display info of the current MMC device"
);
#endif /* !CONFIG_GENERIC_MMC */

View File

@ -605,22 +605,16 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
opts.spread = spread;
if (scrub) {
if (!scrub_yes)
puts(scrub_warn);
if (scrub_yes)
if (scrub_yes) {
opts.scrub = 1;
else if (getc() == 'y') {
puts("y");
if (getc() == '\r')
} else {
puts(scrub_warn);
if (confirm_yesno()) {
opts.scrub = 1;
else {
} else {
puts("scrub aborted\n");
return 1;
}
} else {
puts("scrub aborted\n");
return 1;
}
}
ret = nand_erase_opts(nand, &opts);

View File

@ -158,21 +158,9 @@ int do_otp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
lowup(half + count - 1), page + (half + count - 1) / 2,
half + count
);
i = 0;
while (1) {
if (tstc()) {
const char exp_ans[] = "YES\r";
char c;
putc(c = getc());
if (exp_ans[i++] != c) {
printf(" Aborting\n");
return 1;
} else if (!exp_ans[i]) {
puts("\n");
break;
}
}
if (!confirm_yesno()) {
printf(" Aborting\n");
return 1;
}
}

View File

@ -82,7 +82,7 @@ int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
U_BOOT_CMD(
part, 5, 1, do_part,
"disk partition related commands",
"uuid <interface> <dev>:<part>\n"
"part uuid <interface> <dev>:<part>\n"
" - print partition UUID\n"
"part uuid <interface> <dev>:<part> <varname>\n"
" - set environment variable to partition UUID\n"

View File

@ -537,7 +537,33 @@ int ctrlc(void)
}
return 0;
}
/* Reads user's confirmation.
Returns 1 if user's input is "y", "Y", "yes" or "YES"
*/
int confirm_yesno(void)
{
int i;
char str_input[5];
/* Flush input */
while (tstc())
getc();
i = 0;
while (i < sizeof(str_input)) {
str_input[i] = getc();
putc(str_input[i]);
if (str_input[i] == '\r')
break;
i++;
}
putc('\n');
if (strncmp(str_input, "y\r", 2) == 0 ||
strncmp(str_input, "Y\r", 2) == 0 ||
strncmp(str_input, "yes\r", 4) == 0 ||
strncmp(str_input, "YES\r", 4) == 0)
return 1;
return 0;
}
/* pass 1 to disable ctrlc() checking, 0 to enable.
* returns previous state
*/

View File

@ -22,6 +22,7 @@
struct block_drvr {
char *name;
block_dev_desc_t* (*get_dev)(int dev);
int (*select_hwpart)(int dev_num, int hwpart);
};
static const struct block_drvr block_drvr[] = {
@ -38,7 +39,11 @@ static const struct block_drvr block_drvr[] = {
{ .name = "usb", .get_dev = usb_stor_get_dev, },
#endif
#if defined(CONFIG_MMC)
{ .name = "mmc", .get_dev = mmc_get_dev, },
{
.name = "mmc",
.get_dev = mmc_get_dev,
.select_hwpart = mmc_select_hwpart,
},
#endif
#if defined(CONFIG_SYSTEMACE)
{ .name = "ace", .get_dev = systemace_get_dev, },
@ -52,11 +57,13 @@ static const struct block_drvr block_drvr[] = {
DECLARE_GLOBAL_DATA_PTR;
#ifdef HAVE_BLOCK_DEVICE
block_dev_desc_t *get_dev(const char *ifname, int dev)
block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
const struct block_drvr *drvr = block_drvr;
block_dev_desc_t* (*reloc_get_dev)(int dev);
int (*select_hwpart)(int dev_num, int hwpart);
char *name;
int ret;
if (!ifname)
return NULL;
@ -68,17 +75,41 @@ block_dev_desc_t *get_dev(const char *ifname, int dev)
while (drvr->name) {
name = drvr->name;
reloc_get_dev = drvr->get_dev;
select_hwpart = drvr->select_hwpart;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
name += gd->reloc_off;
reloc_get_dev += gd->reloc_off;
if (select_hwpart)
select_hwpart += gd->reloc_off;
#endif
if (strncmp(ifname, name, strlen(name)) == 0)
return reloc_get_dev(dev);
if (strncmp(ifname, name, strlen(name)) == 0) {
block_dev_desc_t *dev_desc = reloc_get_dev(dev);
if (!dev_desc)
return NULL;
if (hwpart == -1)
return dev_desc;
if (!select_hwpart)
return NULL;
ret = select_hwpart(dev_desc->dev, hwpart);
if (ret < 0)
return NULL;
return dev_desc;
}
drvr++;
}
return NULL;
}
block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return get_dev_hwpart(ifname, dev, -1);
}
#else
block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
return NULL;
}
block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return NULL;
@ -413,25 +444,52 @@ int get_partition_info(block_dev_desc_t *dev_desc, int part
return -1;
}
int get_device(const char *ifname, const char *dev_str,
int get_device(const char *ifname, const char *dev_hwpart_str,
block_dev_desc_t **dev_desc)
{
char *ep;
int dev;
char *dup_str = NULL;
const char *dev_str, *hwpart_str;
int dev, hwpart;
hwpart_str = strchr(dev_hwpart_str, '.');
if (hwpart_str) {
dup_str = strdup(dev_hwpart_str);
dup_str[hwpart_str - dev_hwpart_str] = 0;
dev_str = dup_str;
hwpart_str++;
} else {
dev_str = dev_hwpart_str;
hwpart = -1;
}
dev = simple_strtoul(dev_str, &ep, 16);
if (*ep) {
printf("** Bad device specification %s %s **\n",
ifname, dev_str);
return -1;
dev = -1;
goto cleanup;
}
*dev_desc = get_dev(ifname, dev);
if (hwpart_str) {
hwpart = simple_strtoul(hwpart_str, &ep, 16);
if (*ep) {
printf("** Bad HW partition specification %s %s **\n",
ifname, hwpart_str);
dev = -1;
goto cleanup;
}
}
*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
printf("** Bad device %s %s **\n", ifname, dev_str);
return -1;
printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
dev = -1;
goto cleanup;
}
cleanup:
free(dup_str);
return dev;
}

View File

@ -30,6 +30,7 @@ obj-$(CONFIG_DWMMC) += dw_mmc.o
obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
else

View File

@ -174,7 +174,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
int timeout;
struct fsl_esdhc_cfg *cfg = mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
uint wml_value;
wml_value = data->blocksize/4;
@ -184,12 +184,15 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
wml_value = WML_RD_WML_MAX_VAL;
esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->dest);
#endif
} else {
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
flush_dcache_range((ulong)data->src,
(ulong)data->src+data->blocks
*data->blocksize);
#endif
if (wml_value > WML_WR_WML_MAX)
wml_value = WML_WR_WML_MAX_VAL;
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
@ -199,19 +202,10 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
wml_value << 16);
#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
esdhc_write32(&regs->dsaddr, (u32)data->src);
#endif
}
#else /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
if (!(data->flags & MMC_DATA_READ)) {
if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
printf("\nThe SD card is locked. "
"Can not write to a locked card.\n\n");
return TIMEOUT;
}
esdhc_write32(&regs->dsaddr, (u32)data->src);
} else
esdhc_write32(&regs->dsaddr, (u32)data->dest);
#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
@ -388,9 +382,10 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
goto out;
}
} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
#endif
if (data->flags & MMC_DATA_READ)
check_and_invalidate_dcache_range(cmd, data);
#endif
}
out:

View File

@ -150,6 +150,8 @@ int mmc_send_status(struct mmc *mmc, int timeout)
#endif
return TIMEOUT;
}
if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
return SWITCH_ERR;
return 0;
}
@ -501,7 +503,7 @@ static int mmc_change_freq(struct mmc *mmc)
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if (err)
return err;
return err == SWITCH_ERR ? 0 : err;
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
@ -550,6 +552,32 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0;
}
int mmc_select_hwpart(int dev_num, int hwpart)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret;
if (!mmc)
return -1;
if (mmc->part_num == hwpart)
return 0;
if (mmc->part_config == MMCPART_NOAVAILABLE) {
printf("Card doesn't support part_switch\n");
return -1;
}
ret = mmc_switch_part(dev_num, hwpart);
if (ret)
return -1;
mmc->part_num = hwpart;
return 0;
}
int mmc_switch_part(int dev_num, unsigned int part_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
@ -1310,10 +1338,13 @@ static int mmc_complete_init(struct mmc *mmc)
int mmc_init(struct mmc *mmc)
{
int err = IN_PROGRESS;
unsigned start = get_timer(0);
unsigned start;
if (mmc->has_init)
return 0;
start = get_timer(0);
if (!mmc->init_in_progress)
err = mmc_start_init(mmc);

323
drivers/mmc/rpmb.c 100644
View File

@ -0,0 +1,323 @@
/*
* Copyright 2014, Staubli Faverges
* Pierre Aubert
*
* eMMC- Replay Protected Memory Block
* According to JEDEC Standard No. 84-A441
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <mmc.h>
#include <sha256.h>
#include "mmc_private.h"
/* Request codes */
#define RPMB_REQ_KEY 1
#define RPMB_REQ_WCOUNTER 2
#define RPMB_REQ_WRITE_DATA 3
#define RPMB_REQ_READ_DATA 4
#define RPMB_REQ_STATUS 5
/* Response code */
#define RPMB_RESP_KEY 0x0100
#define RPMB_RESP_WCOUNTER 0x0200
#define RPMB_RESP_WRITE_DATA 0x0300
#define RPMB_RESP_READ_DATA 0x0400
/* Error codes */
#define RPMB_OK 0
#define RPMB_ERR_GENERAL 1
#define RPMB_ERR_AUTH 2
#define RPMB_ERR_COUNTER 3
#define RPMB_ERR_ADDRESS 4
#define RPMB_ERR_WRITE 5
#define RPMB_ERR_READ 6
#define RPMB_ERR_KEY 7
#define RPMB_ERR_CNT_EXPIRED 0x80
#define RPMB_ERR_MSK 0x7
/* Sizes of RPMB data frame */
#define RPMB_SZ_STUFF 196
#define RPMB_SZ_MAC 32
#define RPMB_SZ_DATA 256
#define RPMB_SZ_NONCE 16
#define SHA256_BLOCK_SIZE 64
/* Error messages */
static const char * const rpmb_err_msg[] = {
"",
"General failure",
"Authentication failure",
"Counter failure",
"Address failure",
"Write failure",
"Read failure",
"Authentication key not yet programmed",
};
/* Structure of RPMB data frame. */
struct s_rpmb {
unsigned char stuff[RPMB_SZ_STUFF];
unsigned char mac[RPMB_SZ_MAC];
unsigned char data[RPMB_SZ_DATA];
unsigned char nonce[RPMB_SZ_NONCE];
unsigned long write_counter;
unsigned short address;
unsigned short block_count;
unsigned short result;
unsigned short request;
};
static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
bool is_rel_write)
{
struct mmc_cmd cmd = {0};
cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
cmd.cmdarg = blockcount & 0x0000FFFF;
if (is_rel_write)
cmd.cmdarg |= 1 << 31;
cmd.resp_type = MMC_RSP_R1;
return mmc_send_cmd(mmc, &cmd, NULL);
}
static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
unsigned int count, bool is_rel_write)
{
struct mmc_cmd cmd = {0};
struct mmc_data data;
int ret;
ret = mmc_set_blockcount(mmc, count, is_rel_write);
if (ret) {
#ifdef CONFIG_MMC_RPMB_TRACE
printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
#endif
return 1;
}
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
data.src = (const char *)s;
data.blocks = 1;
data.blocksize = MMC_MAX_BLOCK_LEN;
data.flags = MMC_DATA_WRITE;
ret = mmc_send_cmd(mmc, &cmd, &data);
if (ret) {
#ifdef CONFIG_MMC_RPMB_TRACE
printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
#endif
return 1;
}
return 0;
}
static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
unsigned short expected)
{
struct mmc_cmd cmd = {0};
struct mmc_data data;
int ret;
ret = mmc_set_blockcount(mmc, 1, false);
if (ret) {
#ifdef CONFIG_MMC_RPMB_TRACE
printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
#endif
return -1;
}
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1;
data.dest = (char *)s;
data.blocks = 1;
data.blocksize = MMC_MAX_BLOCK_LEN;
data.flags = MMC_DATA_READ;
ret = mmc_send_cmd(mmc, &cmd, &data);
if (ret) {
#ifdef CONFIG_MMC_RPMB_TRACE
printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
#endif
return -1;
}
/* Check the response and the status */
if (be16_to_cpu(s->request) != expected) {
#ifdef CONFIG_MMC_RPMB_TRACE
printf("%s:response= %x\n", __func__,
be16_to_cpu(s->request));
#endif
return -1;
}
ret = be16_to_cpu(s->result);
if (ret) {
printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
(ret & RPMB_ERR_CNT_EXPIRED) ?
"Write counter has expired" : "");
}
/* Return the status of the command */
return ret;
}
static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
{
ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
return -1;
/* Read the result */
return mmc_rpmb_response(mmc, rpmb_frame, expected);
}
static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
unsigned char *output)
{
sha256_context ctx;
int i;
unsigned char k_ipad[SHA256_BLOCK_SIZE];
unsigned char k_opad[SHA256_BLOCK_SIZE];
sha256_starts(&ctx);
/* According to RFC 4634, the HMAC transform looks like:
SHA(K XOR opad, SHA(K XOR ipad, text))
where K is an n byte key.
ipad is the byte 0x36 repeated blocksize times
opad is the byte 0x5c repeated blocksize times
and text is the data being protected.
*/
for (i = 0; i < RPMB_SZ_MAC; i++) {
k_ipad[i] = key[i] ^ 0x36;
k_opad[i] = key[i] ^ 0x5c;
}
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
for ( ; i < SHA256_BLOCK_SIZE; i++) {
k_ipad[i] = 0x36;
k_opad[i] = 0x5c;
}
sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
sha256_update(&ctx, buff, len);
sha256_finish(&ctx, output);
/* Init context for second pass */
sha256_starts(&ctx);
/* start with outer pad */
sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
/* then results of 1st hash */
sha256_update(&ctx, output, RPMB_SZ_MAC);
/* finish up 2nd pass */
sha256_finish(&ctx, output);
}
int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
{
int ret;
ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
/* Fill the request */
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
return -1;
/* Read the result */
ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
if (ret)
return ret;
*pcounter = be32_to_cpu(rpmb_frame->write_counter);
return 0;
}
int mmc_rpmb_set_key(struct mmc *mmc, void *key)
{
ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
/* Fill the request */
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
return -1;
/* read the operation status */
return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
}
int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
unsigned short cnt, unsigned char *key)
{
ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
int i;
for (i = 0; i < cnt; i++) {
/* Fill the request */
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
rpmb_frame->address = cpu_to_be16(blk + i);
rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
break;
/* Read the result */
if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
break;
/* Check the HMAC if key is provided */
if (key) {
unsigned char ret_hmac[RPMB_SZ_MAC];
rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
printf("MAC error on block #%d\n", i);
break;
}
}
/* Copy data */
memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
}
return i;
}
int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
unsigned short cnt, unsigned char *key)
{
ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
unsigned long wcount;
int i;
for (i = 0; i < cnt; i++) {
if (mmc_rpmb_get_counter(mmc, &wcount)) {
printf("Cannot read RPMB write counter\n");
break;
}
/* Fill the request */
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
rpmb_frame->address = cpu_to_be16(blk + i);
rpmb_frame->block_count = cpu_to_be16(1);
rpmb_frame->write_counter = cpu_to_be32(wcount);
rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
/* Computes HMAC */
rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
break;
/* Get status */
if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
break;
}
return i;
}

View File

@ -836,7 +836,7 @@ int ctrlc (void);
int had_ctrlc (void); /* have we had a Control-C since last clear? */
void clear_ctrlc (void); /* clear the Control-C condition */
int disable_ctrlc (int); /* 1 to disable, 0 to enable Control-C detect */
int confirm_yesno(void); /* 1 if input is "y", "Y", "yes" or "YES" */
/*
* STDIO based functions (can always be used)
*/

View File

@ -109,7 +109,7 @@
#undef CONFIG_ENV_IS_NOWHERE
#define CONFIG_ENV_IS_IN_MMC
#define CONFIG_SYS_MMC_ENV_DEV 1
#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_SYS_MMC_ENV_PART 2
#define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */
#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)

View File

@ -237,7 +237,7 @@
#elif defined(CONFIG_EMMC_BOOT)
#undef CONFIG_ENV_IS_NOWHERE
#define CONFIG_ENV_IS_IN_MMC
#define CONFIG_SYS_MMC_ENV_DEV 1
#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_SYS_MMC_ENV_PART 2
#define CONFIG_ENV_OFFSET 0x40000 /* TODO: Adresse definieren */
#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)

View File

@ -54,6 +54,7 @@
#define COMM_ERR -18 /* Communications Error */
#define TIMEOUT -19
#define IN_PROGRESS -20 /* operation is in progress */
#define SWITCH_ERR -21 /* Card reports failure to switch mode */
#define MMC_CMD_GO_IDLE_STATE 0
#define MMC_CMD_SEND_OP_COND 1
@ -70,6 +71,7 @@
#define MMC_CMD_SET_BLOCKLEN 16
#define MMC_CMD_READ_SINGLE_BLOCK 17
#define MMC_CMD_READ_MULTIPLE_BLOCK 18
#define MMC_CMD_SET_BLOCK_COUNT 23
#define MMC_CMD_WRITE_SINGLE_BLOCK 24
#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
#define MMC_CMD_ERASE_GROUP_START 35
@ -109,6 +111,7 @@
#define SECURE_ERASE 0x80000000
#define MMC_STATUS_MASK (~0x0206BF7F)
#define MMC_STATUS_SWITCH_ERROR (1 << 7)
#define MMC_STATUS_RDY_FOR_DATA (1 << 8)
#define MMC_STATUS_CURR_STATE (0xf << 9)
#define MMC_STATUS_ERROR (1 << 19)
@ -225,6 +228,7 @@
* boot partitions (2), general purpose partitions (4) in MMC v4.4.
*/
#define MMC_NUM_BOOT_PARTITION 2
#define MMC_PART_RPMB 3 /* RPMB partition number */
struct mmc_cid {
unsigned long psn;
@ -336,7 +340,13 @@ int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access);
int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode);
/* Function to modify the RST_n_FUNCTION field of EXT_CSD */
int mmc_set_rst_n_function(struct mmc *mmc, u8 enable);
/* Functions to read / write the RPMB partition */
int mmc_rpmb_set_key(struct mmc *mmc, void *key);
int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *counter);
int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
unsigned short cnt, unsigned char *key);
int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
unsigned short cnt, unsigned char *key);
/**
* Start device initialization and return immediately; it does not block on
* polling OCR (operation condition register) status. Then you should call

View File

@ -103,6 +103,7 @@ block_dev_desc_t* sata_get_dev(int dev);
block_dev_desc_t* scsi_get_dev(int dev);
block_dev_desc_t* usb_stor_get_dev(int dev);
block_dev_desc_t* mmc_get_dev(int dev);
int mmc_select_hwpart(int dev_num, int hwpart);
block_dev_desc_t* systemace_get_dev(int dev);
block_dev_desc_t* mg_disk_get_dev(int dev);
block_dev_desc_t *host_get_dev(int dev);
@ -126,6 +127,7 @@ static inline block_dev_desc_t* sata_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* scsi_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* usb_stor_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* mmc_get_dev(int dev) { return NULL; }
static inline int mmc_select_hwpart(int dev_num, int hwpart) { return -1; }
static inline block_dev_desc_t* systemace_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t* mg_disk_get_dev(int dev) { return NULL; }
static inline block_dev_desc_t *host_get_dev(int dev) { return NULL; }

View File

@ -35,6 +35,7 @@ obj-y += net_utils.o
obj-$(CONFIG_PHYSMEM) += physmem.o
obj-y += qsort.o
obj-$(CONFIG_SHA1) += sha1.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
obj-$(CONFIG_SHA256) += sha256.o
obj-y += strmhz.o
obj-$(CONFIG_TPM) += tpm.o