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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#![allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)]

use crate::system::{
    glb::{self, *},
    hbn::{
        self, HBN_32K_CLK_Type, HBN_32K_Sel, HBN_Power_On_Xtal_32K, HBN_Set_XCLK_CLK_Sel,
        HBN_XCLK_CLK_Type,
    },
    pds,
};

pub const BSP_FCLK_DIV: u8 = 0;
pub const BSP_BCLK_DIV: u8 = 1;

#[repr(C)]
pub enum system_clock_type {
    ///  clock source before fclk_div
    SYSTEM_CLOCK_ROOT_CLOCK = 0,
    ///  clock source after fclk_div
    SYSTEM_CLOCK_FCLK,
    ///  clock source after bclk_div
    SYSTEM_CLOCK_BCLK,
    ///  xtal clock
    SYSTEM_CLOCK_XCLK,
    ///  32K clock
    SYSTEM_CLOCK_32K_CLK,
    ///  audio PLL clock
    SYSTEM_CLOCK_AUPLL,
}

/// This is late system init, called to reconfigure clocks as per users configuration
pub fn board_clock_init() {
    system_clock_init();
    peripheral_clock_init();
}

pub fn system_clock_init() {
    // select root clock
    GLB_Set_System_CLK(
        GLB_DLL_XTAL_Type::GLB_DLL_XTAL_32M,
        GLB_SYS_CLK_Type::GLB_SYS_CLK_DLL144M,
    );

    // set fclk/hclk and bclk clock
    GLB_Set_System_CLK_Div(BSP_FCLK_DIV, BSP_BCLK_DIV);
    // Set MTimer the same frequency as SystemCoreClock
    GLB_Set_MTimer_CLK(
        1,
        GLB_MTIMER_CLK_Type::GLB_MTIMER_CLK_BCLK,
        mtimer_get_clk_src_div() as u8,
    );

    // TODO: set audio PLL
    //  PDS_Set_Audio_PLL_Freq(BSP_AUDIO_PLL_CLOCK_SOURCE - ROOT_CLOCK_SOURCE_AUPLL_12288000_HZ);
    HBN_Power_On_Xtal_32K();
    HBN_32K_Sel(HBN_32K_CLK_Type::HBN_32K_XTAL);

    HBN_Set_XCLK_CLK_Sel(HBN_XCLK_CLK_Type::HBN_XCLK_CLK_XTAL);
}

pub fn peripheral_clock_init() {
    peripheral_clock_gate_all();
    unsafe {
        glb::ptr().cgen_cfg1.modify(|r, w| {
            w.uart0().set_bit();
            w.uart1().set_bit();
            w
        });
    }
}

/// This is early system init - called from preinit in the C SDK
pub fn system_init() {
    unsafe { riscv::interrupt::disable() };
    let pds = unsafe { pds::ptr() };
    let glb = unsafe { glb::ptr() };
    let hbn = unsafe { hbn::ptr() };
    let efuse0 = unsafe { &*bl702_pac::EF_DATA_0::ptr() };
    pds.pds_int.modify(|_r, w| {
        w.cr_pds_wake_int_mask().set_bit(); // mask pds wakeup
        w.cr_pds_rf_done_int_mask().set_bit(); // mask rf done
        w.cr_pds_pll_done_int_mask().set_bit(); // mask all pds wakeup source int
        unsafe {
            // mask all pds wakeup source int
            w.cr_pds_wakeup_src_en().bits(0);
        }
        w
    });

    // GLB_Set_EM_Sel(GLB_EM_0KB);
    glb.seam_misc.modify(|_r, w| unsafe { w.em_sel().bits(0) });

    /* Restore default setting*/
    /* GLB_UART_Sig_Swap_Set(UART_SIG_SWAP_NONE); */
    glb.glb_parm
        .modify(|_r, w| unsafe { w.uart_swap_set().bits(0) });

    /* fix 57.6M */
    if system_frequency() == 57 * 6000 * 1000 {
        unsafe {
            hbn.hbn_rsv2.write_with_zero(|w| {
                // Add 0.5 for const rounding
                w.hbn_rsv2().bits((57.6 * 1000.0 * 1000.0 + 0.5) as u32)
            });
        }
    }

    const CLIC_HART0_ADDR: usize = 0x02800000;
    const CLIC_INTIP: usize = 0x000;
    const CLIC_INTIE: usize = 0x400;
    const IRQ_NUM_BASE: usize = 16;
    const IRQ_QTY: usize = 64;
    const IRQ_ITER_END: usize = (IRQ_NUM_BASE + IRQ_QTY + 2) / 4;
    // TODO: create HAL CLIC interface rather than interact directly here
    // Clear all interrupts
    let clic_e = (CLIC_HART0_ADDR + CLIC_INTIE) as *mut usize;
    for i in 0..IRQ_ITER_END {
        unsafe { clic_e.wrapping_add(i).write_volatile(0) };
    }
    let clic_p = (CLIC_HART0_ADDR + CLIC_INTIP) as *mut usize;
    for i in 0..IRQ_ITER_END {
        unsafe { clic_p.wrapping_add(i).write_volatile(0) };
    }

    // TODO: update SVD with these fields
    // SF io select from efuse value
    let fuse = efuse0.ef_key_slot_5_w2.read().ef_key_slot_5_w2().bits();
    let flash_cfg = (fuse >> 26) & 7;
    let psram_cfg = (fuse >> 24) & 3;

    let is_internal_flash = flash_cfg == 1 || flash_cfg == 2;
    let is_internal_psram = psram_cfg == 1;

    glb.gpio_use_psram__io.modify(|_r, w| {
        unsafe {
            if is_internal_flash && !is_internal_psram {
                w.bits(0x3f);
            } else {
                w.bits(0);
            }
        }
        w
    });

    // TODO: register USB handler (if this isn't done at link time)
    // #ifdef BFLB_EFLASH_LOADER
    //     Interrupt_Handler_Register(USB_IRQn, USB_DoNothing_IRQHandler);
    // #endif

    // HBN_BOR_CFG_Type borCfg = { 0 /* pu_bor */, 0 /* irq_bor_en */, 1 /* bor_vth */, 0 /* bor_sel */ };
    hbn.hbn_irq_mode.modify(|_r, w| {
        w.irq_bor_en().clear_bit();
        w
    });

    hbn.hbn_misc.modify(|_r, w| {
        w.pu_bor().clear_bit();
        w.bor_vth().set_bit();
        w.bor_sel().clear_bit();
        w
    });

    unsafe { riscv::interrupt::enable() };
}

pub fn system_frequency() -> u32 {
    let hbn = unsafe { &*bl702_pac::HBN::ptr() };
    hbn.hbn_rsv2.read().hbn_rsv2().bits()
}

fn mtimer_get_clk_src_div() -> u32 {
    system_clock_get(system_clock_type::SYSTEM_CLOCK_BCLK) / 1000 / 1000 - 1
}

fn system_clock_get(t: system_clock_type) -> u32 {
    let clksel = GLB_Get_Root_CLK_Sel();
    match t {
        system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK => {
            if clksel == GLB_ROOT_CLK_Type::GLB_ROOT_CLK_RC32M
                || clksel == GLB_ROOT_CLK_Type::GLB_ROOT_CLK_XTAL
            {
                32 * 1000 * 1000
            } else {
                let pll_sel = unsafe { glb::ptr().clk_cfg0.read().reg_pll_sel().bits() };
                match pll_sel {
                    // + 0.5 to round as a const expression
                    0 => (57.6 * 1000.0 * 1000.0 + 0.5) as u32,
                    1 => 96 * 1000 * 1000,
                    2 => 144 * 1000 * 1000,
                    _ => 0,
                }
            }
        }
        system_clock_type::SYSTEM_CLOCK_FCLK => {
            system_clock_get(system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK)
                / (GLB_Get_HCLK_Div() as u32 + 1)
        }
        system_clock_type::SYSTEM_CLOCK_BCLK => {
            system_clock_get(system_clock_type::SYSTEM_CLOCK_ROOT_CLOCK)
                / (GLB_Get_HCLK_Div() as u32 + 1)
                / (GLB_Get_BCLK_Div() as u32 + 1)
        }
        system_clock_type::SYSTEM_CLOCK_XCLK => 32000000,
        system_clock_type::SYSTEM_CLOCK_32K_CLK => 32000,
        // TODO: lookup!
        system_clock_type::SYSTEM_CLOCK_AUPLL => 12288000,
    }
}