+/* bitmap helper extension */
+struct range {
+ unsigned int start;
+ unsigned int end;
+};
+
+static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits,
+ struct range *ranges, unsigned int *ranges_count) {
+ *ranges_count = 0;
+ bool last_bit = 0, cur_bit;
+ for (unsigned int i = 0; i < nbits; i++) {
+ cur_bit = test_bit(i, bitmap);
+
+ if (cur_bit && !last_bit) {
+ (*ranges_count)++;
+ ranges[*ranges_count - 1].start = i;
+ ranges[*ranges_count - 1].end = i;
+ } else if (cur_bit && last_bit) {
+ /* update (increment) the end this range */
+ ranges[*ranges_count - 1].end = i;
+ }
+
+ last_bit = cur_bit;
+ }
+}
+
+static inline int range_print_one(struct range *range, char *str)
+{
+ if (range->start == range->end)
+ return sprintf(str, "[%d]", range->start);
+
+ return sprintf(str, "[%d,%d]", range->start, range->end);
+}
+
+static char *range_print_alloc(struct range *ranges, unsigned int ranges_count)
+{
+ /* each range will be printed like the following: [start,end]
+ * start and end, both are unsigned int, an unsigned int takes 10 characters max
+ * plus 3 characters for '[', ',' and ']'
+ * thus means each range can take maximum 23 character
+ * after each range we add a ' ' as separator and finally we need the '\0'
+ * if the ranges_count is zero we reserve one char for '\0' to return an empty string */
+ char *str = calloc(1, ranges_count * (24 * sizeof(char)) + 1);
+ char *ptr = str;
+
+ for (unsigned int i = 0; i < ranges_count; i++) {
+ ptr += range_print_one(&(ranges[i]), ptr);
+
+ if (i < ranges_count - 1)
+ *(ptr++) = ' ';
+ }
+
+ return str;
+}
+
+/* end of bitmap helper extension */
+
+static inline bool stm32l4_is_otp(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return bank->base == stm32l4_info->part_info->otp_base;
+}
+
+static int stm32l4_otp_enable(struct flash_bank *bank, bool enable)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ if (!stm32l4_is_otp(bank))
+ return ERROR_FAIL;
+
+ char *op_str = enable ? "enabled" : "disabled";
+
+ LOG_INFO("OTP memory (bank #%d) is %s%s for write commands",
+ bank->bank_number,
+ stm32l4_info->otp_enabled == enable ? "already " : "",
+ op_str);
+
+ stm32l4_info->otp_enabled = enable;
+
+ return ERROR_OK;
+}
+
+static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return stm32l4_info->otp_enabled;
+}
+
+static void stm32l4_sync_rdp_tzen(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ bool tzen = false;
+
+ if (stm32l4_info->part_info->flags & F_HAS_TZ)
+ tzen = (stm32l4_info->optr & FLASH_TZEN) != 0;
+
+ uint32_t rdp = stm32l4_info->optr & FLASH_RDP_MASK;
+
+ /* for devices without TrustZone:
+ * RDP level 0 and 2 values are to 0xAA and 0xCC
+ * Any other value corresponds to RDP level 1
+ * for devices with TrusZone:
+ * RDP level 0 and 2 values are 0xAA and 0xCC
+ * RDP level 0.5 value is 0x55 only if TZEN = 1
+ * Any other value corresponds to RDP level 1, including 0x55 if TZEN = 0
+ */
+
+ if (rdp != RDP_LEVEL_0 && rdp != RDP_LEVEL_2) {
+ if (!tzen || (tzen && rdp != RDP_LEVEL_0_5))
+ rdp = RDP_LEVEL_1;
+ }
+
+ stm32l4_info->tzen = tzen;
+ stm32l4_info->rdp = rdp;
+}
+