aboutsummaryrefslogtreecommitdiff
path: root/platforms/chibios/boards/GENERIC_STM32_G0B1XB/board/extra.c
blob: 4dbc5dd8b4aeb671475c325b750b9d1e24ff4514 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright 2025 Stefan Kerkmann (@karlk90)
// SPDX-License-Identifier: GPL-2.0-or-later

#include <hal.h>

#define FLASH_KEY1 0x45670123U
#define FLASH_KEY2 0xCDEF89ABU
#define FLASH_OPTKEY1 0x08192A3BU
#define FLASH_OPTKEY2 0x4C5D6E7FU
#define FLASH_OPTR_CLR_MASK (FLASH_OPTR_nBOOT_SEL)
#define FLASH_OPTR_SET_MASK (FLASH_OPTR_NRST_MODE_Msk)

static void wait_for_flash(void) {
    while (READ_BIT(FLASH->SR, FLASH_SR_BSY1)) {
    }
}

void __attribute__((constructor)) enable_boot0_and_nrst_pin(void) {
    // Only apply on STM32G0x1 devices, see RM0444 Rev 6, Table 265: "DEV_ID
    // and REV_ID field values."
    switch (READ_BIT(DBG->IDCODE, DBG_IDCODE_DEV_ID)) {
        case 0x467: // STM32G0B1xx and STM32G0C1xx
        case 0x460: // STM32G071xx and STM32G081xx
        case 0x456: // STM32G051xx and STM32G061xx
        case 0x466: // STM32G041xx and STM32G031xx
            break;
        default:
            return;
    }

    uint32_t optr = FLASH->OPTR;

    // Make sure that:
    // 1. legacy boot0 pin handling is enabled.
    //   OPTR[24] = 0
    // 2. legacy nRST pin handling is enabled.
    //   OPTR[28:27] = 0b11
    // To match the default behavior found in older (F0/F1/F3/F4) STM32 devices.
    if (READ_BIT(optr, FLASH_OPTR_CLR_MASK) || (READ_BIT(optr, FLASH_OPTR_SET_MASK) != FLASH_OPTR_SET_MASK)) {
        if (READ_BIT(FLASH->CR, FLASH_CR_LOCK)) {
            WRITE_REG(FLASH->KEYR, FLASH_KEY1);
            WRITE_REG(FLASH->KEYR, FLASH_KEY2);
            while (READ_BIT(FLASH->CR, FLASH_CR_LOCK)) {
            }
            wait_for_flash();
        }
        if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) {
            WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
            WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);
            while (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK)) {
            }
            wait_for_flash();
        }

        MODIFY_REG(FLASH->OPTR, FLASH_OPTR_CLR_MASK, FLASH_OPTR_SET_MASK);
        wait_for_flash();

        SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
        wait_for_flash();

        CLEAR_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
        wait_for_flash();

        // Launch the option byte (re)loading, which resets the device. This
        // should not return.
        SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
    }
}