aboutsummaryrefslogtreecommitdiff
path: root/src/target.rs
blob: 96ae9f7d1374a6f5aa9c8efdb2d14ca7eb38a343 (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
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
//! i.MX RT target support.
//!
//! Defines a `cortex-m-rt` pre-init function that disables watchdogs and initializes TCM.
//! It then copies instructions, read-only data, and the vector table to their intended location.
//! This only happens if LMAs and VMAs differ.
//!
//! There's a few behaviors worth mentioning:
//!
//! - The implementation never clears the INIT_xTCM_EN bits in GPR16 if the xTCM is unused.
//!   The first reason is because we can't do this on the 1170 chips; the bits are reserved and
//!   should always be set (guessing its for the CM4, which always uses TCM). The second reason
//!   is that it doesn't seem necessary; we'll let xTCM initialize out of non-POR reset. From what
//!   I could gather, this would be the case if we set fuse values to specify an all-OCRAM config,
//!   and nothing says we need to flip these bits if the _fuses_ don't allocate xTCM. (Maybe this
//!   automagically happens? Not sure.)
//! - We're not changing CM7_xTCMSZ to reflect the xTCM sizes. Again, the setting isn't available
//!   on the 1170 chips. It's also OK to keep the POR value, since it represents the maximum-possible
//!   TCM size. This means that users have finer control over xTCM memory sizes, but invalid xTCM accesses
//!   won't cause a bus fault. See 3.1.3.2. in AN12077 for more discussion.
//!
//! Other notes:
//!
//! It's important that something sets the stack pointer. On the 10xx, the boot ROM sets the stack
//! pointer. But on the 11xx, the boot ROM doesn't set the stack pointer. See the link below for
//! more information. This implementation relies on the cortex-m-rt 0.7.2 "set-sp" feature to always
//! set the stack pointer, no matter the target chip.
//!
//! <https://community.nxp.com/t5/i-MX-RT/RT1176-ROM-code-does-not-set-stack-pointer-correctly/td-p/1388830>

use core::{arch::global_asm, ffi::c_void};

pub use cortex_m_rt::*;

global_asm! {r#"
.cfi_sections .debug_frame
.section .__pre_init,"ax"
.global __pre_init
.type __pre_init,%function
.thumb_func
.cfi_startproc

.macro copy_section dst, src, end
    ldr r0, =\dst
    ldr r2, =\src
    cmp r2, r0
    beq 999f

    ldr r1, =\end
    888:
    cmp r1, r0
    beq 999f
    ldm r2!, {{r3}}
    stm r0!, {{r3}}
    b 888b
    999:
.endm

__pre_init:
    ldr r0, =__imxrt_rt_v0.2        @ Need to know which chip family we're initializing.
    ldr r1, =0x1180
    cmp r0, r1                      @ Is this an 1180?
    beq 1180f
    ldr r1, =0x1100
    cmp r0, r1                      @ Is this an 1160 or 1170?

    # Disable RTWODOG3.
    ite gt
    ldrgt r2, =0x40038000           @ RTWDOG base address for 11xx chips...
    ldrle r2, =0x400BC000           @ RTWDOG base address for 10xx chips...
    ldr r3, =0xD928C520             @ RTWDOG magic number
    str r3, [r2, #4]                @ RTWDOG[CNT] = 0xD928C520.
    ldr r3, [r2]                    @ r3 = RTWDOG[CS]
    bic r3, r3, #1<<7               @ r3 = r3 & !(1 << 7), clears enable.
    str r3, [r2]                    @ RTWDOG[CS] = r3

    # Prepare FlexRAM regions.
    ldr r0, =0x400AC000             @ IMXRT_IOMUXC_GPR base address for 10xx chips, overwritten if actually 11xx...
    ldr r1, =__flexram_config       @ Value for GPR17 (and GPR18 for 11xx)
    itttt gt                        @ Need a few extra operations to handle 11xx split banks.
    ldrgt r0, =0x400E4000           @ IMXRT_IOMUXC_GPR base address for 11xx chips, overwrite 10xx address...
    lsrgt r2, r1, #16               @ r2 = ((unsigned)r1 >> 16)
    strgt r2, [r0, #72]             @ *(IMXRT_IOMUXC_GPR + 18) = r2
    ubfxgt r1, r1, #0, #16          @ r1 = ((unsigned)r1 >> 0) & 0xFFFF, overwrite r1 with lower halfword.
    str r1, [r0, #68]               @ *(IMXRT_IOMUXC_GPR + 17) = r1
    ldr r1, [r0, #64]               @ r1 = *(IMXRT_IOMUXC_GPR + 16)
    orr r1, r1, #1<<2               @ r1 |= 1 << 2
    str r1, [r0, #64]               @ *(IMXRT_IOMUXC_GPR + 16) = r1
    b 1000f

    1180:
    ldr r0, =0x444F0060             @ M33_CONFIG
    ldr r1, =__flexram_config
    str r1, [r0, #0]

    1000:
    copy_section __stext            , __sitext          , __etext
    copy_section __svector_table    , __sivector_table  , __evector_table
    copy_section __srodata          , __sirodata        , __erodata

    # All done; back to the reset handler.
    bx lr

.cfi_endproc
.size __pre_init, . - __pre_init
"#
}

/// Returns a pointer to the end of the heap.
///
/// The returned pointer is guaranteed to be 4-byte aligned.
#[inline]
pub fn heap_end() -> *mut u32 {
    unsafe extern "C" {
        static mut __eheap: c_void;
    }
    &raw mut __eheap as _
}