Browse Source
Add 'bbram' command which is very convenient tool for examining and modyfying BBRAM content. Examples: Write one byte: $ bbram write backup_regs 0x1 0xaa Write many bytes (starting from 0x13): $ bbram write backup_regs 0x13 0xa 0xb 0xc 0xd 0xe 0xf 0xaa 0xab 0xac Read whole BBRAM: $ bbram read backup_regs Read many bytes (4 bytes starting from address 0x14 in this case): $ bbram read backup_regs 0x14 4 Read one byte (from 0x14 address): $ bbram read backup_regs 0x14 Signed-off-by: Patryk Duda <pdk@semihalf.com>pull/52883/head
3 changed files with 210 additions and 0 deletions
@ -0,0 +1,202 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 Google Inc |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <zephyr/devicetree.h> |
||||||
|
#include <zephyr/drivers/bbram.h> |
||||||
|
#include <zephyr/kernel.h> |
||||||
|
#include <zephyr/shell/shell.h> |
||||||
|
#include <zephyr/sys/util.h> |
||||||
|
|
||||||
|
/* Buffer is only needed for bytes that follow command, device and address. */ |
||||||
|
#define BUF_ARRAY_CNT (CONFIG_SHELL_ARGC_MAX - 3) |
||||||
|
|
||||||
|
static inline int parse_ul(const char *str, unsigned long *result) |
||||||
|
{ |
||||||
|
char *end; |
||||||
|
unsigned long val; |
||||||
|
|
||||||
|
val = strtoul(str, &end, 0); |
||||||
|
|
||||||
|
if (*str == '\0' || *end != '\0') { |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
*result = val; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static inline int parse_u32(const char *str, uint32_t *result) |
||||||
|
{ |
||||||
|
unsigned long val; |
||||||
|
|
||||||
|
if (parse_ul(str, &val) || val > 0xffffffff) { |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
*result = (uint32_t)val; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static inline int parse_u8(const char *str, uint8_t *result) |
||||||
|
{ |
||||||
|
unsigned long val; |
||||||
|
|
||||||
|
if (parse_ul(str, &val) || val > 0xff) { |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
*result = (uint8_t)val; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static inline int parse_device(const struct shell *sh, size_t argc, char *argv[], |
||||||
|
const struct device **bbram_dev) |
||||||
|
{ |
||||||
|
if (argc < 2) { |
||||||
|
shell_error(sh, "Missing BBRAM device"); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
*bbram_dev = device_get_binding(argv[1]); |
||||||
|
if (!*bbram_dev) { |
||||||
|
shell_error(sh, "Given BBRAM device was not found"); |
||||||
|
return -ENODEV; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int cmd_read(const struct shell *sh, size_t argc, char *argv[]) |
||||||
|
{ |
||||||
|
const struct device *bbram_dev; |
||||||
|
uint32_t addr; |
||||||
|
size_t size; |
||||||
|
int part_size, ret; |
||||||
|
|
||||||
|
ret = parse_device(sh, argc, argv, &bbram_dev); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
if (argc < 3) { |
||||||
|
/* Dump whole BBRAM if address not provided. */ |
||||||
|
addr = 0; |
||||||
|
ret = bbram_get_size(bbram_dev, &size); |
||||||
|
if (ret < 0) { |
||||||
|
shell_error(sh, "Can't get BBRAM size: %d", ret); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
} else { |
||||||
|
/* Parse address if provided. */ |
||||||
|
ret = parse_u32(argv[2], &addr); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* If size not provided read one byte. */ |
||||||
|
size = 1; |
||||||
|
|
||||||
|
if (argc >= 4) { |
||||||
|
/* Parse size if provided. */ |
||||||
|
ret = parse_u32(argv[3], &size); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (int cnt = 0; cnt < size; cnt += part_size) { |
||||||
|
uint8_t data[SHELL_HEXDUMP_BYTES_IN_LINE]; |
||||||
|
|
||||||
|
part_size = MIN(size - cnt, SHELL_HEXDUMP_BYTES_IN_LINE); |
||||||
|
ret = bbram_read(bbram_dev, addr, part_size, data); |
||||||
|
if (ret != 0) { |
||||||
|
shell_error(sh, "BBRAM read error: %d", ret); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
shell_hexdump_line(sh, addr, data, part_size); |
||||||
|
addr += part_size; |
||||||
|
} |
||||||
|
|
||||||
|
shell_print(sh, ""); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int cmd_write(const struct shell *sh, size_t argc, char *argv[]) |
||||||
|
{ |
||||||
|
const struct device *bbram_dev; |
||||||
|
uint8_t buf[BUF_ARRAY_CNT]; |
||||||
|
uint32_t addr; |
||||||
|
size_t size = 0; |
||||||
|
int ret; |
||||||
|
|
||||||
|
ret = parse_device(sh, argc, argv, &bbram_dev); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
if (argc < 3) { |
||||||
|
shell_error(sh, "Missing address"); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
/* Parse address. */ |
||||||
|
ret = parse_u32(argv[2], &addr); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Parse bytes and place them in the buffer. */ |
||||||
|
for (int i = 3; i < argc; i++) { |
||||||
|
ret = parse_u8(argv[i], &buf[i - 3]); |
||||||
|
if (ret) { |
||||||
|
return ret; |
||||||
|
} |
||||||
|
size++; |
||||||
|
} |
||||||
|
|
||||||
|
if (size == 0) { |
||||||
|
shell_error(sh, "Missing data"); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
ret = bbram_write(bbram_dev, addr, size, buf); |
||||||
|
if (ret < 0) { |
||||||
|
shell_error(sh, "BBRAM write error: %d", ret); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static void device_name_get(size_t idx, struct shell_static_entry *entry) |
||||||
|
{ |
||||||
|
const struct device *dev = shell_device_lookup(idx, NULL); |
||||||
|
|
||||||
|
entry->syntax = (dev != NULL) ? dev->name : NULL; |
||||||
|
entry->handler = NULL; |
||||||
|
entry->help = NULL; |
||||||
|
entry->subcmd = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); |
||||||
|
|
||||||
|
SHELL_STATIC_SUBCMD_SET_CREATE(bbram_cmds, |
||||||
|
SHELL_CMD_ARG(read, &dsub_device_name, |
||||||
|
"<device> [<address>] [<count>]", cmd_read, 2, 2), |
||||||
|
SHELL_CMD_ARG(write, &dsub_device_name, |
||||||
|
"<device> <address> <byte> [<byte>...]", cmd_write, 4, |
||||||
|
BUF_ARRAY_CNT), |
||||||
|
SHELL_SUBCMD_SET_END); |
||||||
|
|
||||||
|
static int cmd_bbram(const struct shell *sh, size_t argc, char **argv) |
||||||
|
{ |
||||||
|
shell_error(sh, "%s: unknown parameter: %s", argv[0], argv[1]); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
SHELL_CMD_ARG_REGISTER(bbram, &bbram_cmds, "Battery-backed RAM shell commands", cmd_bbram, 2, 0); |
Loading…
Reference in new issue