mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-21 20:34:38 +00:00
cmd: bcb: extend BCB C API to allow read/write the fields
Currently BCB C API only allows to modify 'command' BCB field. Extend it so that we can also read and modify all the available BCB fields (command, status, recovery, stage). Co-developed-by: Cody Schuffelen <schuffelen@google.com> Signed-off-by: Cody Schuffelen <schuffelen@google.com> Signed-off-by: Dmitrii Merkurev <dimorinny@google.com> Cc: Eugeniu Rosca <erosca@de.adit-jv.com> Cc: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> Cc: Simon Glass <sjg@chromium.org> Cc: Mattijs Korpershoek <mkorpershoek@baylibre.com> Cc: Sean Anderson <sean.anderson@seco.com> Cc: Cody Schuffelen <schuffelen@google.com> Tested-by: Mattijs Korpershoek <mkorpershoek@baylibre.com> # on vim3 Reviewed-by: Mattijs Korpershoek <mkorpershoek@baylibre.com>
This commit is contained in:
parent
a654369b49
commit
dfeb4f0d79
3 changed files with 177 additions and 58 deletions
161
cmd/bcb.c
161
cmd/bcb.c
|
@ -25,10 +25,18 @@ enum bcb_cmd {
|
||||||
BCB_CMD_STORE,
|
BCB_CMD_STORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum uclass_id bcb_uclass_id = UCLASS_INVALID;
|
static const char * const fields[] = {
|
||||||
static int bcb_dev = -1;
|
"command",
|
||||||
static int bcb_part = -1;
|
"status",
|
||||||
|
"recovery",
|
||||||
|
"stage"
|
||||||
|
};
|
||||||
|
|
||||||
static struct bootloader_message bcb __aligned(ARCH_DMA_MINALIGN) = { { 0 } };
|
static struct bootloader_message bcb __aligned(ARCH_DMA_MINALIGN) = { { 0 } };
|
||||||
|
static struct disk_partition partition_data;
|
||||||
|
|
||||||
|
static struct blk_desc *block;
|
||||||
|
static struct disk_partition *partition = &partition_data;
|
||||||
|
|
||||||
static int bcb_cmd_get(char *cmd)
|
static int bcb_cmd_get(char *cmd)
|
||||||
{
|
{
|
||||||
|
@ -82,7 +90,7 @@ static int bcb_is_misused(int argc, char *const argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd != BCB_CMD_LOAD && (bcb_dev < 0 || bcb_part < 0)) {
|
if (cmd != BCB_CMD_LOAD && !block) {
|
||||||
printf("Error: Please, load BCB first!\n");
|
printf("Error: Please, load BCB first!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +102,7 @@ err:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcb_field_get(char *name, char **fieldp, int *sizep)
|
static int bcb_field_get(const char *name, char **fieldp, int *sizep)
|
||||||
{
|
{
|
||||||
if (!strcmp(name, "command")) {
|
if (!strcmp(name, "command")) {
|
||||||
*fieldp = bcb.command;
|
*fieldp = bcb.command;
|
||||||
|
@ -119,16 +127,21 @@ static int bcb_field_get(char *name, char **fieldp, int *sizep)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __bcb_load(const char *iface, int devnum, const char *partp)
|
static void __bcb_reset(void)
|
||||||
|
{
|
||||||
|
block = NULL;
|
||||||
|
partition = &partition_data;
|
||||||
|
memset(&partition_data, 0, sizeof(struct disk_partition));
|
||||||
|
memset(&bcb, 0, sizeof(struct bootloader_message));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __bcb_initialize(const char *iface, int devnum, const char *partp)
|
||||||
{
|
{
|
||||||
struct blk_desc *desc;
|
|
||||||
struct disk_partition info;
|
|
||||||
u64 cnt;
|
|
||||||
char *endp;
|
char *endp;
|
||||||
int part, ret;
|
int part, ret;
|
||||||
|
|
||||||
desc = blk_get_dev(iface, devnum);
|
block = blk_get_dev(iface, devnum);
|
||||||
if (!desc) {
|
if (!block) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err_read_fail;
|
goto err_read_fail;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +150,7 @@ static int __bcb_load(const char *iface, int devnum, const char *partp)
|
||||||
* always select the first hwpart in case another
|
* always select the first hwpart in case another
|
||||||
* blk operation selected a different hwpart
|
* blk operation selected a different hwpart
|
||||||
*/
|
*/
|
||||||
ret = blk_dselect_hwpart(desc, 0);
|
ret = blk_dselect_hwpart(block, 0);
|
||||||
if (IS_ERR_VALUE(ret)) {
|
if (IS_ERR_VALUE(ret)) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err_read_fail;
|
goto err_read_fail;
|
||||||
|
@ -145,49 +158,60 @@ static int __bcb_load(const char *iface, int devnum, const char *partp)
|
||||||
|
|
||||||
part = simple_strtoul(partp, &endp, 0);
|
part = simple_strtoul(partp, &endp, 0);
|
||||||
if (*endp == '\0') {
|
if (*endp == '\0') {
|
||||||
ret = part_get_info(desc, part, &info);
|
ret = part_get_info(block, part, partition);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_read_fail;
|
goto err_read_fail;
|
||||||
} else {
|
} else {
|
||||||
part = part_get_info_by_name(desc, partp, &info);
|
part = part_get_info_by_name(block, partp, partition);
|
||||||
if (part < 0) {
|
if (part < 0) {
|
||||||
ret = part;
|
ret = part;
|
||||||
goto err_read_fail;
|
goto err_read_fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
|
return CMD_RET_SUCCESS;
|
||||||
if (cnt > info.size)
|
|
||||||
|
err_read_fail:
|
||||||
|
printf("Error: %d %d:%s read failed (%d)\n", block->uclass_id,
|
||||||
|
block->devnum, partition->name, ret);
|
||||||
|
__bcb_reset();
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __bcb_load(void)
|
||||||
|
{
|
||||||
|
u64 cnt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), partition->blksz);
|
||||||
|
if (cnt > partition->size)
|
||||||
goto err_too_small;
|
goto err_too_small;
|
||||||
|
|
||||||
if (blk_dread(desc, info.start, cnt, &bcb) != cnt) {
|
if (blk_dread(block, partition->start, cnt, &bcb) != cnt) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto err_read_fail;
|
goto err_read_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bcb_uclass_id = desc->uclass_id;
|
debug("%s: Loaded from %d %d:%s\n", __func__, block->uclass_id,
|
||||||
bcb_dev = desc->devnum;
|
block->devnum, partition->name);
|
||||||
bcb_part = part;
|
|
||||||
debug("%s: Loaded from %s %d:%d\n", __func__, iface, bcb_dev, bcb_part);
|
|
||||||
|
|
||||||
return CMD_RET_SUCCESS;
|
return CMD_RET_SUCCESS;
|
||||||
err_read_fail:
|
err_read_fail:
|
||||||
printf("Error: %s %d:%s read failed (%d)\n", iface, devnum, partp, ret);
|
printf("Error: %d %d:%s read failed (%d)\n", block->uclass_id,
|
||||||
|
block->devnum, partition->name, ret);
|
||||||
goto err;
|
goto err;
|
||||||
err_too_small:
|
err_too_small:
|
||||||
printf("Error: %s %d:%s too small!", iface, devnum, partp);
|
printf("Error: %d %d:%s too small!", block->uclass_id,
|
||||||
goto err;
|
block->devnum, partition->name);
|
||||||
err:
|
err:
|
||||||
bcb_uclass_id = UCLASS_INVALID;
|
__bcb_reset();
|
||||||
bcb_dev = -1;
|
|
||||||
bcb_part = -1;
|
|
||||||
|
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char * const argv[])
|
char * const argv[])
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
int devnum;
|
int devnum;
|
||||||
char *endp;
|
char *endp;
|
||||||
char *iface = "mmc";
|
char *iface = "mmc";
|
||||||
|
@ -204,10 +228,14 @@ static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return __bcb_load(iface, devnum, argv[2]);
|
ret = __bcb_initialize(iface, devnum, argv[2]);
|
||||||
|
if (ret != CMD_RET_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return __bcb_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __bcb_set(char *fieldp, const char *valp)
|
static int __bcb_set(const char *fieldp, const char *valp)
|
||||||
{
|
{
|
||||||
int size, len;
|
int size, len;
|
||||||
char *field, *str, *found, *tmp;
|
char *field, *str, *found, *tmp;
|
||||||
|
@ -307,31 +335,20 @@ static int do_bcb_dump(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
|
|
||||||
static int __bcb_store(void)
|
static int __bcb_store(void)
|
||||||
{
|
{
|
||||||
struct blk_desc *desc;
|
|
||||||
struct disk_partition info;
|
|
||||||
u64 cnt;
|
u64 cnt;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
desc = blk_get_devnum_by_uclass_id(bcb_uclass_id, bcb_dev);
|
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), partition->blksz);
|
||||||
if (!desc) {
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = part_get_info(desc, bcb_part, &info);
|
if (blk_dwrite(block, partition->start, cnt, &bcb) != cnt) {
|
||||||
if (ret)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
|
|
||||||
|
|
||||||
if (blk_dwrite(desc, info.start, cnt, &bcb) != cnt) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CMD_RET_SUCCESS;
|
return CMD_RET_SUCCESS;
|
||||||
err:
|
err:
|
||||||
printf("Error: %d %d:%d write failed (%d)\n", bcb_uclass_id, bcb_dev, bcb_part, ret);
|
printf("Error: %d %d:%s write failed (%d)\n", block->uclass_id,
|
||||||
|
block->devnum, partition->name, ret);
|
||||||
|
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -342,23 +359,59 @@ static int do_bcb_store(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
return __bcb_store();
|
return __bcb_store();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bcb_write_reboot_reason(const char *iface, int devnum, char *partp, const char *reasonp)
|
int bcb_find_partition_and_load(const char *iface, int devnum, char *partp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = __bcb_load(iface, devnum, partp);
|
__bcb_reset();
|
||||||
|
|
||||||
|
ret = __bcb_initialize(iface, devnum, partp);
|
||||||
if (ret != CMD_RET_SUCCESS)
|
if (ret != CMD_RET_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = __bcb_set("command", reasonp);
|
return __bcb_load();
|
||||||
if (ret != CMD_RET_SUCCESS)
|
}
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = __bcb_store();
|
int bcb_load(struct blk_desc *block_description, struct disk_partition *disk_partition)
|
||||||
if (ret != CMD_RET_SUCCESS)
|
{
|
||||||
return ret;
|
__bcb_reset();
|
||||||
|
|
||||||
return 0;
|
block = block_description;
|
||||||
|
partition = disk_partition;
|
||||||
|
|
||||||
|
return __bcb_load();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bcb_set(enum bcb_field field, const char *value)
|
||||||
|
{
|
||||||
|
if (field > BCB_FIELD_STAGE)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
return __bcb_set(fields[field], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bcb_get(enum bcb_field field, char *value_out, size_t value_size)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
char *field_value;
|
||||||
|
|
||||||
|
if (field > BCB_FIELD_STAGE)
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
if (bcb_field_get(fields[field], &field_value, &size))
|
||||||
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
|
strlcpy(value_out, field_value, value_size);
|
||||||
|
|
||||||
|
return CMD_RET_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bcb_store(void)
|
||||||
|
{
|
||||||
|
return __bcb_store();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bcb_reset(void)
|
||||||
|
{
|
||||||
|
__bcb_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmd_tbl cmd_bcb_sub[] = {
|
static struct cmd_tbl cmd_bcb_sub[] = {
|
||||||
|
|
|
@ -91,6 +91,7 @@ void fastboot_okay(const char *reason, char *response)
|
||||||
*/
|
*/
|
||||||
int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
|
int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
static const char * const boot_cmds[] = {
|
static const char * const boot_cmds[] = {
|
||||||
[FASTBOOT_REBOOT_REASON_BOOTLOADER] = "bootonce-bootloader",
|
[FASTBOOT_REBOOT_REASON_BOOTLOADER] = "bootonce-bootloader",
|
||||||
[FASTBOOT_REBOOT_REASON_FASTBOOTD] = "boot-fastboot",
|
[FASTBOOT_REBOOT_REASON_FASTBOOTD] = "boot-fastboot",
|
||||||
|
@ -105,7 +106,18 @@ int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
|
||||||
if (reason >= FASTBOOT_REBOOT_REASONS_COUNT)
|
if (reason >= FASTBOOT_REBOOT_REASONS_COUNT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return bcb_write_reboot_reason("mmc", mmc_dev, "misc", boot_cmds[reason]);
|
ret = bcb_find_partition_and_load("mmc", mmc_dev, "misc");
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = bcb_set(BCB_FIELD_COMMAND, boot_cmds[reason]);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = bcb_store();
|
||||||
|
out:
|
||||||
|
bcb_reset();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,15 +8,69 @@
|
||||||
#ifndef __BCB_H__
|
#ifndef __BCB_H__
|
||||||
#define __BCB_H__
|
#define __BCB_H__
|
||||||
|
|
||||||
|
#include <part.h>
|
||||||
|
|
||||||
|
enum bcb_field {
|
||||||
|
BCB_FIELD_COMMAND,
|
||||||
|
BCB_FIELD_STATUS,
|
||||||
|
BCB_FIELD_RECOVERY,
|
||||||
|
BCB_FIELD_STAGE
|
||||||
|
};
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_CMD_BCB)
|
#if IS_ENABLED(CONFIG_CMD_BCB)
|
||||||
int bcb_write_reboot_reason(const char *iface, int devnum, char *partp, const char *reasonp);
|
|
||||||
|
int bcb_find_partition_and_load(const char *iface,
|
||||||
|
int devnum, char *partp);
|
||||||
|
int bcb_load(struct blk_desc *block_description,
|
||||||
|
struct disk_partition *disk_partition);
|
||||||
|
int bcb_set(enum bcb_field field, const char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bcb_get() - get the field value.
|
||||||
|
* @field: field to get
|
||||||
|
* @value_out: buffer to copy bcb field value to
|
||||||
|
* @value_size: buffer size to avoid overflow in case
|
||||||
|
* value_out is smaller then the field value
|
||||||
|
*/
|
||||||
|
int bcb_get(enum bcb_field field, char *value_out, size_t value_size);
|
||||||
|
|
||||||
|
int bcb_store(void);
|
||||||
|
void bcb_reset(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
static inline int bcb_write_reboot_reason(const char *iface, int devnum,
|
|
||||||
char *partp, const char *reasonp)
|
static inline int bcb_load(struct blk_desc *block_description,
|
||||||
|
struct disk_partition *disk_partition)
|
||||||
{
|
{
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int bcb_find_partition_and_load(const char *iface,
|
||||||
|
int devnum, char *partp)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bcb_set(enum bcb_field field, const char *value)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bcb_get(enum bcb_field field, char *value_out)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bcb_store(void)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bcb_reset(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __BCB_H__ */
|
#endif /* __BCB_H__ */
|
||||||
|
|
Loading…
Add table
Reference in a new issue