1 /*
2 * Copyright (c) 2022 Google Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_stm32_bbram
8
9 #include <errno.h>
10
11 #include <zephyr/drivers/bbram.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/sys/util.h>
14 #include <stm32_ll_pwr.h>
15 #include <stm32_ll_rtc.h>
16 #include <stm32_backup_domain.h>
17
18 LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL);
19
20 #define STM32_BKP_REG_BYTES 4
21 #ifdef TAMP
22 /* If a SoC has a TAMP peripherals, then the backup registers are defined there,
23 * not in the RTC.
24 */
25 #define STM32_BKP_REG_OFFSET (TAMP_BASE + offsetof(TAMP_TypeDef, BKP0R) - RTC_BASE)
26 #else
27 #define STM32_BKP_REG_OFFSET offsetof(RTC_TypeDef, BKP0R)
28 #endif
29 #define STM32_BKP_REG_INDEX(offset) ((offset) >> 2)
30 #define STM32_BKP_REG_BYTE_INDEX(offset) ((offset)&0x3UL)
31 #define STM32_BKP_REG(i) (((volatile uint32_t *)config->base_addr)[(i)])
32
33 /** Device config */
34 struct bbram_stm32_config {
35 const struct device *parent;
36 /* BBRAM base address */
37 uintptr_t base_addr;
38 /* BBRAM size in bytes. */
39 int size;
40 };
41
bbram_stm32_read(const struct device * dev,size_t offset,size_t size,uint8_t * data)42 static int bbram_stm32_read(const struct device *dev, size_t offset, size_t size, uint8_t *data)
43 {
44 const struct bbram_stm32_config *config = dev->config;
45 uint32_t reg, begin, to_copy;
46
47 if (size < 1 || offset + size > config->size) {
48 return -EFAULT;
49 }
50
51 for (size_t read = 0; read < size; read += to_copy) {
52 reg = STM32_BKP_REG(STM32_BKP_REG_INDEX(offset + read));
53 begin = STM32_BKP_REG_BYTE_INDEX(offset + read);
54 to_copy = MIN(STM32_BKP_REG_BYTES - begin, size - read);
55 bytecpy(data + read, (uint8_t *)® + begin, to_copy);
56 }
57
58 return 0;
59 }
60
bbram_stm32_write(const struct device * dev,size_t offset,size_t size,const uint8_t * data)61 static int bbram_stm32_write(const struct device *dev, size_t offset, size_t size,
62 const uint8_t *data)
63 {
64 const struct bbram_stm32_config *config = dev->config;
65 uint32_t reg, begin, to_copy;
66
67 if (size < 1 || offset + size > config->size) {
68 return -EFAULT;
69 }
70
71 stm32_backup_domain_enable_access();
72
73 for (size_t written = 0; written < size; written += to_copy) {
74 reg = STM32_BKP_REG(STM32_BKP_REG_INDEX(offset + written));
75 begin = STM32_BKP_REG_BYTE_INDEX(offset + written);
76 to_copy = MIN(STM32_BKP_REG_BYTES - begin, size - written);
77 bytecpy((uint8_t *)® + begin, data + written, to_copy);
78 STM32_BKP_REG(STM32_BKP_REG_INDEX(offset + written)) = reg;
79 }
80
81 stm32_backup_domain_disable_access();
82
83 return 0;
84 }
85
bbram_stm32_get_size(const struct device * dev,size_t * size)86 static int bbram_stm32_get_size(const struct device *dev, size_t *size)
87 {
88 const struct bbram_stm32_config *config = dev->config;
89
90 *size = config->size;
91
92 return 0;
93 }
94
95 static DEVICE_API(bbram, bbram_stm32_driver_api) = {
96 .read = bbram_stm32_read,
97 .write = bbram_stm32_write,
98 .get_size = bbram_stm32_get_size,
99 };
100
bbram_stm32_init(const struct device * dev)101 static int bbram_stm32_init(const struct device *dev)
102 {
103 const struct bbram_stm32_config *config = dev->config;
104
105 if (!device_is_ready(config->parent)) {
106 LOG_ERR("Device %s is not ready", config->parent->name);
107 return -ENODEV;
108 }
109
110 return 0;
111 }
112
113 #define BBRAM_INIT(inst) \
114 static const struct bbram_stm32_config bbram_cfg_##inst = { \
115 .parent = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
116 .base_addr = DT_REG_ADDR(DT_INST_PARENT(inst)) + STM32_BKP_REG_OFFSET, \
117 .size = DT_INST_PROP(inst, st_backup_regs) * STM32_BKP_REG_BYTES, \
118 }; \
119 DEVICE_DT_INST_DEFINE(inst, bbram_stm32_init, NULL, NULL, &bbram_cfg_##inst, PRE_KERNEL_1, \
120 CONFIG_BBRAM_INIT_PRIORITY, &bbram_stm32_driver_api);
121
122 DT_INST_FOREACH_STATUS_OKAY(BBRAM_INIT);
123