Skip to content

Add support for battery-backed RAM for STM32 deivces #51721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};

&spi1 {
Expand Down
14 changes: 14 additions & 0 deletions boards/arm/stm32f0_disco/stm32f0_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
};
};

&clk_lsi {
status = "okay";
};

&clk_hse {
clock-frequency = <DT_FREQ_M(8)>;
status = "okay";
Expand Down Expand Up @@ -120,3 +124,13 @@
&iwdg {
status = "okay";
};

&rtc {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};
4 changes: 4 additions & 0 deletions boards/arm/stm32f3_disco/stm32f3_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ zephyr_udc0: &usb {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};

&can1 {
Expand Down
4 changes: 4 additions & 0 deletions boards/arm/stm32f4_disco/stm32f4_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};

zephyr_udc0: &usbotg_fs {
Expand Down
4 changes: 4 additions & 0 deletions boards/arm/stm32f746g_disco/stm32f746g_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ zephyr_udc0: &usbotg_fs {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};

&sdmmc1 {
Expand Down
14 changes: 14 additions & 0 deletions boards/arm/stm32h735g_disco/stm32h735g_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
status = "okay";
};

&clk_lsi {
status = "okay";
};

&pll {
div-m = <5>;
mul-n = <110>;
Expand Down Expand Up @@ -150,3 +154,13 @@
};
};
};

&rtc {
clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00010000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};
14 changes: 14 additions & 0 deletions boards/arm/stm32l1_disco/stm32l1_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
};
};

&clk_lsi {
status = "okay";
};

&clk_hsi {
status = "okay";
};
Expand Down Expand Up @@ -114,3 +118,13 @@
pinctrl-names = "default";
status = "okay";
};

&rtc {
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};
4 changes: 4 additions & 0 deletions boards/arm/stm32l476g_disco/stm32l476g_disco.dts
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,8 @@
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>,
<&rcc STM32_SRC_LSI RTC_SEL(2)>;
status = "okay";

backup_regs {
status = "okay";
};
};
3 changes: 3 additions & 0 deletions drivers/bbram/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

zephyr_library()

zephyr_library_sources_ifdef(CONFIG_BBRAM_SHELL bbram_shell.c)

zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c)
11 changes: 11 additions & 0 deletions drivers/bbram/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ module = BBRAM
module-str = bbram
source "subsys/logging/Kconfig.template.log_config"

config BBRAM_SHELL
bool "Battery-backed RAM shell"
depends on SHELL
help
Enable the BBRAM shell with read and write commands.

config BBRAM_INIT_PRIORITY
int "Init priority"
# In STM32, BBRAM is a part of RTC. In this case init priority must be
# lower than COUNTER_INIT_PRIORITY.
default 65 if BBRAM_STM32
default 10
help
BBRAM driver initialization priority
Expand All @@ -26,4 +35,6 @@ source "drivers/bbram/Kconfig.bbram_emul"

source "drivers/bbram/Kconfig.xec"

source "drivers/bbram/Kconfig.stm32"

endif # BBRAM
17 changes: 17 additions & 0 deletions drivers/bbram/Kconfig.stm32
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2022 Google Inc
# SPDX-License-Identifier: Apache-2.0

config BBRAM_STM32
bool "ST STM32 Battery-backed RAM drivers"
default y
depends on DT_HAS_ST_STM32_BBRAM_ENABLED
depends on COUNTER
help
This option enables the BBRAM driver for STM32 family of
processors.

STM32 BBRAM are 32-bit registers which can be used for storing user
application data. They are implemented in the backup domain that remains
powered-on by VBAT when the VDD power is switched off. They are not reset
by system reset or when the device wakes up from Standby mode. They are
reset by a backup domain reset.
202 changes: 202 additions & 0 deletions drivers/bbram/bbram_shell.c
Original file line number Diff line number Diff line change
@@ -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