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
|
//! 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
__pre_init:
ldr r0, =__imxrt_family @ Need to know which chip family we're initializing.
ldr r1, =1180
cmp r0, r1 @ Is this an 1180?
beq flexram_1180
ldr r1, =1100
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 copy_from_flash
flexram_1180:
ldr r0, =0x444F0060 @ M33_CONFIG
ldr r1, =__flexram_config
str r1, [r0, #0]
copy_from_flash:
# Conditionally copy text.
ldr r0, =__stext
ldr r2, =__sitext
cmp r2, r0
beq 42f
ldr r1, =__etext
43:
cmp r1, r0
beq 42f
ldm r2!, {{r3}}
stm r0!, {{r3}}
b 43b
42:
# Conditionally copy the vector table.
ldr r0, =__svector_table
ldr r2, =__sivector_table
cmp r2, r0
beq 52f
ldr r1, =__evector_table
53:
cmp r1, r0
beq 52f
ldm r2!, {{r3}}
stm r0!, {{r3}}
b 53b
52:
# Conditionally copy read-only data.
ldr r0, =__srodata
ldr r2, =__sirodata
cmp r2, r0
beq 62f
ldr r1, =__erodata
63:
cmp r1, r0
beq 62f
ldm r2!, {{r3}}
stm r0!, {{r3}}
b 63b
62:
# 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 {
extern "C" {
static mut __eheap: c_void;
}
// It used to be unsafe. Keeping it unsafe is backwards
// compatible.
#[allow(unused_unsafe)]
unsafe {
core::ptr::addr_of_mut!(__eheap) as _
}
}
|