forked from M-Labs/zynq-rs
Compare commits
214 Commits
Author | SHA1 | Date | |
---|---|---|---|
213529cf7a | |||
4cfcc75d5c | |||
578431cbc6 | |||
6188fe7d69 | |||
2713b459ed | |||
0ea7e2c760 | |||
fa660a7433 | |||
d2ec041107 | |||
48ab85bf2e | |||
d477272c5c | |||
80180ba8f6 | |||
12975de2e1 | |||
8c404829ef | |||
8f041b017c | |||
5815baf88b | |||
cc20478d91 | |||
5ef3016554 | |||
6a45a0dfd0 | |||
b2b3e5c933 | |||
0efbbe39fe | |||
51b8111e79 | |||
46dc25b89e | |||
731684abb4 | |||
195a21fe78 | |||
96cefe6f06 | |||
7c58c0cf43 | |||
9005b73316 | |||
b1994dbe16 | |||
5bd336c961 | |||
298f64a2f9 | |||
4168eb63a7 | |||
a43b8bf64e | |||
91bae572f9 | |||
301f9236e5 | |||
55b36ee37e | |||
24c804e6f0 | |||
be672ab662 | |||
0106430805 | |||
|
c15b54f92b | ||
de42a5d1b2 | |||
ff03bf92a3 | |||
f20c008264 | |||
67dbb5932f | |||
dab5c6f070 | |||
0a3a777652 | |||
92b3f3e1dd | |||
f586ba5a13 | |||
42cc256812 | |||
043a152b91 | |||
6cd32f6ee0 | |||
605c8f73a6 | |||
56c27e98e4 | |||
f496da4f3e | |||
1c8e2c318c | |||
67880b4e0b | |||
e96222ff6f | |||
dc1ca3d3d0 | |||
c4c52c33b4 | |||
072fd5f015 | |||
2b3c7e4b2f | |||
84d6d391ce | |||
43e0440911 | |||
3e95df1f64 | |||
26ab2927b9 | |||
dacc816eb4 | |||
fbc783d7ad | |||
14b0247716 | |||
bc41b91192 | |||
3efc682bd6 | |||
e5e646f40e | |||
2e7cfe04c8 | |||
24e0d724f2 | |||
823e909281 | |||
57d8d8fbc7 | |||
a4902966d1 | |||
2c161720fa | |||
a42e5a95ff | |||
03122f810a | |||
c7e9f85de2 | |||
104d1ef232 | |||
b0ec74d764 | |||
4159aab6c8 | |||
d18c77c0eb | |||
8dbe2cf9f3 | |||
040d41fd76 | |||
9180918619 | |||
8ec7216e9a | |||
0e9d3f146a | |||
411eebd96c | |||
e31adb722d | |||
759bf95a76 | |||
f83ef218de | |||
062b894a4b | |||
2f9019ca0f | |||
7b29ab2628 | |||
a9697ec8d8 | |||
0220cf19eb | |||
a11cb852a8 | |||
42cdedae91 | |||
823ec374ba | |||
666c077cef | |||
def17829d9 | |||
ba252e72da | |||
a2416f26a0 | |||
bf9f1e33c8 | |||
481a0eb25f | |||
05c30dd52e | |||
f816a04cef | |||
faa64c2ce8 | |||
89e4d61dc0 | |||
0b07e9fefc | |||
ccf758cc85 | |||
78d58d17ec | |||
06c646e61f | |||
7681745282 | |||
6e6612bc3e | |||
b50540915d | |||
4aa252546f | |||
b42869e655 | |||
d62c77e6e0 | |||
4555afa624 | |||
5923a66512 | |||
2c6cc58c07 | |||
b4d91e7904 | |||
4c79c797d5 | |||
966e43e14e | |||
8432ff3e30 | |||
1cd4056370 | |||
ddff295ae1 | |||
379b6b973a | |||
178ab38e35 | |||
3172aba1a8 | |||
a62ca507d0 | |||
975202a653 | |||
d76a77b443 | |||
500472b2a8 | |||
02217f27d1 | |||
a3eabf1947 | |||
a32d7abb9a | |||
0e8354faa1 | |||
07f161d9d8 | |||
ef160aa841 | |||
cb50c8d61b | |||
7bbd16f143 | |||
0714162113 | |||
5b2c779cba | |||
0a40d4f36d | |||
55f8d02da8 | |||
990fa56d6a | |||
8fd317d580 | |||
07fedddad9 | |||
0fde82a982 | |||
dffe3cb251 | |||
b9323653bb | |||
515d3bb381 | |||
7e22010d7d | |||
9ee77d8f44 | |||
e508b78b3e | |||
aef010cb14 | |||
d623913535 | |||
0efc7a616f | |||
22833ef0c6 | |||
80d12d5780 | |||
4dd8c93729 | |||
6266d28095 | |||
1796d4e236 | |||
56c94b0855 | |||
34a63d7732 | |||
27d310a937 | |||
f60d0589cc | |||
7c9edfdbd5 | |||
c336e450b1 | |||
6af453494b | |||
ac3e6983b0 | |||
338f918531 | |||
4751fd6011 | |||
e601ac9c45 | |||
a6955edf14 | |||
c634313d5e | |||
7360984efb | |||
82794d3abd | |||
450ccef18e | |||
4e18368aaf | |||
75494421c5 | |||
c4fb7b4c41 | |||
a51f8f2eea | |||
7680de26f0 | |||
7edd192c3b | |||
4fef8a7192 | |||
ae244082ed | |||
66c66447dd | |||
02c67051e8 | |||
08fd1391c5 | |||
a116142f63 | |||
157439bc88 | |||
a73df780d0 | |||
e73ec731aa | |||
73e4e4fd03 | |||
273f9ea72b | |||
671968bac3 | |||
39f672dde8 | |||
c13ca614ef | |||
bb09d25378 | |||
a1f859637a | |||
7cb2669c3b | |||
511c906d4d | |||
1ba0aa450f | |||
283bc9b810 | |||
b268fe015a | |||
64db9b0142 | |||
4b258c19f5 | |||
1a96a7550a | |||
36947104e3 | |||
11089d8a64 |
@ -1,5 +1,4 @@
|
|||||||
[target.armv7-none-eabihf]
|
[target.armv7-none-eabihf]
|
||||||
runner = "./runner.sh"
|
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Tlink.x",
|
||||||
"-C", "target-feature=a9,armv7-a,neon",
|
"-C", "target-feature=a9,armv7-a,neon",
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
|
result*
|
||||||
|
198
Cargo.lock
generated
198
Cargo.lock
generated
@ -1,182 +1,240 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60f0b0d4c0a382d2734228fd12b5a6b5dac185c60e938026fd31b265b94f9bd2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compiler_builtins"
|
name = "compiler_builtins"
|
||||||
version = "0.1.27"
|
version = "0.1.49"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core_io"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://git.m-labs.hk/M-Labs/rs-core_io.git?rev=e9d3edf027#e9d3edf0272502b0dd6c26e8a4869c2912657615"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal"
|
name = "embedded-hal"
|
||||||
version = "0.2.3"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.3",
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "experiments"
|
name = "experiments"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal",
|
||||||
"libasync 0.0.0",
|
"libasync",
|
||||||
"libboard_zynq 0.0.0",
|
"libboard_zynq",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9",
|
||||||
"libregister 0.0.0",
|
"libregister",
|
||||||
"libsupport_zynq 0.0.0",
|
"libsupport_zynq",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fatfs"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "git+https://git.m-labs.hk/M-Labs/rust-fatfs.git?rev=4b5e420084#4b5e420084fd1c4a9c105680b687523909b6469c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"byteorder",
|
||||||
|
"core_io",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9",
|
||||||
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 1.0.0",
|
||||||
"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pin-utils",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smoltcp",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field",
|
||||||
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal",
|
||||||
"libcortex_a9 0.0.0",
|
"libasync",
|
||||||
"libregister 0.0.0",
|
"libcortex_a9",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libregister",
|
||||||
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.3",
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smoltcp",
|
||||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void",
|
||||||
|
"volatile-register",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libconfig"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core_io",
|
||||||
|
"fatfs",
|
||||||
|
"libboard_zynq",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field",
|
||||||
"libregister 0.0.0",
|
"libregister",
|
||||||
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit_field",
|
||||||
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vcell",
|
||||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"volatile-register",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc",
|
||||||
"libboard_zynq 0.0.0",
|
"compiler_builtins",
|
||||||
"libcortex_a9 0.0.0",
|
"libboard_zynq",
|
||||||
"libregister 0.0.0",
|
"libcortex_a9",
|
||||||
"linked_list_allocator 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libregister",
|
||||||
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked_list_allocator",
|
||||||
|
"r0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked_list_allocator"
|
name = "linked_list_allocator"
|
||||||
version = "0.8.4"
|
version = "0.8.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.8"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managed"
|
name = "managed"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nb"
|
name = "nb"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||||
|
dependencies = [
|
||||||
|
"nb 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nb"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "r0"
|
name = "r0"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smoltcp"
|
name = "smoltcp"
|
||||||
version = "0.6.0"
|
version = "0.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags",
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"managed",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "szl"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"core_io",
|
||||||
|
"libboard_zynq",
|
||||||
|
"libconfig",
|
||||||
|
"libcortex_a9",
|
||||||
|
"libregister",
|
||||||
|
"libsupport_zynq",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcell"
|
name = "vcell"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "volatile-register"
|
name = "volatile-register"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vcell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[metadata]
|
|
||||||
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
|
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
"checksum compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "38f18416546abfbf8d801c555a0e99524453e7214f9cc9107ad49de3d5948ccc"
|
|
||||||
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
|
||||||
"checksum linked_list_allocator 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e70e46c13c0e8374c26cec5752e3347ca1087d9711de8f45aa513a7700efd73d"
|
|
||||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
|
||||||
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
|
||||||
"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
|
||||||
"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
||||||
"checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
|
||||||
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
|
|
||||||
"checksum vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
|
|
||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|
||||||
"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
|
|
||||||
|
19
Cargo.toml
19
Cargo.toml
@ -1,19 +1,20 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"libregister", "libcortex_a9",
|
"libregister",
|
||||||
"libboard_zynq", "libsupport_zynq",
|
"libcortex_a9",
|
||||||
|
"libboard_zynq",
|
||||||
|
"libsupport_zynq",
|
||||||
"libasync",
|
"libasync",
|
||||||
|
"libconfig",
|
||||||
"experiments",
|
"experiments",
|
||||||
|
"szl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
panic = "abort"
|
|
||||||
lto = false
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = true
|
debug = true
|
||||||
# Link-Time Optimization:
|
codegen-units = 1
|
||||||
# turn off if you get unusable debug symbols.
|
opt-level = 's'
|
||||||
lto = true
|
lto = true
|
||||||
opt-level = 'z' # Optimize for size.
|
debug-assertions = false
|
||||||
|
overflow-checks = false
|
||||||
|
165
LICENSE
Normal file
165
LICENSE
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
109
README.md
109
README.md
@ -1,47 +1,49 @@
|
|||||||
# Build
|
# Bare-metal Rust on Zynq-7000
|
||||||
|
|
||||||
|
Supported features:
|
||||||
|
|
||||||
|
* Clocking setup
|
||||||
|
* UART
|
||||||
|
* SDRAM setup
|
||||||
|
* Ethernet with smoltcp and async-await on TCP sockets
|
||||||
|
* SD card
|
||||||
|
* PL programming and startup
|
||||||
|
* Pure Rust SZL first-stage bootloader, with SD boot and netboot
|
||||||
|
* Control of second CPU core and message passing, with async-await support
|
||||||
|
|
||||||
|
|
||||||
|
Supported boards:
|
||||||
|
* Kasli-SoC
|
||||||
|
* ZC706
|
||||||
|
* Red Pitaya
|
||||||
|
* Cora Z7-10 (seems to also run on Cora Z7-07S, including dual-core support)
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Zynq-rs is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.4+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
|
||||||
|
|
||||||
|
You can build SZL or experiments crate for the platform of your choice by using ``nix build`` command, e.g.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cargo xbuild --release -p experiments"
|
nix build .#coraz7-experiments
|
||||||
```
|
```
|
||||||
|
|
||||||
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`
|
Alternatively, you can still use ``cargo xbuild`` within ``nix develop`` shell.
|
||||||
|
|
||||||
# Debug
|
|
||||||
|
|
||||||
## Using the Xilinx toolchain
|
|
||||||
|
|
||||||
Tested with the ZC706 board.
|
|
||||||
|
|
||||||
Run the Xilinx Microprocessor Debugger:
|
|
||||||
```shell
|
```shell
|
||||||
/opt/Xilinx/14.7/ISE_DS/EDK/bin/lin64/xmd
|
nix develop
|
||||||
|
cargo xbuild --release -p experiments
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to target (given it is connected and you have permissions):
|
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`, or `result/experiments.elf` for Nix Flakes build.
|
||||||
```tcl
|
|
||||||
connect arm hw
|
|
||||||
```
|
|
||||||
|
|
||||||
Leave xmd running.
|
## Debug
|
||||||
|
|
||||||
Start the Xilinx version of the GNU debugger with your latest build:
|
|
||||||
```shell
|
|
||||||
/opt/Xilinx/14.7/ISE_DS/EDK/gnu/arm/lin/bin/arm-xilinx-linux-gnueabi-gdb zc706
|
|
||||||
```
|
|
||||||
|
|
||||||
Connect the debugger to xmd over TCP on localhost:
|
|
||||||
```gdb
|
|
||||||
target remote :1234
|
|
||||||
```
|
|
||||||
|
|
||||||
Proceed using gdb with `load`, `c`
|
|
||||||
|
|
||||||
## Using OpenOCD
|
|
||||||
|
|
||||||
### Running on the ZC706
|
### Running on the ZC706
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cargo xbuild --release -p experiments"
|
nix develop
|
||||||
|
cargo xbuild --release -p experiments
|
||||||
cd openocd
|
cd openocd
|
||||||
openocd -f zc706.cfg
|
openocd -f zc706.cfg
|
||||||
```
|
```
|
||||||
@ -49,7 +51,8 @@ openocd -f zc706.cfg
|
|||||||
### Running on the Cora Z7-10
|
### Running on the Cora Z7-10
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix-shell --command "cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10"
|
nix develop
|
||||||
|
cargo xbuild --release -p experiments --no-default-features --features=target_coraz7
|
||||||
cd openocd
|
cd openocd
|
||||||
openocd -f cora-z7-10.cfg
|
openocd -f cora-z7-10.cfg
|
||||||
```
|
```
|
||||||
@ -60,43 +63,7 @@ openocd -f cora-z7-10.cfg
|
|||||||
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development Process
|
## License
|
||||||
|
|
||||||
Clone this repo onto your development/build machine and the raspberry pi that controls the Xilinx 7000 board
|
|
||||||
|
|
||||||
On the dev machine, the below script builds zc706 and secure copies it to the target pi (in your pi $HOME directory):
|
|
||||||
```shell
|
|
||||||
cd ~/zynq-rs
|
|
||||||
./build.sh $your_user_or_ssh_id
|
|
||||||
```
|
|
||||||
|
|
||||||
On the pi, we need an information rich environment that includes a relatively reliable `gdb` experience (that includes `ctrl-p` and `ctrl-n` command history that persists across `cgdb` executions), run:
|
|
||||||
```shell
|
|
||||||
ssh pi4
|
|
||||||
cd zynq-rs
|
|
||||||
# For ZC706, run:
|
|
||||||
./tmux.sh 0
|
|
||||||
# For Cora Z7, run:
|
|
||||||
./tmux.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Time to run your code with:
|
|
||||||
```shell
|
|
||||||
zynq-connect
|
|
||||||
zynq-restart
|
|
||||||
c
|
|
||||||
```
|
|
||||||
or, for a more succinct experience, (identical to above)
|
|
||||||
```shell
|
|
||||||
dc
|
|
||||||
dr
|
|
||||||
c
|
|
||||||
```
|
|
||||||
|
|
||||||
After every build on your dev machine, simply run:
|
|
||||||
```shell
|
|
||||||
dr
|
|
||||||
c
|
|
||||||
```
|
|
||||||
Sometimes you might need to type `load` after `dr`.
|
|
||||||
|
|
||||||
|
Copyright (C) 2019-2022 M-Labs Limited.
|
||||||
|
Released under the GNU LGPL v3. See the LICENSE file for details.
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
{
|
{
|
||||||
"abi-blacklist": [
|
|
||||||
"stdcall",
|
|
||||||
"fastcall",
|
|
||||||
"vectorcall",
|
|
||||||
"thiscall",
|
|
||||||
"win64",
|
|
||||||
"sysv64"
|
|
||||||
],
|
|
||||||
"arch": "arm",
|
"arch": "arm",
|
||||||
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
|
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
|
||||||
"emit-debug-gdb-scripts": false,
|
"emit-debug-gdb-scripts": false,
|
||||||
|
1
build.sh
1
build.sh
@ -1 +0,0 @@
|
|||||||
nix-shell --command "cargo xbuild --release -p experiments" && scp -C target/armv7-none-eabihf/release/experiments $1@rpi-4.m-labs.hk:/home/$1/zc706/zc706.elf
|
|
File diff suppressed because it is too large
Load Diff
63
default.nix
63
default.nix
@ -1,63 +0,0 @@
|
|||||||
{ # Use master branch of the overlay by default
|
|
||||||
mozillaOverlay ? import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz),
|
|
||||||
rustManifest ? ./channel-rust-nightly.toml,
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
|
||||||
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; };
|
|
||||||
rustcSrc = pkgs.fetchgit {
|
|
||||||
url = https://github.com/rust-lang/rust.git;
|
|
||||||
# master of 2020-04-25
|
|
||||||
rev = "14b15521c52549ebbb113173b4abecd124b5a823";
|
|
||||||
sha256 = "0a6bi8g636cajpdrpcfkpza95b7ss7041m9cs6hxcd7h8bf6xhwi";
|
|
||||||
fetchSubmodules = true;
|
|
||||||
};
|
|
||||||
targets = [];
|
|
||||||
rustChannelOfTargets = _channel: _date: targets:
|
|
||||||
(pkgs.lib.rustLib.fromManifestFile rustManifest {
|
|
||||||
inherit (pkgs) stdenv fetchurl patchelf;
|
|
||||||
}).rust.override { inherit targets; };
|
|
||||||
rust =
|
|
||||||
rustChannelOfTargets "nightly" null targets;
|
|
||||||
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
|
||||||
rustc = rust // { src = rustcSrc; };
|
|
||||||
cargo = rust;
|
|
||||||
});
|
|
||||||
gcc = pkgs.pkgsCross.armv7l-hf-multiplatform.buildPackages.gcc;
|
|
||||||
xbuildRustPackage = { cargoFeatures, crateSubdir, ... } @ attrs:
|
|
||||||
let
|
|
||||||
buildPkg = rustPlatform.buildRustPackage attrs;
|
|
||||||
in
|
|
||||||
buildPkg.overrideAttrs ({ name, nativeBuildInputs, ... }: {
|
|
||||||
nativeBuildInputs =
|
|
||||||
nativeBuildInputs ++ [ pkgs.cargo-xbuild ];
|
|
||||||
buildPhase = ''
|
|
||||||
pushd ${crateSubdir}
|
|
||||||
cargo xbuild --release --frozen \
|
|
||||||
--no-default-features \
|
|
||||||
--features=${cargoFeatures}
|
|
||||||
popd
|
|
||||||
'';
|
|
||||||
XARGO_RUST_SRC = "${rustcSrc}/src";
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
ls -la target/armv7-none-eabihf/release/
|
|
||||||
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
xbuildCrate = name: crate: features: xbuildRustPackage rec {
|
|
||||||
name = "${crate}";
|
|
||||||
src = ./.;
|
|
||||||
crateSubdir = crate;
|
|
||||||
cargoSha256 = "1c1qpg9by8bg93yhgllb5xs155g27qmh99pbrb681wazm8k7nwim";
|
|
||||||
cargoFeatures = features;
|
|
||||||
doCheck = false;
|
|
||||||
dontFixup = true;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
inherit pkgs rustPlatform rustcSrc gcc;
|
|
||||||
zc706 = {
|
|
||||||
experiments-zc706 = xbuildCrate "experiments-zc706" "experiments" "target_zc706";
|
|
||||||
experiments-cora = xbuildCrate "experiments-cora" "experiments" "target_cora_z7_10";
|
|
||||||
};
|
|
||||||
}
|
|
@ -2,12 +2,15 @@
|
|||||||
name = "experiments"
|
name = "experiments"
|
||||||
description = "Developing bare-metal Rust on Zynq"
|
description = "Developing bare-metal Rust on Zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
|
||||||
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10", "libsupport_zynq/target_cora_z7_10"]
|
target_coraz7 = ["libboard_zynq/target_coraz7", "libsupport_zynq/target_coraz7"]
|
||||||
|
target_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libsupport_zynq/target_ebaz4205"]
|
||||||
|
target_redpitaya = ["libboard_zynq/target_redpitaya", "libsupport_zynq/target_redpitaya"]
|
||||||
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc"]
|
||||||
default = ["target_zc706"]
|
default = ["target_zc706"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -16,5 +19,5 @@ embedded-hal = "0.2"
|
|||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
libboard_zynq = { path = "../libboard_zynq" }
|
libboard_zynq = { path = "../libboard_zynq" }
|
||||||
libsupport_zynq = { path = "../libsupport_zynq", default-features = false, features = ["panic_handler"]}
|
libsupport_zynq = { path = "../libsupport_zynq", default-features = false, features = ["panic_handler", "dummy_fiq_handler"]}
|
||||||
libasync = { path = "../libasync" }
|
libasync = { path = "../libasync" }
|
||||||
|
@ -34,6 +34,20 @@ SECTIONS
|
|||||||
__bss_end = .;
|
__bss_end = .;
|
||||||
} > OCM3
|
} > OCM3
|
||||||
|
|
||||||
|
.irq_stack1 (NOLOAD) : ALIGN(8)
|
||||||
|
{
|
||||||
|
__irq_stack1_end = .;
|
||||||
|
. += 0x100;
|
||||||
|
__irq_stack1_start = .;
|
||||||
|
} > OCM3
|
||||||
|
|
||||||
|
.irq_stack0 (NOLOAD) : ALIGN(8)
|
||||||
|
{
|
||||||
|
__irq_stack0_end = .;
|
||||||
|
. += 0x100;
|
||||||
|
__irq_stack0_start = .;
|
||||||
|
} > OCM3
|
||||||
|
|
||||||
.stack1 (NOLOAD) : ALIGN(8) {
|
.stack1 (NOLOAD) : ALIGN(8) {
|
||||||
__stack1_end = .;
|
__stack1_end = .;
|
||||||
. += 0x200;
|
. += 0x200;
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(const_in_array_repeat_expressions)]
|
#![allow(incomplete_features)]
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
|
#![feature(asm)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
|
use core::arch::asm;
|
||||||
use libasync::{
|
use libasync::{
|
||||||
delay,
|
delay,
|
||||||
smoltcp::{Sockets, TcpStream},
|
smoltcp::{Sockets, TcpStream},
|
||||||
@ -15,7 +18,7 @@ use libboard_zynq::{
|
|||||||
self as zynq,
|
self as zynq,
|
||||||
clocks::source::{ArmPll, ClockSource, IoPll},
|
clocks::source::{ArmPll, ClockSource, IoPll},
|
||||||
clocks::Clocks,
|
clocks::Clocks,
|
||||||
print, println, stdio,
|
println, stdio,
|
||||||
mpcore,
|
mpcore,
|
||||||
gic,
|
gic,
|
||||||
smoltcp::{
|
smoltcp::{
|
||||||
@ -25,17 +28,20 @@ use libboard_zynq::{
|
|||||||
},
|
},
|
||||||
time::Milliseconds,
|
time::Milliseconds,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
use libboard_zynq::print;
|
||||||
use libcortex_a9::{
|
use libcortex_a9::{
|
||||||
mutex::Mutex,
|
mutex::Mutex,
|
||||||
|
l2c::enable_l2_cache,
|
||||||
sync_channel::{Sender, Receiver},
|
sync_channel::{Sender, Receiver},
|
||||||
sync_channel,
|
sync_channel,
|
||||||
regs::{MPIDR, SP},
|
regs::{MPIDR, SP},
|
||||||
spin_lock_yield, notify_spin_lock,
|
spin_lock_yield, notify_spin_lock,
|
||||||
asm
|
asm, interrupt_handler
|
||||||
};
|
};
|
||||||
use libregister::{RegisterR, RegisterW};
|
use libregister::{RegisterR, RegisterW};
|
||||||
use libsupport_zynq::{
|
use libsupport_zynq::{
|
||||||
boot, ram,
|
boot, exception_vectors, ram,
|
||||||
};
|
};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
@ -51,14 +57,19 @@ extern "C" {
|
|||||||
|
|
||||||
static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
|
static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||||
#[no_mangle]
|
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||||
#[naked]
|
let mut gic = gic::InterruptController::gic(mpcore);
|
||||||
pub unsafe extern "C" fn IRQ() {
|
|
||||||
if MPIDR.read().cpu_id() == 1{
|
|
||||||
let mpcore = mpcore::RegisterBlock::new();
|
|
||||||
let mut gic = gic::InterruptController::new(mpcore);
|
|
||||||
let id = gic.get_interrupt_id();
|
let id = gic.get_interrupt_id();
|
||||||
|
match MPIDR.read().cpu_id(){
|
||||||
|
0 => {
|
||||||
|
if id.0 == 0 {
|
||||||
|
println!("Interrupting core0...");
|
||||||
|
gic.end_interrupt(id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1 => {
|
||||||
if id.0 == 0 {
|
if id.0 == 0 {
|
||||||
gic.end_interrupt(id);
|
gic.end_interrupt(id);
|
||||||
asm::exit_irq();
|
asm::exit_irq();
|
||||||
@ -68,14 +79,16 @@ pub unsafe extern "C" fn IRQ() {
|
|||||||
notify_spin_lock();
|
notify_spin_lock();
|
||||||
main_core1();
|
main_core1();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
stdio::drop_uart();
|
stdio::drop_uart();
|
||||||
println!("IRQ");
|
println!("IRQ");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
});
|
||||||
|
|
||||||
pub fn restart_core1() {
|
pub fn restart_core1() {
|
||||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||||
CORE1_RESTART.store(true, Ordering::Relaxed);
|
CORE1_RESTART.store(true, Ordering::Relaxed);
|
||||||
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into());
|
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into());
|
||||||
while CORE1_RESTART.load(Ordering::Relaxed) {
|
while CORE1_RESTART.load(Ordering::Relaxed) {
|
||||||
@ -85,42 +98,39 @@ pub fn restart_core1() {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
|
exception_vectors::set_vector_table(0x0);
|
||||||
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
||||||
println!("\nzc706 main");
|
enable_l2_cache(0x8);
|
||||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
println!("\nZynq experiments");
|
||||||
|
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||||
interrupt_controller.enable_interrupts();
|
interrupt_controller.enable_interrupts();
|
||||||
// ps7_init::apply();
|
|
||||||
libboard_zynq::stdio::drop_uart();
|
|
||||||
|
|
||||||
libboard_zynq::logger::init().unwrap();
|
libboard_zynq::logger::init().unwrap();
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Boot mode: {:?}",
|
"Boot mode: {:?}",
|
||||||
zynq::slcr::RegisterBlock::new()
|
zynq::slcr::RegisterBlock::slcr()
|
||||||
.boot_mode
|
.boot_mode
|
||||||
.read()
|
.read()
|
||||||
.boot_mode_pins()
|
.boot_mode_pins()
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(
|
||||||
|
feature = "target_zc706",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
const CPU_FREQ: u32 = 800_000_000;
|
const CPU_FREQ: u32 = 800_000_000;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_coraz7")]
|
||||||
const CPU_FREQ: u32 = 650_000_000;
|
const CPU_FREQ: u32 = 650_000_000;
|
||||||
|
|
||||||
info!("Setup clock sources...");
|
info!("Setup clock sources...");
|
||||||
ArmPll::setup(2 * CPU_FREQ);
|
ArmPll::setup(2 * CPU_FREQ);
|
||||||
Clocks::set_cpu_freq(CPU_FREQ);
|
Clocks::set_cpu_freq(CPU_FREQ);
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
{
|
|
||||||
IoPll::setup(1_000_000_000);
|
IoPll::setup(1_000_000_000);
|
||||||
libboard_zynq::stdio::drop_uart();
|
libboard_zynq::stdio::drop_uart();
|
||||||
}
|
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
|
||||||
{
|
|
||||||
IoPll::setup(1_000_000_000);
|
|
||||||
libboard_zynq::stdio::drop_uart();
|
|
||||||
}
|
|
||||||
info!("PLLs set up");
|
info!("PLLs set up");
|
||||||
let clocks = zynq::clocks::Clocks::get();
|
let clocks = zynq::clocks::Clocks::get();
|
||||||
info!(
|
info!(
|
||||||
@ -131,62 +141,16 @@ pub fn main_core0() {
|
|||||||
clocks.cpu_1x()
|
clocks.cpu_1x()
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
|
|
||||||
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
|
|
||||||
for i in 0..=1 {
|
|
||||||
print!("Flash {}:", i);
|
|
||||||
for b in &flash_ram[(i * 16 * 1024 * 1024)..][..128] {
|
|
||||||
print!(" {:02X}", *b);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
let _flash = flash.stop();
|
|
||||||
|
|
||||||
let timer = libboard_zynq::timer::GlobalTimer::start();
|
let timer = libboard_zynq::timer::GlobalTimer::start();
|
||||||
|
|
||||||
let mut ddr = zynq::ddr::DdrRam::new();
|
let mut ddr = zynq::ddr::DdrRam::ddrram();
|
||||||
#[cfg(not(feature = "target_zc706"))]
|
#[cfg(not(feature = "target_zc706"))]
|
||||||
ddr.memtest();
|
ddr.memtest();
|
||||||
ram::init_alloc_ddr(&mut ddr);
|
ram::init_alloc_ddr(&mut ddr);
|
||||||
|
|
||||||
#[cfg(dev)]
|
info!("Send software interrupt to core0");
|
||||||
for i in 0..=1 {
|
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core0.into());
|
||||||
let mut flash_io = flash.manual_mode(i);
|
info!("Core0 returned from interrupt");
|
||||||
// println!("rdcr={:02X}", flash_io.rdcr());
|
|
||||||
print!("Flash {} ID:", i);
|
|
||||||
for b in flash_io.rdid() {
|
|
||||||
print!(" {:02X}", b);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
print!("Flash {} I/O:", i);
|
|
||||||
for o in 0..8 {
|
|
||||||
const CHUNK: u32 = 8;
|
|
||||||
for b in flash_io.read(CHUNK * o, CHUNK as usize) {
|
|
||||||
print!(" {:02X}", b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
|
|
||||||
flash_io.dump("Read cr1", 0x35);
|
|
||||||
flash_io.dump("Read Autoboot", 0x14);
|
|
||||||
flash_io.dump("Read Bank", 0x16);
|
|
||||||
flash_io.dump("DLP Bank", 0x16);
|
|
||||||
flash_io.dump("Read ESig", 0xAB);
|
|
||||||
flash_io.dump("OTP Read", 0x4B);
|
|
||||||
flash_io.dump("DYB Read", 0xE0);
|
|
||||||
flash_io.dump("PPB Read", 0xE2);
|
|
||||||
flash_io.dump("ASP Read", 0x2B);
|
|
||||||
flash_io.dump("Password Read", 0xE7);
|
|
||||||
|
|
||||||
flash_io.write_enabled(|flash_io| {
|
|
||||||
flash_io.erase(0);
|
|
||||||
});
|
|
||||||
flash_io.write_enabled(|flash_io| {
|
|
||||||
flash_io.program(0, [0x23054223; 0x100 >> 2].iter().cloned());
|
|
||||||
});
|
|
||||||
|
|
||||||
flash = flash_io.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
boot::Core1::start(false);
|
boot::Core1::start(false);
|
||||||
|
|
||||||
@ -207,8 +171,8 @@ pub fn main_core0() {
|
|||||||
// Test I2C
|
// Test I2C
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
{
|
{
|
||||||
let mut i2c = zynq::i2c::I2C::i2c();
|
let mut i2c = zynq::i2c::I2c::i2c0();
|
||||||
i2c.init();
|
i2c.init().unwrap();
|
||||||
println!("I2C bit-banging enabled");
|
println!("I2C bit-banging enabled");
|
||||||
let mut eeprom = zynq::i2c::eeprom::EEPROM::new(&mut i2c, 16);
|
let mut eeprom = zynq::i2c::eeprom::EEPROM::new(&mut i2c, 16);
|
||||||
// Write to 0x00 and 0x08
|
// Write to 0x00 and 0x08
|
||||||
@ -217,19 +181,19 @@ pub fn main_core0() {
|
|||||||
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
|
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
|
||||||
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
||||||
];
|
];
|
||||||
eeprom.write(0x00, &eeprom_buffer[0..6]);
|
eeprom.write(0x00, &eeprom_buffer[0..6]).unwrap();
|
||||||
eeprom.write(0x08, &eeprom_buffer[6..22]);
|
eeprom.write(0x08, &eeprom_buffer[6..22]).unwrap();
|
||||||
println!("Data written to EEPROM");
|
println!("Data written to EEPROM");
|
||||||
let mut eeprom_buffer = [0u8; 24];
|
let mut eeprom_buffer = [0u8; 24];
|
||||||
// Read from 0x00
|
// Read from 0x00
|
||||||
eeprom.read(0x00, &mut eeprom_buffer);
|
eeprom.read(0x00, &mut eeprom_buffer).unwrap();
|
||||||
print!("Data read from EEPROM @ 0x00: (hex) ");
|
print!("Data read from EEPROM @ 0x00: (hex) ");
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
print!("{:02x} ", eeprom_buffer[i]);
|
print!("{:02x} ", eeprom_buffer[i]);
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
// Read from 0x08
|
// Read from 0x08
|
||||||
eeprom.read(0x08, &mut eeprom_buffer);
|
eeprom.read(0x08, &mut eeprom_buffer).unwrap();
|
||||||
print!("Data read from EEPROM @ 0x08: (hex) ");
|
print!("Data read from EEPROM @ 0x08: (hex) ");
|
||||||
for i in 0..16 {
|
for i in 0..16 {
|
||||||
print!("{:02x} ", eeprom_buffer[i]);
|
print!("{:02x} ", eeprom_buffer[i]);
|
||||||
@ -237,7 +201,21 @@ pub fn main_core0() {
|
|||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
{
|
||||||
|
let mut err_cdwn = timer.countdown();
|
||||||
|
let mut err_state = true;
|
||||||
|
let mut led = zynq::error_led::ErrorLED::error_led();
|
||||||
|
task::spawn( async move {
|
||||||
|
loop {
|
||||||
|
led.toggle(err_state);
|
||||||
|
err_state = !err_state;
|
||||||
|
delay(&mut err_cdwn, Milliseconds(1000)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let eth = zynq::eth::Eth::eth0(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
||||||
const RX_LEN: usize = 4096;
|
const RX_LEN: usize = 4096;
|
||||||
@ -270,12 +248,12 @@ pub fn main_core0() {
|
|||||||
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
|
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
|
||||||
let stats_tx = stats_tx.clone();
|
let stats_tx = stats_tx.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let tx_data = (0..=255).take(4096).collect::<alloc::vec::Vec<u8>>();
|
let tx_data = (0..=255).cycle().take(4096).collect::<alloc::vec::Vec<u8>>();
|
||||||
loop {
|
loop {
|
||||||
// const CHUNK_SIZE: usize = 65536;
|
// const CHUNK_SIZE: usize = 65536;
|
||||||
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
|
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
|
||||||
match stream.send_slice(&tx_data[..]).await {
|
match stream.send_slice(&tx_data[..]).await {
|
||||||
Ok(len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
|
Ok(_len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("tx: {:?}", e);
|
warn!("tx: {:?}", e);
|
||||||
break
|
break
|
||||||
@ -331,7 +309,7 @@ static DONE: Mutex<bool> = Mutex::new(false);
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core1() {
|
pub fn main_core1() {
|
||||||
println!("Hello from core1!");
|
println!("Hello from core1!");
|
||||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||||
interrupt_controller.enable_interrupts();
|
interrupt_controller.enable_interrupts();
|
||||||
let req = unsafe { &mut CORE1_REQ.1 };
|
let req = unsafe { &mut CORE1_REQ.1 };
|
||||||
let res = unsafe { &mut CORE1_RES.0 };
|
let res = unsafe { &mut CORE1_RES.0 };
|
||||||
|
49
flake.lock
generated
Normal file
49
flake.lock
generated
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734529975,
|
||||||
|
"narHash": "sha256-ze3IJksru9dN0keqUxY0WNf8xrwfs8Ty/z9v/keyBbg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "72d11d40b9878a67c38f003c240c2d2e1811e72a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-24.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719454714,
|
||||||
|
"narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "d1c527659cf076ecc4b96a91c702d080b213801e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"ref": "snapshot/2024-08-01",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
177
flake.nix
Normal file
177
flake.nix
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
{
|
||||||
|
description = "Bare-metal Rust on Zynq-7000";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.05;
|
||||||
|
inputs.rust-overlay = {
|
||||||
|
url = "github:oxalica/rust-overlay?ref=snapshot/2024-08-01";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, rust-overlay }:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import rust-overlay) crosspkgs-overlay ]; };
|
||||||
|
|
||||||
|
rust = pkgs.rust-bin.nightly."2021-09-01".default.override {
|
||||||
|
extensions = [ "rust-src" ];
|
||||||
|
targets = [ ];
|
||||||
|
};
|
||||||
|
rustPlatform = pkgs.makeRustPlatform {
|
||||||
|
rustc = rust // {
|
||||||
|
# https://github.com/oxalica/rust-overlay/commit/c48c2d76b68dd9ede0815fec53479375c61af857
|
||||||
|
targetPlatforms = pkgs.lib.platforms.all;
|
||||||
|
tier1TargetPlatforms = pkgs.lib.platforms.all;
|
||||||
|
badTargetPlatforms = [ ];
|
||||||
|
};
|
||||||
|
cargo = rust;
|
||||||
|
};
|
||||||
|
|
||||||
|
crosspkgs-overlay = (self: super: {
|
||||||
|
pkgsCross = super.pkgsCross // {
|
||||||
|
zynq-baremetal = import super.path {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
crossSystem = {
|
||||||
|
config = "arm-none-eabihf";
|
||||||
|
libc = "newlib";
|
||||||
|
gcc.cpu = "cortex-a9";
|
||||||
|
gcc.fpu = "vfpv3";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
mkbootimage = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "mkbootimage";
|
||||||
|
version = "2.3dev";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "antmicro";
|
||||||
|
repo = "zynq-mkbootimage";
|
||||||
|
rev = "872363ce32c249f8278cf107bc6d3bdeb38d849f";
|
||||||
|
sha256 = "sha256-5FPyAhUWZDwHbqmp9J2ZXTmjaXPz+dzrJMolaNwADHs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
propagatedBuildInputs = [ pkgs.libelf pkgs.pcre ];
|
||||||
|
patchPhase =
|
||||||
|
''
|
||||||
|
substituteInPlace Makefile --replace "git rev-parse --short HEAD" "echo nix"
|
||||||
|
'';
|
||||||
|
installPhase =
|
||||||
|
''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp mkbootimage $out/bin
|
||||||
|
'';
|
||||||
|
hardeningDisable = [ "fortify" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fsbl = { board ? "zc706" }: pkgs.stdenv.mkDerivation {
|
||||||
|
name = "${board}-fsbl";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "Xilinx";
|
||||||
|
repo = "embeddedsw";
|
||||||
|
rev = "xilinx_v2022.2";
|
||||||
|
sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw=";
|
||||||
|
};
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.pkgsCross.zynq-baremetal.buildPackages.binutils
|
||||||
|
pkgs.pkgsCross.zynq-baremetal.buildPackages.gcc
|
||||||
|
];
|
||||||
|
patchPhase = ''
|
||||||
|
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
|
||||||
|
|
||||||
|
for x in lib/sw_apps/zynq_fsbl/src/Makefile lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh lib/bsp/standalone/src/arm/cortexa9/gcc/Makefile; do
|
||||||
|
substituteInPlace $x \
|
||||||
|
--replace "arm-none-eabi-" "arm-none-eabihf-"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
buildPhase = ''
|
||||||
|
cd lib/sw_apps/zynq_fsbl/src
|
||||||
|
make BOARD=${board} "CFLAGS=-DFSBL_DEBUG_INFO -g"
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
mkdir $out
|
||||||
|
cp fsbl.elf $out
|
||||||
|
'';
|
||||||
|
doCheck = false;
|
||||||
|
dontFixup = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
cargo-xbuild = pkgs.cargo-xbuild.overrideAttrs(oa: {
|
||||||
|
postPatch = "substituteInPlace src/sysroot.rs --replace 2021 2018";
|
||||||
|
});
|
||||||
|
|
||||||
|
build-crate = name: crate: features: rustPlatform.buildRustPackage rec {
|
||||||
|
name = "${crate}";
|
||||||
|
|
||||||
|
src = builtins.filterSource (path: type:
|
||||||
|
baseNameOf path != "target"
|
||||||
|
) ./.;
|
||||||
|
cargoLock = {
|
||||||
|
lockFile = ./Cargo.lock;
|
||||||
|
outputHashes = {
|
||||||
|
"core_io-0.1.0" = "sha256-0HINFWRiJx8pjMgUOL/CS336ih7SENSRh3Kah9LPRrw=";
|
||||||
|
"fatfs-0.3.6" = "sha256-Nz9hCq/1YgSXF8ltJ5ZawV0Hc8WV44KNK0tJdVnNb4U=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [ cargo-xbuild pkgs.llvmPackages_13.clang-unwrapped ];
|
||||||
|
buildPhase = ''
|
||||||
|
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
|
||||||
|
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
|
||||||
|
pushd ${crate}
|
||||||
|
cargo xbuild --release --frozen \
|
||||||
|
--no-default-features \
|
||||||
|
--features=${features}
|
||||||
|
popd
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out $out/nix-support
|
||||||
|
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
|
||||||
|
echo file binary-dist $out/${name}.elf >> $out/nix-support/hydra-build-products
|
||||||
|
'';
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
dontFixup = true;
|
||||||
|
auditable = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
targetCrates = target: {
|
||||||
|
"${target}-experiments" = build-crate "${target}-experiments" "experiments" "target_${target}";
|
||||||
|
"${target}-szl" = build-crate "${target}-szl" "szl" "target_${target}";
|
||||||
|
};
|
||||||
|
targets = ["zc706" "coraz7" "redpitaya" "kasli_soc" "ebaz4205"];
|
||||||
|
allTargetCrates = (builtins.foldl' (results: target:
|
||||||
|
results // targetCrates target
|
||||||
|
) {} targets);
|
||||||
|
|
||||||
|
szl = pkgs.runCommand "szl" {} (builtins.foldl' (commands: target:
|
||||||
|
let
|
||||||
|
szlResult = builtins.getAttr "${target}-szl" allTargetCrates;
|
||||||
|
in
|
||||||
|
commands + "ln -s ${szlResult}/szl.elf $out/szl-${target}.elf\n"
|
||||||
|
) "mkdir $out\n" targets);
|
||||||
|
in rec {
|
||||||
|
packages.x86_64-linux = {
|
||||||
|
inherit cargo-xbuild szl mkbootimage;
|
||||||
|
zc706-fsbl = fsbl { board = "zc706"; };
|
||||||
|
} // allTargetCrates ;
|
||||||
|
|
||||||
|
hydraJobs = packages.x86_64-linux;
|
||||||
|
|
||||||
|
inherit rust rustPlatform;
|
||||||
|
|
||||||
|
devShell.x86_64-linux = pkgs.mkShell {
|
||||||
|
name = "zynq-rs-dev-shell";
|
||||||
|
buildInputs = [
|
||||||
|
rust
|
||||||
|
cargo-xbuild
|
||||||
|
mkbootimage
|
||||||
|
|
||||||
|
pkgs.openocd pkgs.gdb
|
||||||
|
pkgs.openssh pkgs.rsync
|
||||||
|
pkgs.llvmPackages_13.clang-unwrapped
|
||||||
|
(pkgs.python3.withPackages(ps: [ ps.pyftdi ]))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
17
kasli_soc_por.py
Normal file
17
kasli_soc_por.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from time import sleep
|
||||||
|
from pyftdi.ftdi import Ftdi
|
||||||
|
|
||||||
|
POR = 1 << 7
|
||||||
|
|
||||||
|
def main():
|
||||||
|
dev = Ftdi()
|
||||||
|
dev.open_bitbang_from_url("ftdi://ftdi:4232h/0")
|
||||||
|
dev.set_bitmode(POR, Ftdi.BitMode.BITBANG)
|
||||||
|
dev.write_data(bytes([0]))
|
||||||
|
sleep(0.1)
|
||||||
|
dev.write_data(bytes([POR]))
|
||||||
|
sleep(0.1)
|
||||||
|
dev.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -2,17 +2,17 @@
|
|||||||
name = "libasync"
|
name = "libasync"
|
||||||
description = "low-level async support"
|
description = "low-level async support"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
#futures = { version = "0.3", default-features = false }
|
#futures = { version = "0.3", default-features = false }
|
||||||
pin-utils = "0.1.0-alpha.4"
|
pin-utils = "0.1.0-alpha.4"
|
||||||
embedded-hal = "0.2"
|
embedded-hal = "0.2"
|
||||||
nb = "0.1"
|
nb = "1.0"
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.6"
|
version = "0.7"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc"]
|
features = ["alloc"]
|
||||||
|
@ -6,7 +6,7 @@ use core::{
|
|||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, collections::VecDeque as Deque};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
//use futures::future::FutureExt;
|
//use futures::future::FutureExt;
|
||||||
use pin_utils::pin_mut;
|
use pin_utils::pin_mut;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ static VTABLE: RawWakerVTable = {
|
|||||||
/// ready should not move as long as this waker references it. That is
|
/// ready should not move as long as this waker references it. That is
|
||||||
/// the reason for keeping Tasks in a pinned box.
|
/// the reason for keeping Tasks in a pinned box.
|
||||||
fn wrap_waker(ready: &AtomicBool) -> Waker {
|
fn wrap_waker(ready: &AtomicBool) -> Waker {
|
||||||
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const _, &VTABLE)) }
|
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const (), &VTABLE)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single-threaded executor
|
/// A single-threaded executor
|
||||||
@ -44,7 +44,7 @@ pub struct Executor {
|
|||||||
/// Tasks reside on the heap, so that we just queue pointers. They
|
/// Tasks reside on the heap, so that we just queue pointers. They
|
||||||
/// must also be pinned in memory because our RawWaker is a pointer
|
/// must also be pinned in memory because our RawWaker is a pointer
|
||||||
/// to their `ready` field.
|
/// to their `ready` field.
|
||||||
tasks: RefCell<Deque<Pin<Box<Task>>>>,
|
tasks: RefCell<Vec<Pin<Box<Task>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
@ -52,7 +52,7 @@ impl Executor {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
in_block_on: RefCell::new(false),
|
in_block_on: RefCell::new(false),
|
||||||
tasks: RefCell::new(Deque::new()),
|
tasks: RefCell::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +72,7 @@ impl Executor {
|
|||||||
pin_mut!(f);
|
pin_mut!(f);
|
||||||
let ready = AtomicBool::new(true);
|
let ready = AtomicBool::new(true);
|
||||||
let waker = wrap_waker(&ready);
|
let waker = wrap_waker(&ready);
|
||||||
|
let mut backup = Vec::new();
|
||||||
let val = loop {
|
let val = loop {
|
||||||
// advance the main task
|
// advance the main task
|
||||||
if ready.load(Ordering::Relaxed) {
|
if ready.load(Ordering::Relaxed) {
|
||||||
@ -85,10 +86,9 @@ impl Executor {
|
|||||||
// println!("ran block_on");
|
// println!("ran block_on");
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!("tasks: {}", self.tasks.borrow().len());
|
// advance all tasks
|
||||||
// advance other tasks
|
core::mem::swap(&mut *self.tasks.borrow_mut(), &mut backup);
|
||||||
let next_task = self.tasks.borrow_mut().pop_front();
|
for mut task in backup.drain(..) {
|
||||||
if let Some(mut task) = next_task {
|
|
||||||
// NOTE we don't need a CAS operation here because `wake` invocations that come from
|
// NOTE we don't need a CAS operation here because `wake` invocations that come from
|
||||||
// interrupt handlers (the only source of 'race conditions' (!= data races)) are
|
// interrupt handlers (the only source of 'race conditions' (!= data races)) are
|
||||||
// "oneshot": they'll issue a `wake` and then disable themselves to not run again
|
// "oneshot": they'll issue a `wake` and then disable themselves to not run again
|
||||||
@ -106,7 +106,7 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Requeue
|
// Requeue
|
||||||
self.tasks.borrow_mut().push_back(task);
|
self.tasks.borrow_mut().push(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
|
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
|
||||||
@ -119,7 +119,7 @@ impl Executor {
|
|||||||
|
|
||||||
pub fn spawn(&self, f: impl Future + 'static) {
|
pub fn spawn(&self, f: impl Future + 'static) {
|
||||||
let task = Box::pin(Task::new(f));
|
let task = Box::pin(Task::new(f));
|
||||||
self.tasks.borrow_mut().push_back(task);
|
self.tasks.borrow_mut().push(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,17 +7,23 @@ use smoltcp::{
|
|||||||
iface::EthernetInterface,
|
iface::EthernetInterface,
|
||||||
phy::Device,
|
phy::Device,
|
||||||
socket::SocketSet,
|
socket::SocketSet,
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use crate::task;
|
use crate::task;
|
||||||
|
|
||||||
mod tcp_stream;
|
mod tcp_stream;
|
||||||
pub use tcp_stream::TcpStream;
|
pub use tcp_stream::TcpStream;
|
||||||
|
|
||||||
|
pub trait LinkCheck {
|
||||||
|
type Link;
|
||||||
|
fn is_idle(&self) -> bool;
|
||||||
|
fn check_link_change(&mut self) -> Option<Self::Link>;
|
||||||
|
}
|
||||||
|
|
||||||
static mut SOCKETS: Option<Sockets> = None;
|
static mut SOCKETS: Option<Sockets> = None;
|
||||||
|
|
||||||
pub struct Sockets {
|
pub struct Sockets {
|
||||||
sockets: RefCell<SocketSet<'static, 'static, 'static>>,
|
sockets: RefCell<SocketSet<'static>>,
|
||||||
wakers: RefCell<Vec<Waker>>,
|
wakers: RefCell<Vec<Waker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,14 +47,24 @@ impl Sockets {
|
|||||||
|
|
||||||
/// Block and run executor indefinitely while polling the smoltcp
|
/// Block and run executor indefinitely while polling the smoltcp
|
||||||
/// iface
|
/// iface
|
||||||
pub fn run<'b, 'c, 'e, D: for<'d> Device<'d>>(
|
pub fn run<'b, D: for<'d> Device<'d> + LinkCheck>(
|
||||||
iface: &mut EthernetInterface<'b, 'c, 'e, D>,
|
iface: &mut EthernetInterface<'b, D>,
|
||||||
mut get_time: impl FnMut() -> Instant,
|
mut get_time: impl FnMut() -> Instant,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
task::block_on(async {
|
task::block_on(async {
|
||||||
|
let mut last_link_check = Instant::from_millis(0);
|
||||||
|
const LINK_CHECK_INTERVAL: u64 = 500;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let instant = get_time();
|
let instant = get_time();
|
||||||
Self::instance().poll(iface, instant);
|
Self::instance().poll(iface, instant);
|
||||||
|
|
||||||
|
let dev = iface.device_mut();
|
||||||
|
if dev.is_idle() && instant >= last_link_check + Duration::from_millis(LINK_CHECK_INTERVAL) {
|
||||||
|
dev.check_link_change();
|
||||||
|
last_link_check = instant;
|
||||||
|
}
|
||||||
|
|
||||||
task::r#yield().await;
|
task::r#yield().await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -58,9 +74,9 @@ impl Sockets {
|
|||||||
unsafe { SOCKETS.as_ref().expect("Sockets") }
|
unsafe { SOCKETS.as_ref().expect("Sockets") }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll<'b, 'c, 'e, D: for<'d> Device<'d>>(
|
fn poll<'b, D: for<'d> Device<'d>>(
|
||||||
&self,
|
&self,
|
||||||
iface: &mut EthernetInterface<'b, 'c, 'e, D>,
|
iface: &mut EthernetInterface<'b, D>,
|
||||||
instant: Instant
|
instant: Instant
|
||||||
) {
|
) {
|
||||||
let processed = {
|
let processed = {
|
||||||
@ -81,7 +97,14 @@ impl Sockets {
|
|||||||
/// TODO: this was called through eg. TcpStream, another poll()
|
/// TODO: this was called through eg. TcpStream, another poll()
|
||||||
/// might want to send packets before sleeping for an interrupt.
|
/// might want to send packets before sleeping for an interrupt.
|
||||||
pub(crate) fn register_waker(waker: Waker) {
|
pub(crate) fn register_waker(waker: Waker) {
|
||||||
Self::instance().wakers.borrow_mut()
|
let mut wakers = Self::instance().wakers.borrow_mut();
|
||||||
.push(waker);
|
for (i, w) in wakers.iter().enumerate() {
|
||||||
|
if w.will_wake(&waker) {
|
||||||
|
let last = wakers.len() - 1;
|
||||||
|
wakers.swap(i, last);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wakers.push(waker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,6 +262,14 @@ impl TcpStream {
|
|||||||
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
||||||
self.with_socket(|mut socket| socket.set_timeout(duration));
|
self.with_socket(|mut socket| socket.set_timeout(duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ack_delay(&self) -> Option<Duration> {
|
||||||
|
self.with_socket(|socket| socket.ack_delay())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ack_delay(&mut self, duration: Option<Duration>) {
|
||||||
|
self.with_socket(|mut socket| socket.set_ack_delay(duration));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TcpStream {
|
impl Drop for TcpStream {
|
||||||
|
@ -2,12 +2,16 @@
|
|||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
description = "Drivers for peripherals in the Zynq PS"
|
description = "Drivers for peripherals in the Zynq PS"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = []
|
target_zc706 = []
|
||||||
target_cora_z7_10 = []
|
target_coraz7 = []
|
||||||
|
target_ebaz4205 = []
|
||||||
|
target_redpitaya = []
|
||||||
|
target_kasli_soc = []
|
||||||
|
ipv6 = [ "smoltcp/proto-ipv6" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
volatile-register = "0.2"
|
volatile-register = "0.2"
|
||||||
@ -18,8 +22,9 @@ void = { version = "1", default-features = false }
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
libasync = { path = "../libasync" }
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.6"
|
version = "0.7"
|
||||||
features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"]
|
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use core::unimplemented;
|
||||||
|
|
||||||
use libregister::{RegisterR, RegisterRW};
|
use libregister::{RegisterR, RegisterRW};
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
pub use slcr::ArmPllSource;
|
pub use slcr::ArmPllSource;
|
||||||
@ -14,7 +16,7 @@ enum CpuClockMode {
|
|||||||
|
|
||||||
impl CpuClockMode {
|
impl CpuClockMode {
|
||||||
pub fn get() -> Self {
|
pub fn get() -> Self {
|
||||||
let regs = slcr::RegisterBlock::new();
|
let regs = slcr::RegisterBlock::slcr();
|
||||||
if regs.clk_621_true.read().clk_621_true() {
|
if regs.clk_621_true.read().clk_621_true() {
|
||||||
CpuClockMode::C621
|
CpuClockMode::C621
|
||||||
} else {
|
} else {
|
||||||
@ -59,7 +61,7 @@ impl Clocks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn cpu_6x4x(&self) -> u32 {
|
pub fn cpu_6x4x(&self) -> u32 {
|
||||||
let slcr = slcr::RegisterBlock::new();
|
let slcr = slcr::RegisterBlock::slcr();
|
||||||
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
||||||
let pll = match arm_clk_ctrl.srcsel() {
|
let pll = match arm_clk_ctrl.srcsel() {
|
||||||
ArmPllSource::ArmPll => self.arm,
|
ArmPllSource::ArmPll => self.arm,
|
||||||
@ -92,7 +94,7 @@ impl Clocks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn uart_ref_clk(&self) -> u32 {
|
pub fn uart_ref_clk(&self) -> u32 {
|
||||||
let regs = slcr::RegisterBlock::new();
|
let regs = slcr::RegisterBlock::slcr();
|
||||||
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
||||||
let pll = match uart_clk_ctrl.srcsel() {
|
let pll = match uart_clk_ctrl.srcsel() {
|
||||||
slcr::PllSource::ArmPll =>
|
slcr::PllSource::ArmPll =>
|
||||||
@ -101,12 +103,14 @@ impl Clocks {
|
|||||||
self.ddr,
|
self.ddr,
|
||||||
slcr::PllSource::IoPll =>
|
slcr::PllSource::IoPll =>
|
||||||
self.io,
|
self.io,
|
||||||
|
slcr::PllSource::Emio =>
|
||||||
|
unimplemented!(),
|
||||||
};
|
};
|
||||||
pll / u32::from(uart_clk_ctrl.divisor())
|
pll / u32::from(uart_clk_ctrl.divisor())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sdio_ref_clk(&self) -> u32 {
|
pub fn sdio_ref_clk(&self) -> u32 {
|
||||||
let regs = slcr::RegisterBlock::new();
|
let regs = slcr::RegisterBlock::slcr();
|
||||||
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
||||||
let pll = match sdio_clk_ctrl.srcsel() {
|
let pll = match sdio_clk_ctrl.srcsel() {
|
||||||
slcr::PllSource::ArmPll =>
|
slcr::PllSource::ArmPll =>
|
||||||
@ -115,6 +119,8 @@ impl Clocks {
|
|||||||
self.ddr,
|
self.ddr,
|
||||||
slcr::PllSource::IoPll =>
|
slcr::PllSource::IoPll =>
|
||||||
self.io,
|
self.io,
|
||||||
|
slcr::PllSource::Emio =>
|
||||||
|
unimplemented!(),
|
||||||
};
|
};
|
||||||
pll / u32::from(sdio_clk_ctrl.divisor())
|
pll / u32::from(sdio_clk_ctrl.divisor())
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,14 @@ use super::slcr;
|
|||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
pub const PS_CLK: u32 = 33_333_333;
|
pub const PS_CLK: u32 = 33_333_333;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_coraz7")]
|
||||||
pub const PS_CLK: u32 = 50_000_000;
|
pub const PS_CLK: u32 = 50_000_000;
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
pub const PS_CLK: u32 = 33_333_333;
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
pub const PS_CLK: u32 = 33_333_333;
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
pub const PS_CLK: u32 = 33_333_333;
|
||||||
|
|
||||||
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
|
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
|
||||||
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
||||||
@ -44,7 +50,7 @@ pub trait ClockSource {
|
|||||||
|
|
||||||
/// get configured frequency
|
/// get configured frequency
|
||||||
fn freq() -> u32 {
|
fn freq() -> u32 {
|
||||||
let mut slcr = slcr::RegisterBlock::new();
|
let mut slcr = slcr::RegisterBlock::slcr();
|
||||||
let (pll_ctrl, _, _) = Self::pll_regs(&mut slcr);
|
let (pll_ctrl, _, _) = Self::pll_regs(&mut slcr);
|
||||||
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
||||||
}
|
}
|
||||||
@ -55,7 +61,7 @@ pub trait ClockSource {
|
|||||||
/// 25.10.4 PLLs
|
/// 25.10.4 PLLs
|
||||||
fn setup(target_freq: u32) {
|
fn setup(target_freq: u32) {
|
||||||
let fdiv = (target_freq / PS_CLK).min(66) as u16;
|
let fdiv = (target_freq / PS_CLK).min(66) as u16;
|
||||||
let (pll_res, pll_cp, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
|
let (pll_cp, pll_res, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
|
||||||
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
|
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.expect("PLL_FDIV_LOCK_PARAM")
|
.expect("PLL_FDIV_LOCK_PARAM")
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
use log::{debug, info, error};
|
use log::{debug, info, error};
|
||||||
use crate::{print, println};
|
use crate::{print, println};
|
||||||
use super::slcr::{self, DdriobVrefSel};
|
use super::slcr;
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
use super::slcr::DdriobVrefSel;
|
||||||
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
|
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
|
||||||
|
|
||||||
mod regs;
|
mod regs;
|
||||||
@ -10,27 +12,36 @@ mod regs;
|
|||||||
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
|
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
|
||||||
const DDR_FREQ: u32 = 666_666_666;
|
const DDR_FREQ: u32 = 666_666_666;
|
||||||
|
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_coraz7")]
|
||||||
/// Micron MT41K256M16HA-125: 800 MHz DDR3L, max supported 533 MHz
|
/// Micron MT41K256M16HA-125: 800 MHz DDR3L, max supported 533 MHz
|
||||||
const DDR_FREQ: u32 = 525_000_000;
|
const DDR_FREQ: u32 = 525_000_000;
|
||||||
|
|
||||||
/// MT41K256M16HA-125
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
const DCI_FREQ: u32 = 10_000_000;
|
/// EtronTech Memory EM6GD16EWKG-12H: 800 MHz DDR3 at 533 MHz
|
||||||
|
const DDR_FREQ: u32 = 533_333_333;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
/// Alliance Memory AS4C256M16D3B: 800 MHz DDR3 at 533 MHz
|
||||||
|
const DDR_FREQ: u32 = 533_333_333;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
/// MT41K256M16HA-125:E: 800 MHz DDR3L at 533 MHz
|
||||||
|
const DDR_FREQ: u32 = 533_333_333;
|
||||||
|
|
||||||
|
const DCI_MAX_FREQ: u32 = 10_000_000;
|
||||||
|
|
||||||
pub struct DdrRam {
|
pub struct DdrRam {
|
||||||
regs: &'static mut regs::RegisterBlock,
|
regs: &'static mut regs::RegisterBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DdrRam {
|
impl DdrRam {
|
||||||
pub fn new() -> Self {
|
pub fn ddrram() -> Self {
|
||||||
let clocks = Self::clock_setup();
|
let clocks = Self::clock_setup();
|
||||||
Self::calibrate_iob_impedance(&clocks);
|
|
||||||
Self::configure_iob();
|
Self::configure_iob();
|
||||||
|
Self::calibrate_iob_impedance(&clocks);
|
||||||
let regs = unsafe { regs::RegisterBlock::new() };
|
let regs = regs::RegisterBlock::ddrc();
|
||||||
let mut ddr = DdrRam { regs };
|
let mut ddr = DdrRam { regs };
|
||||||
ddr.configure();
|
ddr.reset_ddrc(|ddr| ddr.configure());
|
||||||
ddr.reset_ddrc();
|
|
||||||
ddr
|
ddr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +68,7 @@ impl DdrRam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_dci_divisors(clocks: &Clocks) -> (u8, u8) {
|
fn calculate_dci_divisors(clocks: &Clocks) -> (u8, u8) {
|
||||||
let target = (DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ;
|
let target = (DCI_MAX_FREQ - 1 + clocks.ddr) / DCI_MAX_FREQ;
|
||||||
|
|
||||||
let mut best = None;
|
let mut best = None;
|
||||||
let mut best_error = 0;
|
let mut best_error = 0;
|
||||||
@ -140,13 +151,23 @@ impl DdrRam {
|
|||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
let data1_config = data0_config.clone();
|
let data1_config = data0_config.clone();
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
let data0_config = slcr::DdriobConfig::zeroed()
|
let data0_config = slcr::DdriobConfig::zeroed()
|
||||||
.inp_type(slcr::DdriobInputType::VrefDifferential)
|
.inp_type(slcr::DdriobInputType::VrefDifferential)
|
||||||
.term_en(true)
|
.term_en(true)
|
||||||
.dci_type(slcr::DdriobDciType::Termination)
|
.dci_type(slcr::DdriobDciType::Termination)
|
||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
let data1_config = slcr::DdriobConfig::zeroed()
|
let data1_config = slcr::DdriobConfig::zeroed()
|
||||||
.pullup_en(true);
|
.pullup_en(true);
|
||||||
slcr.ddriob_data0.write(data0_config);
|
slcr.ddriob_data0.write(data0_config);
|
||||||
@ -160,16 +181,25 @@ impl DdrRam {
|
|||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
let diff1_config = diff0_config.clone();
|
let diff1_config = diff0_config.clone();
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
let diff0_config = slcr::DdriobConfig::zeroed()
|
let diff0_config = slcr::DdriobConfig::zeroed()
|
||||||
.inp_type(slcr::DdriobInputType::Differential)
|
.inp_type(slcr::DdriobInputType::Differential)
|
||||||
.term_en(true)
|
.term_en(true)
|
||||||
.dci_type(slcr::DdriobDciType::Termination)
|
.dci_type(slcr::DdriobDciType::Termination)
|
||||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
let diff1_config = slcr::DdriobConfig::zeroed()
|
let diff1_config = slcr::DdriobConfig::zeroed()
|
||||||
.pullup_en(true);
|
.pullup_en(true);
|
||||||
|
|
||||||
slcr.ddriob_diff0.write(diff0_config);
|
slcr.ddriob_diff0.write(diff0_config);
|
||||||
slcr.ddriob_diff1.write(diff1_config);
|
slcr.ddriob_diff1.write(diff1_config);
|
||||||
|
|
||||||
@ -186,12 +216,17 @@ impl DdrRam {
|
|||||||
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
|
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable external V[REF]
|
#[cfg(any(
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
||||||
.vref_int_en(false)
|
.vref_int_en(false)
|
||||||
.vref_ext_en_lower(true)
|
.vref_ext_en_lower(true)
|
||||||
.vref_ext_en_upper(false)
|
.vref_ext_en_upper(false)
|
||||||
|
.refio_en(true)
|
||||||
);
|
);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
||||||
@ -204,12 +239,50 @@ impl DdrRam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn configure(&mut self) {
|
fn configure(&mut self) {
|
||||||
|
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
|
||||||
|
self.regs.dram_param0.write(
|
||||||
|
regs::DramParam0::zeroed()
|
||||||
|
.t_rc(0x1a)
|
||||||
|
.t_rfc_min(0x9e)
|
||||||
|
.post_selfref_gap_x32(0x10)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
self.regs.dram_param0.write(
|
||||||
|
regs::DramParam0::zeroed()
|
||||||
|
.t_rc(0x1a)
|
||||||
|
.t_rfc_min(0x56)
|
||||||
|
.post_selfref_gap_x32(0x10)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
self.regs.dram_param0.write(
|
||||||
|
regs::DramParam0::zeroed()
|
||||||
|
.t_rc(0x1b)
|
||||||
|
.t_rfc_min(0xa0)
|
||||||
|
.post_selfref_gap_x32(0x10)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
self.regs.dram_param0.write(
|
self.regs.dram_param0.write(
|
||||||
regs::DramParam0::zeroed()
|
regs::DramParam0::zeroed()
|
||||||
.t_rc(0x1b)
|
.t_rc(0x1b)
|
||||||
.t_rfc_min(0x56)
|
.t_rfc_min(0x56)
|
||||||
.post_selfref_gap_x32(0x10)
|
.post_selfref_gap_x32(0x10)
|
||||||
);
|
);
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
self.regs.dram_param1.modify(
|
||||||
|
|_, w| w
|
||||||
|
.t_faw(0x16)
|
||||||
|
.t_ras_min(0x13)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
self.regs.dram_param1.modify(
|
||||||
|
|_, w| w
|
||||||
|
.wr2pre(0x12)
|
||||||
|
.powerdown_to_x32(6)
|
||||||
|
.t_faw(0x16)
|
||||||
|
.t_ras_max(0x24)
|
||||||
|
.t_ras_min(0x13)
|
||||||
|
.t_cke(4)
|
||||||
|
);
|
||||||
|
|
||||||
self.regs.dram_param2.write(
|
self.regs.dram_param2.write(
|
||||||
regs::DramParam2::zeroed()
|
regs::DramParam2::zeroed()
|
||||||
@ -221,6 +294,25 @@ impl DdrRam {
|
|||||||
.rd2pre(0x4)
|
.rd2pre(0x4)
|
||||||
.t_rcd(0x7)
|
.t_rcd(0x7)
|
||||||
);
|
);
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
self.regs.dram_param3.modify(
|
||||||
|
|_, w| w
|
||||||
|
.t_rp(7)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
self.regs.dram_param3.modify(
|
||||||
|
|_, w| w
|
||||||
|
.t_ccd(4)
|
||||||
|
.t_rrd(6)
|
||||||
|
.refresh_margin(2)
|
||||||
|
.t_rp(7)
|
||||||
|
.refresh_to_x32(8)
|
||||||
|
.mobile(false)
|
||||||
|
.dfi_dram_clk_disable(false)
|
||||||
|
.read_latency(7)
|
||||||
|
.mode_ddr1_ddr2(true)
|
||||||
|
.dis_pad_pd(false)
|
||||||
|
);
|
||||||
|
|
||||||
self.regs.dram_emr_mr.write(
|
self.regs.dram_emr_mr.write(
|
||||||
regs::DramEmrMr::zeroed()
|
regs::DramEmrMr::zeroed()
|
||||||
@ -228,6 +320,25 @@ impl DdrRam {
|
|||||||
.emr(0x4)
|
.emr(0x4)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
self.regs.phy_configs[2].modify(
|
||||||
|
|_, w| w.data_slice_in_use(false)
|
||||||
|
);
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
self.regs.phy_configs[3].modify(
|
||||||
|
|_, w| w.data_slice_in_use(false)
|
||||||
|
);
|
||||||
|
|
||||||
self.regs.phy_cmd_timeout_rddata_cpt.modify(
|
self.regs.phy_cmd_timeout_rddata_cpt.modify(
|
||||||
|_, w| w
|
|_, w| w
|
||||||
.rd_cmd_to_data(0x0)
|
.rd_cmd_to_data(0x0)
|
||||||
@ -260,12 +371,36 @@ impl DdrRam {
|
|||||||
.ctrlup_max(0x40)
|
.ctrlup_max(0x40)
|
||||||
);
|
);
|
||||||
|
|
||||||
self.regs.phy_init_ratio3.write(
|
#[cfg(feature = "target_zc706")]
|
||||||
|
self.regs.phy_init_ratios[3].write(
|
||||||
regs::PhyInitRatio::zeroed()
|
regs::PhyInitRatio::zeroed()
|
||||||
.wrlvl_init_ratio(0x21)
|
.wrlvl_init_ratio(0x21)
|
||||||
.gatelvl_init_ratio(0xee)
|
.gatelvl_init_ratio(0xee)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_kasli_soc"),
|
||||||
|
)]
|
||||||
|
self.regs.reg_64.modify(
|
||||||
|
|_, w| w
|
||||||
|
.phy_ctrl_slave_ratio(0x100)
|
||||||
|
.phy_invert_clkout(true)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
self.regs.reg_64.modify(
|
||||||
|
|_, w| w
|
||||||
|
.phy_bl2(false)
|
||||||
|
.phy_invert_clkout(true)
|
||||||
|
.phy_sel_logic(false)
|
||||||
|
.phy_ctrl_slave_ratio(0x100)
|
||||||
|
.phy_ctrl_slave_force(false)
|
||||||
|
.phy_ctrl_slave_delay(0)
|
||||||
|
.phy_lpddr(false)
|
||||||
|
.phy_cmd_latency(false)
|
||||||
|
);
|
||||||
|
|
||||||
self.regs.reg_65.write(
|
self.regs.reg_65.write(
|
||||||
regs::Reg65::zeroed()
|
regs::Reg65::zeroed()
|
||||||
.wr_rl_delay(0x2)
|
.wr_rl_delay(0x2)
|
||||||
@ -280,7 +415,23 @@ impl DdrRam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset DDR controller
|
/// Reset DDR controller
|
||||||
fn reset_ddrc(&mut self) {
|
fn reset_ddrc<F: FnMut(&mut Self)>(&mut self, mut f: F) {
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
let width = regs::DataBusWidth::Width32bit;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
let width = regs::DataBusWidth::Width16bit;
|
||||||
|
self.regs.ddrc_ctrl.modify(|_, w| w
|
||||||
|
.soft_rstb(false)
|
||||||
|
.powerdown_en(false)
|
||||||
|
.data_bus_width(width)
|
||||||
|
);
|
||||||
|
f(self);
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
unsafe {
|
unsafe {
|
||||||
// row/column address bits
|
// row/column address bits
|
||||||
@ -288,16 +439,19 @@ impl DdrRam {
|
|||||||
self.regs.dram_addr_map_col.write(0xFFF00000);
|
self.regs.dram_addr_map_col.write(0xFFF00000);
|
||||||
self.regs.dram_addr_map_row.write(0x0F666666);
|
self.regs.dram_addr_map_row.write(0x0F666666);
|
||||||
}
|
}
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_coraz7",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
unsafe {
|
||||||
|
// row/column address bits
|
||||||
|
self.regs.dram_addr_map_bank.write(0x00000666);
|
||||||
|
self.regs.dram_addr_map_col.write(0xFFFF0000);
|
||||||
|
self.regs.dram_addr_map_row.write(0x0F555555);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
|
||||||
let width = regs::DataBusWidth::Width32bit;
|
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
|
||||||
let width = regs::DataBusWidth::Width16bit;
|
|
||||||
self.regs.ddrc_ctrl.modify(|_, w| w
|
|
||||||
.soft_rstb(false)
|
|
||||||
.powerdown_en(false)
|
|
||||||
.data_bus_width(width)
|
|
||||||
);
|
|
||||||
self.regs.ddrc_ctrl.modify(|_, w| w
|
self.regs.ddrc_ctrl.modify(|_, w| w
|
||||||
.soft_rstb(true)
|
.soft_rstb(true)
|
||||||
.powerdown_en(false)
|
.powerdown_en(false)
|
||||||
@ -318,10 +472,18 @@ impl DdrRam {
|
|||||||
/// actually there's 1 MB more but starting at 0x0000_0000
|
/// actually there's 1 MB more but starting at 0x0000_0000
|
||||||
/// overlaps with OCM.
|
/// overlaps with OCM.
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
|
// DDR range ends at 0x3FFF_FFFF in the default SCU address
|
||||||
|
// filtering address map
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
let megabytes = 1023;
|
let megabytes = 1023;
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(any(
|
||||||
let megabytes = 511;
|
feature = "target_coraz7",
|
||||||
|
feature = "target_redpitaya",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
let megabytes = 512;
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
let megabytes = 256;
|
||||||
|
|
||||||
megabytes * 1024 * 1024
|
megabytes * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use volatile_register::{RO, RW};
|
use volatile_register::{RO, RW};
|
||||||
|
|
||||||
use libregister::{register, register_bit, register_bits, register_bits_typed};
|
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -33,14 +33,14 @@ pub struct RegisterBlock {
|
|||||||
pub lpr: RW<u32>,
|
pub lpr: RW<u32>,
|
||||||
pub wr: RW<u32>,
|
pub wr: RW<u32>,
|
||||||
pub dram_param0: DramParam0,
|
pub dram_param0: DramParam0,
|
||||||
pub dram_param1: RW<u32>,
|
pub dram_param1: DramParam1,
|
||||||
pub dram_param2: DramParam2,
|
pub dram_param2: DramParam2,
|
||||||
pub dram_param3: RW<u32>,
|
pub dram_param3: DramParam3,
|
||||||
pub dram_param4: RW<u32>,
|
pub dram_param4: RW<u32>,
|
||||||
pub dram_init_param: RW<u32>,
|
pub dram_init_param: RW<u32>,
|
||||||
pub dram_emr: RW<u32>,
|
pub dram_emr: RW<u32>,
|
||||||
pub dram_emr_mr: DramEmrMr,
|
pub dram_emr_mr: DramEmrMr,
|
||||||
pub dram_burst8_rdwr: RW<u32>,
|
pub dram_burst8_rdwr: Burst8Rdwr,
|
||||||
pub dram_disable_dq: RW<u32>,
|
pub dram_disable_dq: RW<u32>,
|
||||||
pub dram_addr_map_bank: RW<u32>,
|
pub dram_addr_map_bank: RW<u32>,
|
||||||
pub dram_addr_map_col: RW<u32>,
|
pub dram_addr_map_col: RW<u32>,
|
||||||
@ -60,7 +60,7 @@ pub struct RegisterBlock {
|
|||||||
pub ctrl6: RW<u32>,
|
pub ctrl6: RW<u32>,
|
||||||
_unused1: [RO<u32>; 8],
|
_unused1: [RO<u32>; 8],
|
||||||
pub che_refresh_timer01: RW<u32>,
|
pub che_refresh_timer01: RW<u32>,
|
||||||
pub che_t_zq: RW<u32>,
|
pub che_t_zq: CheTZq,
|
||||||
pub che_t_zq_short_interval: RW<u32>,
|
pub che_t_zq_short_interval: RW<u32>,
|
||||||
pub deep_pwrdwn: RW<u32>,
|
pub deep_pwrdwn: RW<u32>,
|
||||||
pub reg_2c: Reg2C,
|
pub reg_2c: Reg2C,
|
||||||
@ -84,15 +84,9 @@ pub struct RegisterBlock {
|
|||||||
pub che_ecc_corr_bit_mask_63_32_offset: RW<u32>,
|
pub che_ecc_corr_bit_mask_63_32_offset: RW<u32>,
|
||||||
_unused3: [RO<u32>; 5],
|
_unused3: [RO<u32>; 5],
|
||||||
pub phy_rcvr_enable: RW<u32>,
|
pub phy_rcvr_enable: RW<u32>,
|
||||||
pub phy_config0: RW<u32>,
|
pub phy_configs: [PhyConfig; 4],
|
||||||
pub phy_config1: RW<u32>,
|
|
||||||
pub phy_config2: RW<u32>,
|
|
||||||
pub phy_config3: RW<u32>,
|
|
||||||
_unused4: RO<u32>,
|
_unused4: RO<u32>,
|
||||||
pub phy_init_ratio0: PhyInitRatio,
|
pub phy_init_ratios: [PhyInitRatio; 4],
|
||||||
pub phy_init_ratio1: PhyInitRatio,
|
|
||||||
pub phy_init_ratio2: PhyInitRatio,
|
|
||||||
pub phy_init_ratio3: PhyInitRatio,
|
|
||||||
_unused5: RO<u32>,
|
_unused5: RO<u32>,
|
||||||
pub phy_rd_dqs_cfg0: RW<u32>,
|
pub phy_rd_dqs_cfg0: RW<u32>,
|
||||||
pub phy_rd_dqs_cfg1: RW<u32>,
|
pub phy_rd_dqs_cfg1: RW<u32>,
|
||||||
@ -114,7 +108,7 @@ pub struct RegisterBlock {
|
|||||||
pub wr_data_slv2: RW<u32>,
|
pub wr_data_slv2: RW<u32>,
|
||||||
pub wr_data_slv3: RW<u32>,
|
pub wr_data_slv3: RW<u32>,
|
||||||
_unused9: RO<u32>,
|
_unused9: RO<u32>,
|
||||||
pub reg_64: RW<u32>,
|
pub reg_64: Reg64,
|
||||||
pub reg_65: Reg65,
|
pub reg_65: Reg65,
|
||||||
_unused10: [RO<u32>; 3],
|
_unused10: [RO<u32>; 3],
|
||||||
pub reg69_6a0: RW<u32>,
|
pub reg69_6a0: RW<u32>,
|
||||||
@ -138,14 +132,8 @@ pub struct RegisterBlock {
|
|||||||
_unused14: [RO<u32>; 5],
|
_unused14: [RO<u32>; 5],
|
||||||
pub axi_id: RW<u32>,
|
pub axi_id: RW<u32>,
|
||||||
pub page_mask: RW<u32>,
|
pub page_mask: RW<u32>,
|
||||||
pub axi_priority_wr_port0: RW<u32>,
|
pub axi_priority_wr_ports: [RW<u32>; 4],
|
||||||
pub axi_priority_wr_port1: RW<u32>,
|
pub axi_priority_rd_ports: [AxiPriorityRd; 4],
|
||||||
pub axi_priority_wr_port2: RW<u32>,
|
|
||||||
pub axi_priority_wr_port3: RW<u32>,
|
|
||||||
pub axi_priority_rd_port0: RW<u32>,
|
|
||||||
pub axi_priority_rd_port1: RW<u32>,
|
|
||||||
pub axi_priority_rd_port2: RW<u32>,
|
|
||||||
pub axi_priority_rd_port3: RW<u32>,
|
|
||||||
_unused15: [RO<u32>; 27],
|
_unused15: [RO<u32>; 27],
|
||||||
pub excl_access_cfg0: RW<u32>,
|
pub excl_access_cfg0: RW<u32>,
|
||||||
pub excl_access_cfg1: RW<u32>,
|
pub excl_access_cfg1: RW<u32>,
|
||||||
@ -158,11 +146,7 @@ pub struct RegisterBlock {
|
|||||||
pub lpddr_ctrl3: RW<u32>,
|
pub lpddr_ctrl3: RW<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterBlock {
|
register_at!(RegisterBlock, 0xF8006000, ddrc);
|
||||||
pub unsafe fn new() -> &'static mut Self {
|
|
||||||
&mut *(0xF8006000 as *mut _)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register!(ddrc_ctrl, DdrcCtrl, RW, u32);
|
register!(ddrc_ctrl, DdrcCtrl, RW, u32);
|
||||||
register_bit!(ddrc_ctrl,
|
register_bit!(ddrc_ctrl,
|
||||||
@ -177,6 +161,14 @@ register_bits!(dram_param0, t_rc, u8, 0, 5);
|
|||||||
register_bits!(dram_param0, t_rfc_min, u8, 6, 13);
|
register_bits!(dram_param0, t_rfc_min, u8, 6, 13);
|
||||||
register_bits!(dram_param0, post_selfref_gap_x32, u8, 14, 20);
|
register_bits!(dram_param0, post_selfref_gap_x32, u8, 14, 20);
|
||||||
|
|
||||||
|
register!(dram_param1, DramParam1, RW, u32);
|
||||||
|
register_bits!(dram_param1, wr2pre, u8, 0, 4);
|
||||||
|
register_bits!(dram_param1, powerdown_to_x32, u8, 5, 9);
|
||||||
|
register_bits!(dram_param1, t_faw, u8, 10, 15);
|
||||||
|
register_bits!(dram_param1, t_ras_max, u8, 16, 21);
|
||||||
|
register_bits!(dram_param1, t_ras_min, u8, 22, 26);
|
||||||
|
register_bits!(dram_param1, t_cke, u8, 28, 31);
|
||||||
|
|
||||||
register!(dram_param2, DramParam2, RW, u32);
|
register!(dram_param2, DramParam2, RW, u32);
|
||||||
register_bits!(dram_param2, write_latency, u8, 0, 4);
|
register_bits!(dram_param2, write_latency, u8, 0, 4);
|
||||||
register_bits!(dram_param2, rd2wr, u8, 5, 9);
|
register_bits!(dram_param2, rd2wr, u8, 5, 9);
|
||||||
@ -186,10 +178,29 @@ register_bits!(dram_param2, pad_pd, u8, 20, 22);
|
|||||||
register_bits!(dram_param2, rd2pre, u8, 23, 27);
|
register_bits!(dram_param2, rd2pre, u8, 23, 27);
|
||||||
register_bits!(dram_param2, t_rcd, u8, 28, 31);
|
register_bits!(dram_param2, t_rcd, u8, 28, 31);
|
||||||
|
|
||||||
|
register!(dram_param3, DramParam3, RW, u32);
|
||||||
|
register_bits!(dram_param3, t_ccd, u8, 2, 4);
|
||||||
|
register_bits!(dram_param3, t_rrd, u8, 5, 7);
|
||||||
|
register_bits!(dram_param3, refresh_margin, u8, 8, 11);
|
||||||
|
register_bits!(dram_param3, t_rp, u8, 12, 15);
|
||||||
|
register_bits!(dram_param3, refresh_to_x32, u8, 16, 20);
|
||||||
|
register_bit!(dram_param3, sdram, 21);
|
||||||
|
register_bit!(dram_param3, mobile, 22);
|
||||||
|
register_bit!(dram_param3, dfi_dram_clk_disable, 23);
|
||||||
|
register_bits!(dram_param3, read_latency, u8, 24, 28);
|
||||||
|
register_bit!(dram_param3, mode_ddr1_ddr2, 29);
|
||||||
|
register_bit!(dram_param3, dis_pad_pd, 30);
|
||||||
|
|
||||||
register!(dram_emr_mr, DramEmrMr, RW, u32);
|
register!(dram_emr_mr, DramEmrMr, RW, u32);
|
||||||
register_bits!(dram_emr_mr, mr, u16, 0, 15);
|
register_bits!(dram_emr_mr, mr, u16, 0, 15);
|
||||||
register_bits!(dram_emr_mr, emr, u16, 16, 31);
|
register_bits!(dram_emr_mr, emr, u16, 16, 31);
|
||||||
|
|
||||||
|
register!(burst8_rdwr, Burst8Rdwr, RW, u32);
|
||||||
|
register_bits!(burst8_rdwr, burst_rdwr, u8, 0, 3);
|
||||||
|
register_bits!(burst8_rdwr, pre_cke_x1024, u16, 4, 13);
|
||||||
|
register_bits!(burst8_rdwr, post_cke_x1024, u16, 16, 25);
|
||||||
|
register_bit!(burst8_rdwr, burstchop, 28);
|
||||||
|
|
||||||
register!(phy_cmd_timeout_rddata_cpt, PhyCmdTimeoutRddataCpt, RW, u32);
|
register!(phy_cmd_timeout_rddata_cpt, PhyCmdTimeoutRddataCpt, RW, u32);
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, rd_cmd_to_data, u8, 0, 3);
|
register_bits!(phy_cmd_timeout_rddata_cpt, rd_cmd_to_data, u8, 0, 3);
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, wr_cmd_to_data, u8, 4, 7);
|
register_bits!(phy_cmd_timeout_rddata_cpt, wr_cmd_to_data, u8, 4, 7);
|
||||||
@ -202,6 +213,13 @@ register_bit!(phy_cmd_timeout_rddata_cpt, clk_stall_level, 19);
|
|||||||
register_bits!(phy_cmd_timeout_rddata_cpt, gatelvl_num_of_dq0, u8, 24, 27);
|
register_bits!(phy_cmd_timeout_rddata_cpt, gatelvl_num_of_dq0, u8, 24, 27);
|
||||||
register_bits!(phy_cmd_timeout_rddata_cpt, wrlvl_num_of_dq0, u8, 28, 31);
|
register_bits!(phy_cmd_timeout_rddata_cpt, wrlvl_num_of_dq0, u8, 28, 31);
|
||||||
|
|
||||||
|
register!(che_t_zq, CheTZq, RW, u32);
|
||||||
|
register_bit!(che_t_zq, dis_auto_zq, 0);
|
||||||
|
register_bit!(che_t_zq, ddr3, 1);
|
||||||
|
register_bits!(che_t_zq, t_mod, u8, 2, 11);
|
||||||
|
register_bits!(che_t_zq, t_zq_long_nop, u16, 12, 21);
|
||||||
|
register_bits!(che_t_zq, t_zq_short_nop, u16, 22, 31);
|
||||||
|
|
||||||
register!(reg_2c, Reg2C, RW, u32);
|
register!(reg_2c, Reg2C, RW, u32);
|
||||||
register_bits!(reg_2c, wrlvl_max_x1024, u16, 0, 11);
|
register_bits!(reg_2c, wrlvl_max_x1024, u16, 0, 11);
|
||||||
register_bits!(reg_2c, rdlvl_max_x1024, u16, 12, 23);
|
register_bits!(reg_2c, rdlvl_max_x1024, u16, 12, 23);
|
||||||
@ -216,10 +234,27 @@ register_bits!(dfi_timing, rddata_en, u8, 0, 4);
|
|||||||
register_bits!(dfi_timing, ctrlup_min, u16, 5, 14);
|
register_bits!(dfi_timing, ctrlup_min, u16, 5, 14);
|
||||||
register_bits!(dfi_timing, ctrlup_max, u16, 15, 24);
|
register_bits!(dfi_timing, ctrlup_max, u16, 15, 24);
|
||||||
|
|
||||||
|
register!(phy_config, PhyConfig, RW, u32);
|
||||||
|
register_bit!(phy_config, data_slice_in_use, 0);
|
||||||
|
register_bit!(phy_config, rdlvl_inc_mode, 1);
|
||||||
|
register_bit!(phy_config, gatelvl_inc_mode, 2);
|
||||||
|
register_bit!(phy_config, wrlvl_inc_mode, 3);
|
||||||
|
register_bits!(phy_config, dq_offset, u8, 24, 30);
|
||||||
|
|
||||||
register!(phy_init_ratio, PhyInitRatio, RW, u32);
|
register!(phy_init_ratio, PhyInitRatio, RW, u32);
|
||||||
register_bits!(phy_init_ratio, wrlvl_init_ratio, u16, 0, 9);
|
register_bits!(phy_init_ratio, wrlvl_init_ratio, u16, 0, 9);
|
||||||
register_bits!(phy_init_ratio, gatelvl_init_ratio, u16, 10, 19);
|
register_bits!(phy_init_ratio, gatelvl_init_ratio, u16, 10, 19);
|
||||||
|
|
||||||
|
register!(reg_64, Reg64, RW, u32);
|
||||||
|
register_bit!(reg_64, phy_bl2, 1);
|
||||||
|
register_bit!(reg_64, phy_invert_clkout, 7);
|
||||||
|
register_bit!(reg_64, phy_sel_logic, 9);
|
||||||
|
register_bits!(reg_64, phy_ctrl_slave_ratio, u16, 10, 19);
|
||||||
|
register_bit!(reg_64, phy_ctrl_slave_force, 20);
|
||||||
|
register_bits!(reg_64, phy_ctrl_slave_delay, u8, 21, 27);
|
||||||
|
register_bit!(reg_64, phy_lpddr, 29);
|
||||||
|
register_bit!(reg_64, phy_cmd_latency, 30);
|
||||||
|
|
||||||
register!(reg_65, Reg65, RW, u32);
|
register!(reg_65, Reg65, RW, u32);
|
||||||
register_bits!(reg_65, wr_rl_delay, u8, 0, 4);
|
register_bits!(reg_65, wr_rl_delay, u8, 0, 4);
|
||||||
register_bits!(reg_65, rd_rl_delay, u8, 5, 9);
|
register_bits!(reg_65, rd_rl_delay, u8, 5, 9);
|
||||||
@ -235,3 +270,10 @@ register!(mode_sts_reg,
|
|||||||
ModeStsReg, RO, u32);
|
ModeStsReg, RO, u32);
|
||||||
register_bits_typed!(mode_sts_reg, operating_mode, u8, ControllerStatus, 0, 2);
|
register_bits_typed!(mode_sts_reg, operating_mode, u8, ControllerStatus, 0, 2);
|
||||||
// (mode_sts_reg) ...
|
// (mode_sts_reg) ...
|
||||||
|
|
||||||
|
register!(axi_priority_rd, AxiPriorityRd, RW, u32);
|
||||||
|
register_bits!(axi_priority_rd, arb_pri_rd_portn, u16, 0, 9);
|
||||||
|
register_bit!(axi_priority_rd, arb_disable_aging_rd_portn, 16);
|
||||||
|
register_bit!(axi_priority_rd, arb_disable_urgent_rd_portn, 17);
|
||||||
|
register_bit!(axi_priority_rd, arb_disable_page_match_rd_portn, 18);
|
||||||
|
register_bit!(axi_priority_rd, arb_set_hpr_rd_portn, 19);
|
||||||
|
114
libboard_zynq/src/error_led.rs
Normal file
114
libboard_zynq/src/error_led.rs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
use libregister::{RegisterRW, RegisterW};
|
||||||
|
use libregister::{register, register_at, register_bit, register_bits};
|
||||||
|
use super::slcr;
|
||||||
|
|
||||||
|
pub struct ErrorLED {
|
||||||
|
regs: RegisterBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ErrorLED {
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
pub fn error_led() -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// Error LED at MIO pin 37
|
||||||
|
slcr.mio_pin_37.write(
|
||||||
|
slcr::MioPin37::zeroed()
|
||||||
|
.l3_sel(0b000)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos25)
|
||||||
|
.pullup(true)
|
||||||
|
.disable_rcvr(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::error_led_common(0xFFFF - 0x0080)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_led_common(gpio_output_mask: u16) -> Self {
|
||||||
|
// Setup register block
|
||||||
|
let self_ = Self {
|
||||||
|
regs: RegisterBlock::error_led(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup GPIO output mask
|
||||||
|
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||||
|
w.mask(gpio_output_mask)
|
||||||
|
});
|
||||||
|
|
||||||
|
self_.regs.gpio_direction.modify(|_, w| {
|
||||||
|
w.lederr(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
self_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn led_oe(&mut self, oe: bool) {
|
||||||
|
self.regs.gpio_output_enable.modify(|_, w| {
|
||||||
|
w.lederr(oe)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn led_o(&mut self, o: bool) {
|
||||||
|
self.regs.gpio_output_mask.modify(|_, w| {
|
||||||
|
w.lederr_o(o)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle(&mut self, state: bool) {
|
||||||
|
self.led_o(state);
|
||||||
|
self.led_oe(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct RegisterBlock {
|
||||||
|
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
||||||
|
pub gpio_direction: &'static mut GPIODirection,
|
||||||
|
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterBlock {
|
||||||
|
pub fn error_led() -> Self {
|
||||||
|
Self {
|
||||||
|
gpio_output_mask: GPIOOutputMask::new(),
|
||||||
|
gpio_direction: GPIODirection::new(),
|
||||||
|
gpio_output_enable: GPIOOutputEnable::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(gpio_output_mask,
|
||||||
|
/// MASK_DATA_1_LSW:
|
||||||
|
/// Maskable output data for MIO[47:32]
|
||||||
|
GPIOOutputMask, RW, u32);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_at!(GPIOOutputMask, 0xE000A008, new);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_output_mask,
|
||||||
|
/// Output for LED_ERR (MIO[37])
|
||||||
|
lederr_o, 5);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bits!(gpio_output_mask,
|
||||||
|
mask, u16, 16, 31);
|
||||||
|
|
||||||
|
register!(gpio_direction,
|
||||||
|
/// DIRM_1:
|
||||||
|
/// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||||
|
GPIODirection, RW, u32);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_at!(GPIODirection, 0xE000A244, new);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_direction,
|
||||||
|
/// Direction for LED_ERR
|
||||||
|
lederr, 5);
|
||||||
|
|
||||||
|
register!(gpio_output_enable,
|
||||||
|
/// OEN_1:
|
||||||
|
/// Output enable for MIO[53:32]
|
||||||
|
GPIOOutputEnable, RW, u32);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_at!(GPIOOutputEnable, 0xE000A248, new);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_output_enable,
|
||||||
|
/// Output enable for LED_ERR
|
||||||
|
lederr, 5);
|
||||||
|
|
@ -13,6 +13,9 @@ mod regs;
|
|||||||
pub mod rx;
|
pub mod rx;
|
||||||
pub mod tx;
|
pub mod tx;
|
||||||
|
|
||||||
|
use super::time::Milliseconds;
|
||||||
|
use embedded_hal::timer::CountDown;
|
||||||
|
|
||||||
/// Size of all the buffers
|
/// Size of all the buffers
|
||||||
pub const MTU: usize = 1536;
|
pub const MTU: usize = 1536;
|
||||||
/// Maximum MDC clock
|
/// Maximum MDC clock
|
||||||
@ -27,7 +30,7 @@ const TX_1000: u32 = 125_000_000;
|
|||||||
pub struct Buffer(pub [u8; MTU]);
|
pub struct Buffer(pub [u8; MTU]);
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Buffer([0; MTU])
|
Buffer([0; MTU])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,17 +65,31 @@ impl Gem for Gem0 {
|
|||||||
slcr.gem0_clk_ctrl.write(
|
slcr.gem0_clk_ctrl.write(
|
||||||
// 0x0050_0801: 8, 5: 100 Mb/s
|
// 0x0050_0801: 8, 5: 100 Mb/s
|
||||||
// ...: 8, 1: 1000 Mb/s
|
// ...: 8, 1: 1000 Mb/s
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
slcr::GemClkCtrl::zeroed()
|
slcr::GemClkCtrl::zeroed()
|
||||||
.clkact(true)
|
.clkact(true)
|
||||||
.srcsel(slcr::PllSource::IoPll)
|
.srcsel(slcr::PllSource::IoPll)
|
||||||
.divisor(divisor0 as u8)
|
.divisor(divisor0 as u8)
|
||||||
|
.divisor1(divisor1 as u8),
|
||||||
|
// ebaz4205 -- EMIO
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
slcr::GemClkCtrl::zeroed()
|
||||||
|
.clkact(true)
|
||||||
|
.srcsel(slcr::PllSource::Emio)
|
||||||
|
.divisor(divisor0 as u8)
|
||||||
.divisor1(divisor1 as u8)
|
.divisor1(divisor1 as u8)
|
||||||
);
|
);
|
||||||
// Enable gem0 recv clock
|
// Enable gem0 recv clock
|
||||||
slcr.gem0_rclk_ctrl.write(
|
slcr.gem0_rclk_ctrl.write(
|
||||||
// 0x0000_0801
|
// 0x0000_0801
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
|
slcr::RclkCtrl::zeroed()
|
||||||
|
.clkact(true),
|
||||||
|
// ebaz4205 -- EMIO
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
slcr::RclkCtrl::zeroed()
|
slcr::RclkCtrl::zeroed()
|
||||||
.clkact(true)
|
.clkact(true)
|
||||||
|
.srcsel(true)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -145,10 +162,13 @@ pub struct Eth<GEM: Gem, RX, TX> {
|
|||||||
tx: TX,
|
tx: TX,
|
||||||
inner: EthInner<GEM>,
|
inner: EthInner<GEM>,
|
||||||
phy: Phy,
|
phy: Phy,
|
||||||
|
/// keep track of RX path occupation to avoid needless `check_link_change()`
|
||||||
|
idle: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eth<Gem0, (), ()> {
|
impl Eth<Gem0, (), ()> {
|
||||||
pub fn default(macaddr: [u8; 6]) -> Self {
|
pub fn eth0(macaddr: [u8; 6]) -> Self {
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Manual example: 0x0000_1280
|
// Manual example: 0x0000_1280
|
||||||
// MDIO
|
// MDIO
|
||||||
@ -224,48 +244,48 @@ impl Eth<Gem0, (), ()> {
|
|||||||
// RX_CLK
|
// RX_CLK
|
||||||
slcr.mio_pin_22.write(
|
slcr.mio_pin_22.write(
|
||||||
slcr::MioPin22::zeroed()
|
slcr::MioPin22::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RX_CTRL
|
// RX_CTRL
|
||||||
slcr.mio_pin_27.write(
|
slcr.mio_pin_27.write(
|
||||||
slcr::MioPin27::zeroed()
|
slcr::MioPin27::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD3
|
// RXD3
|
||||||
slcr.mio_pin_26.write(
|
slcr.mio_pin_26.write(
|
||||||
slcr::MioPin26::zeroed()
|
slcr::MioPin26::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD2
|
// RXD2
|
||||||
slcr.mio_pin_25.write(
|
slcr.mio_pin_25.write(
|
||||||
slcr::MioPin25::zeroed()
|
slcr::MioPin25::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD1
|
// RXD1
|
||||||
slcr.mio_pin_24.write(
|
slcr.mio_pin_24.write(
|
||||||
slcr::MioPin24::zeroed()
|
slcr::MioPin24::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
// RXD0
|
// RXD0
|
||||||
slcr.mio_pin_23.write(
|
slcr.mio_pin_23.write(
|
||||||
slcr::MioPin23::zeroed()
|
slcr::MioPin23::zeroed()
|
||||||
.tri_enable(true)
|
|
||||||
.l0_sel(true)
|
.l0_sel(true)
|
||||||
|
.speed(true)
|
||||||
.io_type(slcr::IoBufferType::Hstl)
|
.io_type(slcr::IoBufferType::Hstl)
|
||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
@ -280,37 +300,50 @@ impl Eth<Gem0, (), ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gem0(macaddr: [u8; 6]) -> Self {
|
pub fn gem0(macaddr: [u8; 6]) -> Self {
|
||||||
Self::new(macaddr)
|
Self::gem_common(macaddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Eth<Gem1, (), ()> {
|
impl Eth<Gem1, (), ()> {
|
||||||
|
// TODO: Add a `eth1()`
|
||||||
|
|
||||||
pub fn gem1(macaddr: [u8; 6]) -> Self {
|
pub fn gem1(macaddr: [u8; 6]) -> Self {
|
||||||
Self::new(macaddr)
|
Self::gem_common(macaddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<GEM: Gem> Eth<GEM, (), ()> {
|
impl<GEM: Gem> Eth<GEM, (), ()> {
|
||||||
fn new(macaddr: [u8; 6]) -> Self {
|
fn gem_common(macaddr: [u8; 6]) -> Self {
|
||||||
GEM::setup_clock(TX_1000);
|
GEM::setup_clock(TX_1000);
|
||||||
|
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
{
|
||||||
|
let mut eth_reset_pin = PhyRst::rst_pin();
|
||||||
|
eth_reset_pin.reset();
|
||||||
|
}
|
||||||
|
|
||||||
let mut inner = EthInner {
|
let mut inner = EthInner {
|
||||||
gem: PhantomData,
|
gem: PhantomData,
|
||||||
link: None,
|
link: None,
|
||||||
};
|
};
|
||||||
inner.init();
|
inner.init();
|
||||||
|
|
||||||
inner.configure(macaddr);
|
inner.configure(macaddr);
|
||||||
|
|
||||||
let phy = Phy::find(&mut inner).expect("phy");
|
let phy = Phy::find(&mut inner).expect("phy");
|
||||||
phy.reset(&mut inner);
|
phy.reset(&mut inner);
|
||||||
phy.restart_autoneg(&mut inner);
|
phy.restart_autoneg(&mut inner);
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
phy.set_leds(&mut inner);
|
||||||
|
|
||||||
Eth {
|
Eth {
|
||||||
rx: (),
|
rx: (),
|
||||||
tx: (),
|
tx: (),
|
||||||
inner,
|
inner,
|
||||||
phy,
|
phy,
|
||||||
|
idle: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,6 +355,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
|||||||
tx: self.tx,
|
tx: self.tx,
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
phy: self.phy,
|
phy: self.phy,
|
||||||
|
idle: self.idle,
|
||||||
};
|
};
|
||||||
let list_addr = new_self.rx.list_addr();
|
let list_addr = new_self.rx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
@ -341,6 +375,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
|||||||
tx: tx::DescList::new(tx_size),
|
tx: tx::DescList::new(tx_size),
|
||||||
inner: self.inner,
|
inner: self.inner,
|
||||||
phy: self.phy,
|
phy: self.phy,
|
||||||
|
idle: self.idle,
|
||||||
};
|
};
|
||||||
let list_addr = &new_self.tx.list_addr();
|
let list_addr = &new_self.tx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
@ -392,17 +427,31 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
|||||||
regs::RxStatus::zeroed()
|
regs::RxStatus::zeroed()
|
||||||
.frame_recd(true)
|
.frame_recd(true)
|
||||||
);
|
);
|
||||||
|
self.idle = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ =>
|
||||||
|
self.idle = false,
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
self.inner.check_link_change(&self.phy);
|
self.idle = true;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<GEM: Gem, TX> libasync::smoltcp::LinkCheck for &mut Eth<GEM, rx::DescList, TX> {
|
||||||
|
type Link = Option<phy::Link>;
|
||||||
|
|
||||||
|
fn check_link_change(&mut self) -> Option<Self::Link> {
|
||||||
|
self.inner.check_link_change(&self.phy)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_idle(&self) -> bool {
|
||||||
|
self.idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<GEM: Gem, RX> Eth<GEM, RX, tx::DescList> {
|
impl<GEM: Gem, RX> Eth<GEM, RX, tx::DescList> {
|
||||||
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
|
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
|
||||||
self.tx.send(GEM::regs(), length)
|
self.tx.send(GEM::regs(), length)
|
||||||
@ -436,10 +485,11 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
|||||||
regs: GEM::regs(),
|
regs: GEM::regs(),
|
||||||
desc_list: &mut self.tx,
|
desc_list: &mut self.tx,
|
||||||
};
|
};
|
||||||
|
self.idle = false;
|
||||||
Some((pktref, tx_token))
|
Some((pktref, tx_token))
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
self.inner.check_link_change(&self.phy);
|
self.idle = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -457,6 +507,69 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PhyRst {
|
||||||
|
regs: regs::GpioRegisterBlock,
|
||||||
|
count_down: super::timer::global::CountDown<Milliseconds>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhyRst {
|
||||||
|
pub fn rst_pin() -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// Hardware Reset for PHY
|
||||||
|
slcr.mio_pin_47.write(
|
||||||
|
slcr::MioPin47::zeroed()
|
||||||
|
.l3_sel(0b000)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
.disable_rcvr(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Self::eth_reset_common(0xFFFF - 0x8000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delay_ms(&mut self, ms: u64) {
|
||||||
|
self.count_down.start(Milliseconds(ms));
|
||||||
|
nb::block!(self.count_down.wait()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eth_reset_common(gpio_output_mask: u16) -> Self {
|
||||||
|
let self_ = Self {
|
||||||
|
regs: regs::GpioRegisterBlock::regs(),
|
||||||
|
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup GPIO output mask
|
||||||
|
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||||
|
w.mask(gpio_output_mask)
|
||||||
|
});
|
||||||
|
|
||||||
|
self_.regs.gpio_direction.modify(|_, w| {
|
||||||
|
w.phy_rst(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
self_
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oe(&mut self, oe: bool) {
|
||||||
|
self.regs.gpio_output_enable.modify(|_, w| {
|
||||||
|
w.phy_rst(oe)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle(&mut self, o: bool) {
|
||||||
|
self.regs.gpio_output_mask.modify(|_, w| {
|
||||||
|
w.phy_rst(o)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.toggle(false); // drive phy_rst (active LOW) pin low
|
||||||
|
self.oe(true); // enable pin's output
|
||||||
|
self.delay_ms(10);
|
||||||
|
self.toggle(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct EthInner<GEM: Gem> {
|
struct EthInner<GEM: Gem> {
|
||||||
gem: PhantomData<GEM>,
|
gem: PhantomData<GEM>,
|
||||||
@ -530,7 +643,10 @@ impl<GEM: Gem> EthInner<GEM> {
|
|||||||
|
|
||||||
fn configure(&mut self, macaddr: [u8; 6]) {
|
fn configure(&mut self, macaddr: [u8; 6]) {
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
let mdc_clk_div = (clocks.cpu_1x() / MAX_MDC) + 1;
|
let mut mdc_clk_div = clocks.cpu_1x() / MAX_MDC;
|
||||||
|
if clocks.cpu_1x() % MAX_MDC > 0 {
|
||||||
|
mdc_clk_div += 1;
|
||||||
|
}
|
||||||
|
|
||||||
GEM::regs().net_cfg.write(
|
GEM::regs().net_cfg.write(
|
||||||
regs::NetCfg::zeroed()
|
regs::NetCfg::zeroed()
|
||||||
@ -539,10 +655,10 @@ impl<GEM: Gem> EthInner<GEM> {
|
|||||||
.speed(true)
|
.speed(true)
|
||||||
.no_broadcast(false)
|
.no_broadcast(false)
|
||||||
.multi_hash_en(true)
|
.multi_hash_en(true)
|
||||||
// Promiscuous mode (TODO?)
|
.rx_1536_byte_frames(true)
|
||||||
.copy_all(true)
|
|
||||||
// Remove 4-byte Frame CheckSum
|
// Remove 4-byte Frame CheckSum
|
||||||
.fcs_remove(true)
|
.fcs_remove(true)
|
||||||
|
.dis_cp_pause_frame(true)
|
||||||
// RX checksum offload
|
// RX checksum offload
|
||||||
.rx_chksum_offld_en(true)
|
.rx_chksum_offld_en(true)
|
||||||
// One of the slower speeds
|
// One of the slower speeds
|
||||||
@ -550,22 +666,23 @@ impl<GEM: Gem> EthInner<GEM> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let macaddr_msbs =
|
let macaddr_msbs =
|
||||||
(u16::from(macaddr[0]) << 8) |
|
(u16::from(macaddr[5]) << 8) |
|
||||||
u16::from(macaddr[1]);
|
u16::from(macaddr[4]);
|
||||||
let macaddr_lsbs =
|
let macaddr_lsbs =
|
||||||
(u32::from(macaddr[2]) << 24) |
|
(u32::from(macaddr[3]) << 24) |
|
||||||
(u32::from(macaddr[3]) << 16) |
|
(u32::from(macaddr[2]) << 16) |
|
||||||
(u32::from(macaddr[4]) << 8) |
|
(u32::from(macaddr[1]) << 8) |
|
||||||
u32::from(macaddr[5]);
|
u32::from(macaddr[0]);
|
||||||
GEM::regs().spec_addr1_top.write(
|
// writing to bot would disable the specific address
|
||||||
regs::SpecAddrTop::zeroed()
|
|
||||||
.addr_msbs(macaddr_msbs)
|
|
||||||
);
|
|
||||||
GEM::regs().spec_addr1_bot.write(
|
GEM::regs().spec_addr1_bot.write(
|
||||||
regs::SpecAddrBot::zeroed()
|
regs::SpecAddrBot::zeroed()
|
||||||
.addr_lsbs(macaddr_lsbs)
|
.addr_lsbs(macaddr_lsbs)
|
||||||
);
|
);
|
||||||
|
// writing to top would enable it again
|
||||||
|
GEM::regs().spec_addr1_top.write(
|
||||||
|
regs::SpecAddrTop::zeroed()
|
||||||
|
.addr_msbs(macaddr_msbs)
|
||||||
|
);
|
||||||
|
|
||||||
GEM::regs().dma_cfg.write(
|
GEM::regs().dma_cfg.write(
|
||||||
regs::DmaCfg::zeroed()
|
regs::DmaCfg::zeroed()
|
||||||
@ -595,13 +712,7 @@ impl<GEM: Gem> EthInner<GEM> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn check_link_change(&mut self, phy: &Phy) {
|
fn check_link_change(&mut self, phy: &Phy) -> Option<Option<phy::Link>> {
|
||||||
// As the PHY access takes some time, exit early if there was
|
|
||||||
// already a link. TODO: check once per second.
|
|
||||||
if self.link.is_some() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let link = phy.get_link(self);
|
let link = phy.get_link(self);
|
||||||
|
|
||||||
// Check link state transition
|
// Check link state transition
|
||||||
@ -633,6 +744,9 @@ impl<GEM: Gem> EthInner<GEM> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.link = link;
|
self.link = link;
|
||||||
|
Some(link)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,10 @@ impl PhyRegister for Control {
|
|||||||
fn addr() -> u8 {
|
fn addr() -> u8 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn page() -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for Control {
|
impl From<u16> for Control {
|
||||||
|
@ -11,6 +11,9 @@ pub struct PhyIdentifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn identify_phy<PA: PhyAccess>(pa: &mut PA, addr: u8) -> Option<PhyIdentifier> {
|
pub fn identify_phy<PA: PhyAccess>(pa: &mut PA, addr: u8) -> Option<PhyIdentifier> {
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
pa.write_phy(addr, 0x16, 0); //reset page
|
||||||
|
|
||||||
let id1 = pa.read_phy(addr, 2);
|
let id1 = pa.read_phy(addr, 2);
|
||||||
let id2 = pa.read_phy(addr, 3);
|
let id2 = pa.read_phy(addr, 3);
|
||||||
if id1 != 0xFFFF || id2 != 0xFFFF {
|
if id1 != 0xFFFF || id2 != 0xFFFF {
|
||||||
|
79
libboard_zynq/src/eth/phy/leds.rs
Normal file
79
libboard_zynq/src/eth/phy/leds.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use bit_field::BitField;
|
||||||
|
use super::{PhyRegister, Led0Control, Led1Control};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
/// LED Control Register
|
||||||
|
pub struct Leds(pub u16);
|
||||||
|
|
||||||
|
impl Leds {
|
||||||
|
pub fn led0(&self) -> Led0Control {
|
||||||
|
match self.0.get_bits(0..=3) {
|
||||||
|
0b0000 => Led0Control::OnLinkOffNoLink,
|
||||||
|
0b0001 => Led0Control::OnLinkBlinkActivityOffNoLink,
|
||||||
|
0b0010 => Led0Control::BlinkDependingOnLink,
|
||||||
|
0b0011 => Led0Control::OnActivityOffNoActivity,
|
||||||
|
0b0100 => Led0Control::BlinkActivityOffNoActivity,
|
||||||
|
0b0101 => Led0Control::OnTransmitOffNoTransmit,
|
||||||
|
0b0110 => Led0Control::OnCopperLinkOffElse,
|
||||||
|
0b0111 => Led0Control::On1000LinkOffElse,
|
||||||
|
0b1000 => Led0Control::ForceOff,
|
||||||
|
0b1001 => Led0Control::ForceOn,
|
||||||
|
0b1010 => Led0Control::ForceHiZ,
|
||||||
|
0b1011 => Led0Control::ForceBlink,
|
||||||
|
0b1100 => Led0Control::Mode1,
|
||||||
|
0b1101 => Led0Control::Mode2,
|
||||||
|
0b1110 => Led0Control::Mode3,
|
||||||
|
0b1111 => Led0Control::Mode4,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn led1(&self) -> Led1Control {
|
||||||
|
match self.0.get_bits(4..=7) {
|
||||||
|
0b0000 => Led1Control::OnReceiveOffNoReceive,
|
||||||
|
0b0001 => Led1Control::OnLinkBlinkActivityOffNoLink,
|
||||||
|
0b0010 => Led1Control::OnLinkBlinkReceiveOffNoLink,
|
||||||
|
0b0011 => Led1Control::OnActivityOffNoActivity,
|
||||||
|
0b0100 => Led1Control::BlinkActivityOffNoActivity,
|
||||||
|
0b0101 => Led1Control::On100OrFiberOffElse,
|
||||||
|
0b0110 => Led1Control::On1001000LinkOffElse,
|
||||||
|
0b0111 => Led1Control::On100LinkOffElse,
|
||||||
|
0b1000 => Led1Control::ForceOff,
|
||||||
|
0b1001 => Led1Control::ForceOn,
|
||||||
|
0b1010 => Led1Control::ForceHiZ,
|
||||||
|
0b1011 => Led1Control::ForceBlink,
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_led0(mut self, setting: Led0Control) -> Self {
|
||||||
|
self.0.set_bits(0..=3, setting as u16);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_led1(mut self, setting: Led1Control) -> Self {
|
||||||
|
self.0.set_bits(4..=7, setting as u16);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhyRegister for Leds {
|
||||||
|
fn addr() -> u8 {
|
||||||
|
0x10
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page() -> u8 {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for Leds {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
Leds(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u16> for Leds {
|
||||||
|
fn into(self) -> u16 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,10 @@ mod control;
|
|||||||
pub use control::Control;
|
pub use control::Control;
|
||||||
mod pssr;
|
mod pssr;
|
||||||
pub use pssr::PSSR;
|
pub use pssr::PSSR;
|
||||||
|
mod leds;
|
||||||
|
pub use leds::Leds;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
pub speed: LinkSpeed,
|
pub speed: LinkSpeed,
|
||||||
pub duplex: LinkDuplex,
|
pub duplex: LinkDuplex,
|
||||||
@ -26,51 +28,105 @@ pub enum LinkDuplex {
|
|||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub enum Led0Control {
|
||||||
|
OnLinkOffNoLink = 0b0000,
|
||||||
|
OnLinkBlinkActivityOffNoLink = 0b0001,
|
||||||
|
BlinkDependingOnLink = 0b0010,
|
||||||
|
OnActivityOffNoActivity = 0b0011,
|
||||||
|
BlinkActivityOffNoActivity = 0b0100,
|
||||||
|
OnTransmitOffNoTransmit = 0b0101,
|
||||||
|
OnCopperLinkOffElse = 0b0110,
|
||||||
|
On1000LinkOffElse = 0b0111,
|
||||||
|
ForceOff = 0b1000,
|
||||||
|
ForceOn = 0b1001,
|
||||||
|
ForceHiZ = 0b1010,
|
||||||
|
ForceBlink = 0b1011,
|
||||||
|
Mode1 = 0b1100,
|
||||||
|
Mode2 = 0b1101,
|
||||||
|
Mode3 = 0b1110,
|
||||||
|
Mode4 = 0b1111
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub enum Led1Control {
|
||||||
|
OnReceiveOffNoReceive = 0b0000,
|
||||||
|
OnLinkBlinkActivityOffNoLink = 0b0001,
|
||||||
|
OnLinkBlinkReceiveOffNoLink = 0b0010,
|
||||||
|
OnActivityOffNoActivity = 0b0011,
|
||||||
|
BlinkActivityOffNoActivity = 0b0100,
|
||||||
|
On100OrFiberOffElse = 0b0101,
|
||||||
|
On1001000LinkOffElse = 0b0110,
|
||||||
|
On100LinkOffElse = 0b0111,
|
||||||
|
ForceOff = 0b1000,
|
||||||
|
ForceOn = 0b1001,
|
||||||
|
ForceHiZ = 0b1010,
|
||||||
|
ForceBlink = 0b1011,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait PhyAccess {
|
pub trait PhyAccess {
|
||||||
fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
|
fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
|
||||||
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
|
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait PhyRegister {
|
||||||
|
fn addr() -> u8;
|
||||||
|
fn page() -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Phy {
|
pub struct Phy {
|
||||||
pub addr: u8,
|
pub addr: u8,
|
||||||
device: PhyDevice,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum PhyDevice {
|
|
||||||
Marvell88E1116R,
|
|
||||||
Rtl8211E,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const OUI_MARVELL: u32 = 0x005043;
|
const OUI_MARVELL: u32 = 0x005043;
|
||||||
const OUI_REALTEK: u32 = 0x000732;
|
const OUI_REALTEK: u32 = 0x000732;
|
||||||
|
const OUI_LANTIQ : u32 = 0x355969;
|
||||||
|
const OUI_ICPLUS : u32 = 0x0090c3;
|
||||||
|
|
||||||
|
//only change pages on Kasli-SoC's Marvel 88E11xx
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
const PAGE_REGISTER: u8 = 0x16;
|
||||||
|
|
||||||
impl Phy {
|
impl Phy {
|
||||||
/// Probe all addresses on MDIO for a known PHY
|
/// Probe all addresses on MDIO for a known PHY
|
||||||
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
||||||
(1..32).filter_map(|addr| {
|
(0..32).find(|addr| {
|
||||||
match identify_phy(pa, addr) {
|
match identify_phy(pa, *addr) {
|
||||||
Some(PhyIdentifier {
|
Some(PhyIdentifier {
|
||||||
oui: OUI_MARVELL,
|
oui: OUI_MARVELL,
|
||||||
|
// Marvell 88E1116R
|
||||||
model: 36,
|
model: 36,
|
||||||
..
|
..
|
||||||
}) => Some(PhyDevice::Marvell88E1116R),
|
}) => true,
|
||||||
|
Some(PhyIdentifier {
|
||||||
|
oui: OUI_MARVELL,
|
||||||
|
// Marvell 88E1512
|
||||||
|
model: 29,
|
||||||
|
..
|
||||||
|
}) => true,
|
||||||
Some(PhyIdentifier {
|
Some(PhyIdentifier {
|
||||||
oui: OUI_REALTEK,
|
oui: OUI_REALTEK,
|
||||||
|
// RTL 8211E
|
||||||
model: 0b010001,
|
model: 0b010001,
|
||||||
rev: 0b0101,
|
rev: 0b0101,
|
||||||
}) => Some(PhyDevice::Rtl8211E),
|
}) => true,
|
||||||
_ => None,
|
Some(PhyIdentifier {
|
||||||
}.map(|device| Phy { addr, device })
|
oui: OUI_LANTIQ,
|
||||||
}).next()
|
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
|
||||||
}
|
model: 0,
|
||||||
|
..
|
||||||
pub fn name(&self) -> &'static str {
|
}) => true,
|
||||||
match self.device {
|
Some(PhyIdentifier {
|
||||||
PhyDevice::Marvell88E1116R => &"Marvell 88E1116R",
|
oui: OUI_ICPLUS,
|
||||||
PhyDevice::Rtl8211E => &"RTL8211E",
|
// IP101G-DS-R01
|
||||||
|
model: 5,
|
||||||
|
rev: 4,
|
||||||
|
}) => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
|
}).map(|addr| Phy { addr })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
|
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
|
||||||
@ -78,6 +134,9 @@ impl Phy {
|
|||||||
PA: PhyAccess,
|
PA: PhyAccess,
|
||||||
PR: PhyRegister + From<u16>,
|
PR: PhyRegister + From<u16>,
|
||||||
{
|
{
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
|
||||||
|
|
||||||
pa.read_phy(self.addr, PR::addr()).into()
|
pa.read_phy(self.addr, PR::addr()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +146,9 @@ impl Phy {
|
|||||||
PR: PhyRegister + From<u16> + Into<u16>,
|
PR: PhyRegister + From<u16> + Into<u16>,
|
||||||
F: FnMut(PR) -> PR,
|
F: FnMut(PR) -> PR,
|
||||||
{
|
{
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
|
||||||
|
|
||||||
let reg = pa.read_phy(self.addr, PR::addr()).into();
|
let reg = pa.read_phy(self.addr, PR::addr()).into();
|
||||||
let reg = f(reg);
|
let reg = f(reg);
|
||||||
pa.write_phy(self.addr, PR::addr(), reg.into())
|
pa.write_phy(self.addr, PR::addr(), reg.into())
|
||||||
@ -100,6 +162,14 @@ impl Phy {
|
|||||||
self.modify_reg(pa, f)
|
self.modify_reg(pa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn modify_leds<PA, F>(&self, pa: &mut PA, f: F)
|
||||||
|
where
|
||||||
|
PA: PhyAccess,
|
||||||
|
F: FnMut(Leds) -> Leds,
|
||||||
|
{
|
||||||
|
self.modify_reg(pa, f)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
|
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
|
||||||
self.read_reg(pa)
|
self.read_reg(pa)
|
||||||
}
|
}
|
||||||
@ -133,8 +203,12 @@ impl Phy {
|
|||||||
.set_restart_autoneg(true)
|
.set_restart_autoneg(true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PhyRegister {
|
#[cfg(feature="target_kasli_soc")]
|
||||||
fn addr() -> u8;
|
pub fn set_leds<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||||
|
self.modify_leds(pa, |leds|
|
||||||
|
leds.set_led0(Led0Control::OnCopperLinkOffElse)
|
||||||
|
.set_led1(Led1Control::BlinkActivityOffNoActivity)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,10 @@ impl PhyRegister for PSSR {
|
|||||||
fn addr() -> u8 {
|
fn addr() -> u8 {
|
||||||
0x11
|
0x11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn page() -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for PSSR {
|
impl From<u16> for PSSR {
|
||||||
|
@ -55,12 +55,22 @@ impl Status {
|
|||||||
pub fn get_link(&self) -> Option<Link> {
|
pub fn get_link(&self) -> Option<Link> {
|
||||||
if ! self.link_status() {
|
if ! self.link_status() {
|
||||||
None
|
None
|
||||||
} else if self.cap_10base_t_half() {
|
} else if self.cap_100base_tx_full() {
|
||||||
Some(Link {
|
Some(Link {
|
||||||
speed: LinkSpeed::S10,
|
speed: LinkSpeed::S100,
|
||||||
|
duplex: LinkDuplex::Full,
|
||||||
|
})
|
||||||
|
} else if self.cap_100base_tx_half() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S100,
|
||||||
duplex: LinkDuplex::Half,
|
duplex: LinkDuplex::Half,
|
||||||
})
|
})
|
||||||
} else if self.cap_10base_t_full() {
|
} else if self.cap_100base_t4() {
|
||||||
|
Some(Link {
|
||||||
|
speed: LinkSpeed::S100,
|
||||||
|
duplex: LinkDuplex::Half,
|
||||||
|
})
|
||||||
|
} else if self.cap_10base_t2_full() {
|
||||||
Some(Link {
|
Some(Link {
|
||||||
speed: LinkSpeed::S10,
|
speed: LinkSpeed::S10,
|
||||||
duplex: LinkDuplex::Full,
|
duplex: LinkDuplex::Full,
|
||||||
@ -70,26 +80,16 @@ impl Status {
|
|||||||
speed: LinkSpeed::S10,
|
speed: LinkSpeed::S10,
|
||||||
duplex: LinkDuplex::Half,
|
duplex: LinkDuplex::Half,
|
||||||
})
|
})
|
||||||
} else if self.cap_10base_t2_full() {
|
} else if self.cap_10base_t_full() {
|
||||||
Some(Link {
|
Some(Link {
|
||||||
speed: LinkSpeed::S10,
|
speed: LinkSpeed::S10,
|
||||||
duplex: LinkDuplex::Full,
|
duplex: LinkDuplex::Full,
|
||||||
})
|
})
|
||||||
} else if self.cap_100base_t4() {
|
} else if self.cap_10base_t_half() {
|
||||||
Some(Link {
|
Some(Link {
|
||||||
speed: LinkSpeed::S100,
|
speed: LinkSpeed::S10,
|
||||||
duplex: LinkDuplex::Half,
|
duplex: LinkDuplex::Half,
|
||||||
})
|
})
|
||||||
} else if self.cap_100base_tx_half() {
|
|
||||||
Some(Link {
|
|
||||||
speed: LinkSpeed::S100,
|
|
||||||
duplex: LinkDuplex::Half,
|
|
||||||
})
|
|
||||||
} else if self.cap_100base_tx_full() {
|
|
||||||
Some(Link {
|
|
||||||
speed: LinkSpeed::S100,
|
|
||||||
duplex: LinkDuplex::Full,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -100,6 +100,10 @@ impl PhyRegister for Status {
|
|||||||
fn addr() -> u8 {
|
fn addr() -> u8 {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn page() -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for Status {
|
impl From<u16> for Status {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use volatile_register::{RO, WO, RW};
|
use volatile_register::{RO, WO, RW};
|
||||||
|
|
||||||
use libregister::{register, register_bit, register_bits, register_bits_typed};
|
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
@ -110,18 +110,51 @@ pub struct RegisterBlock {
|
|||||||
pub design_cfg5: RO<u32>,
|
pub design_cfg5: RO<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterBlock {
|
pub struct GpioRegisterBlock {
|
||||||
const GEM0: *mut Self = 0xE000B000 as *mut _;
|
pub gpio_output_mask: &'static mut OutputMask,
|
||||||
const GEM1: *mut Self = 0xE000C000 as *mut _;
|
pub gpio_direction: &'static mut Direction,
|
||||||
|
pub gpio_output_enable: &'static mut OutputEnable,
|
||||||
pub fn gem0() -> &'static mut Self {
|
|
||||||
unsafe { &mut *Self::GEM0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gem1() -> &'static mut Self {
|
impl GpioRegisterBlock {
|
||||||
unsafe { &mut *Self::GEM1 }
|
pub fn regs() -> Self {
|
||||||
|
Self {
|
||||||
|
gpio_output_mask: OutputMask::new(),
|
||||||
|
gpio_direction: Direction::new(),
|
||||||
|
gpio_output_enable: OutputEnable::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register!(gpio_output_mask,
|
||||||
|
/// MASK_DATA_1_SW:
|
||||||
|
/// Maskable output data for MIO[47:32]
|
||||||
|
OutputMask, RW, u32);
|
||||||
|
register_at!(OutputMask, 0xE000A008, new);
|
||||||
|
register_bit!(gpio_output_mask,
|
||||||
|
/// Output for PHY_RST (MIO[47])
|
||||||
|
phy_rst, 15);
|
||||||
|
register_bits!(gpio_output_mask,
|
||||||
|
mask, u16, 16, 31);
|
||||||
|
register!(gpio_direction,
|
||||||
|
/// DIRM_1:
|
||||||
|
/// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||||
|
Direction, RW, u32);
|
||||||
|
register_at!(Direction, 0xE000A244, new);
|
||||||
|
register_bit!(gpio_direction,
|
||||||
|
/// Direction for PHY_RST
|
||||||
|
phy_rst, 15);
|
||||||
|
register!(gpio_output_enable,
|
||||||
|
/// OEN_1:
|
||||||
|
/// Output enable for MIO[53:32]
|
||||||
|
OutputEnable, RW, u32);
|
||||||
|
register_at!(OutputEnable, 0xE000A248, new);
|
||||||
|
register_bit!(gpio_output_enable,
|
||||||
|
/// Output enable for PHY_RST
|
||||||
|
phy_rst, 15);
|
||||||
|
|
||||||
|
register_at!(RegisterBlock, 0xE000B000, gem0);
|
||||||
|
register_at!(RegisterBlock, 0xE000C000, gem1);
|
||||||
|
|
||||||
register!(net_ctrl, NetCtrl, RW, u32);
|
register!(net_ctrl, NetCtrl, RW, u32);
|
||||||
register_bit!(net_ctrl, loopback_local, 1);
|
register_bit!(net_ctrl, loopback_local, 1);
|
||||||
|
@ -108,6 +108,20 @@ impl DescList {
|
|||||||
if entry.word0.read().used() {
|
if entry.word0.read().used() {
|
||||||
let word1 = entry.word1.read();
|
let word1 = entry.word1.read();
|
||||||
let len = word1.frame_length_lsbs().into();
|
let len = word1.frame_length_lsbs().into();
|
||||||
|
let padding = {
|
||||||
|
let diff = len % 0x20;
|
||||||
|
if diff == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
0x20 - diff
|
||||||
|
}
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
// invalidate the buffer
|
||||||
|
// we cannot do it in the drop function, as L2 cache data prefetch would prefetch
|
||||||
|
// the data, and there is no way for us to prevent that unless changing MMU table.
|
||||||
|
dci_slice(&mut self.buffers[self.next][0..len + padding]);
|
||||||
|
}
|
||||||
let buffer = &mut self.buffers[self.next][0..len];
|
let buffer = &mut self.buffers[self.next][0..len];
|
||||||
|
|
||||||
self.next += 1;
|
self.next += 1;
|
||||||
@ -135,10 +149,6 @@ pub struct PktRef<'a> {
|
|||||||
|
|
||||||
impl<'a> Drop for PktRef<'a> {
|
impl<'a> Drop for PktRef<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Flush buffer from cache, to be filled by the peripheral
|
|
||||||
// before next read
|
|
||||||
dcci_slice(self.buffer);
|
|
||||||
|
|
||||||
self.entry.word0.modify(|_, w| w.used(false));
|
self.entry.word0.modify(|_, w| w.used(false));
|
||||||
dmb();
|
dmb();
|
||||||
}
|
}
|
||||||
|
@ -132,12 +132,10 @@ impl<'a> Drop for PktRef<'a> {
|
|||||||
dcc_slice(self.buffer);
|
dcc_slice(self.buffer);
|
||||||
|
|
||||||
self.entry.word1.modify(|_, w| w.used(false));
|
self.entry.word1.modify(|_, w| w.used(false));
|
||||||
if ! self.regs.tx_status.read().tx_go() {
|
// Start the TX engine
|
||||||
// Start TX if not already running
|
|
||||||
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Deref for PktRef<'a> {
|
impl<'a> Deref for PktRef<'a> {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
@ -166,10 +164,7 @@ impl<'a> smoltcp::phy::TxToken for Token<'a> {
|
|||||||
None =>
|
None =>
|
||||||
Err(smoltcp::Error::Exhausted),
|
Err(smoltcp::Error::Exhausted),
|
||||||
Some(mut pktref) => {
|
Some(mut pktref) => {
|
||||||
let result = f(pktref.deref_mut());
|
f(pktref.deref_mut())
|
||||||
// TODO: on result.is_err() don;t send
|
|
||||||
drop(pktref);
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
pub trait BytesTransferExt: Sized {
|
|
||||||
// Turn u32 into u8
|
|
||||||
fn bytes_transfer(self) -> BytesTransfer<Self>
|
|
||||||
where
|
|
||||||
Self: Iterator<Item = u32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator<Item = u32>> BytesTransferExt for I {
|
|
||||||
// Turn u32 into u8
|
|
||||||
fn bytes_transfer(self) -> BytesTransfer<Self> {
|
|
||||||
BytesTransfer {
|
|
||||||
iter: self,
|
|
||||||
shift: 0,
|
|
||||||
word: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BytesTransfer<I: Iterator<Item = u32> + Sized> {
|
|
||||||
iter: I,
|
|
||||||
shift: u8,
|
|
||||||
word: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator<Item = u32> + Sized> Iterator for BytesTransfer<I> {
|
|
||||||
type Item = u8;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<u8> {
|
|
||||||
if self.shift > 0 {
|
|
||||||
self.shift -= 8;
|
|
||||||
Some((self.word >> self.shift) as u8)
|
|
||||||
} else {
|
|
||||||
self.iter.next()
|
|
||||||
.and_then(|word| {
|
|
||||||
self.shift = 32;
|
|
||||||
self.word = word;
|
|
||||||
self.next()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,503 +0,0 @@
|
|||||||
//! Quad-SPI Flash Controller
|
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use log::{error, info, warn};
|
|
||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
|
||||||
use crate::{print, println};
|
|
||||||
use super::slcr;
|
|
||||||
use super::clocks::source::{IoPll, ClockSource};
|
|
||||||
|
|
||||||
mod regs;
|
|
||||||
mod bytes;
|
|
||||||
pub use bytes::{BytesTransferExt, BytesTransfer};
|
|
||||||
mod spi_flash_register;
|
|
||||||
use spi_flash_register::*;
|
|
||||||
mod transfer;
|
|
||||||
use transfer::Transfer;
|
|
||||||
|
|
||||||
const FLASH_BAUD_RATE: u32 = 50_000_000;
|
|
||||||
/// 16 MB
|
|
||||||
pub const SINGLE_CAPACITY: u32 = 0x1000000;
|
|
||||||
pub const SECTOR_SIZE: u32 = 0x10000;
|
|
||||||
pub const PAGE_SIZE: u32 = 0x100;
|
|
||||||
|
|
||||||
/// Instruction: Read Identification
|
|
||||||
const INST_RDID: u8 = 0x9F;
|
|
||||||
/// Instruction: Read
|
|
||||||
const INST_READ: u8 = 0x03;
|
|
||||||
/// Instruction: Quad I/O Fast Read
|
|
||||||
const INST_4IO_FAST_READ: u8 = 0xEB;
|
|
||||||
/// Instruction: Write Disable
|
|
||||||
const INST_WRDI: u8 = 0x04;
|
|
||||||
/// Instruction: Write Enable
|
|
||||||
const INST_WREN: u8 = 0x06;
|
|
||||||
/// Instruction: Program page
|
|
||||||
const INST_PP: u8 = 0x02;
|
|
||||||
/// Instruction: Erase 4K Block
|
|
||||||
const INST_BE_4K: u8 = 0x20;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum SpiWord {
|
|
||||||
W8(u8),
|
|
||||||
W16(u16),
|
|
||||||
W24(u32),
|
|
||||||
W32(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for SpiWord {
|
|
||||||
fn from(x: u8) -> Self {
|
|
||||||
SpiWord::W8(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u16> for SpiWord {
|
|
||||||
fn from(x: u16) -> Self {
|
|
||||||
SpiWord::W16(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for SpiWord {
|
|
||||||
fn from(x: u32) -> Self {
|
|
||||||
SpiWord::W32(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Memory-mapped mode
|
|
||||||
pub struct LinearAddressing;
|
|
||||||
/// Manual I/O mode
|
|
||||||
pub struct Manual;
|
|
||||||
|
|
||||||
/// Flash Interface Driver
|
|
||||||
///
|
|
||||||
/// For 2x Spansion S25FL128SAGMFIR01
|
|
||||||
pub struct Flash<MODE> {
|
|
||||||
regs: &'static mut regs::RegisterBlock,
|
|
||||||
_mode: PhantomData<MODE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<MODE> Flash<MODE> {
|
|
||||||
fn transition<TO>(self) -> Flash<TO> {
|
|
||||||
Flash {
|
|
||||||
regs: self.regs,
|
|
||||||
_mode: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disable_interrupts(&mut self) {
|
|
||||||
self.regs.intr_dis.write(
|
|
||||||
regs::IntrDis::zeroed()
|
|
||||||
.rx_overflow(true)
|
|
||||||
.tx_fifo_not_full(true)
|
|
||||||
.tx_fifo_full(true)
|
|
||||||
.rx_fifo_not_empty(true)
|
|
||||||
.rx_fifo_full(true)
|
|
||||||
.tx_fifo_underflow(true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_rx_fifo(&self) {
|
|
||||||
while self.regs.intr_status.read().rx_fifo_not_empty() {
|
|
||||||
let _ = self.regs.rx_data.read();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_interrupt_status(&mut self) {
|
|
||||||
self.regs.intr_status.write(
|
|
||||||
regs::IntrStatus::zeroed()
|
|
||||||
.rx_overflow(true)
|
|
||||||
.tx_fifo_underflow(true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_tx_fifo_flush(&mut self) {
|
|
||||||
self.regs.config.modify(|_, w| w.man_start_com(true));
|
|
||||||
while !self.regs.intr_status.read().tx_fifo_not_full() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Flash<()> {
|
|
||||||
pub fn new(clock: u32) -> Self {
|
|
||||||
Self::enable_clocks(clock);
|
|
||||||
Self::setup_signals();
|
|
||||||
Self::reset();
|
|
||||||
|
|
||||||
let regs = regs::RegisterBlock::qspi();
|
|
||||||
let mut flash = Flash { regs, _mode: PhantomData };
|
|
||||||
flash.configure((FLASH_BAUD_RATE - 1 + clock) / FLASH_BAUD_RATE);
|
|
||||||
flash
|
|
||||||
}
|
|
||||||
|
|
||||||
/// typical: `200_000_000` Hz
|
|
||||||
fn enable_clocks(clock: u32) {
|
|
||||||
let io_pll = IoPll::freq();
|
|
||||||
let divisor = ((clock - 1 + io_pll) / clock)
|
|
||||||
.max(1).min(63) as u8;
|
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.lqspi_clk_ctrl.write(
|
|
||||||
slcr::LqspiClkCtrl::zeroed()
|
|
||||||
.src_sel(slcr::PllSource::IoPll)
|
|
||||||
.divisor(divisor)
|
|
||||||
.clkact(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_signals() {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
// 1. Configure MIO pin 1 for chip select 0 output.
|
|
||||||
slcr.mio_pin_01.write(
|
|
||||||
slcr::MioPin01::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Configure MIO pins 2 through 5 for I/O.
|
|
||||||
slcr.mio_pin_02.write(
|
|
||||||
slcr::MioPin02::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_03.write(
|
|
||||||
slcr::MioPin03::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_04.write(
|
|
||||||
slcr::MioPin04::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_05.write(
|
|
||||||
slcr::MioPin05::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. Configure MIO pin 6 for serial clock 0 output.
|
|
||||||
slcr.mio_pin_06.write(
|
|
||||||
slcr::MioPin06::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Option: Add Second Device Chip Select
|
|
||||||
// 4. Configure MIO pin 0 for chip select 1 output.
|
|
||||||
slcr.mio_pin_00.write(
|
|
||||||
slcr::MioPin00::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Option: Add Second Serial Clock
|
|
||||||
// 5. Configure MIO pin 9 for serial clock 1 output.
|
|
||||||
slcr.mio_pin_09.write(
|
|
||||||
slcr::MioPin09::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Option: Add 4-bit Data
|
|
||||||
// 6. Configure MIO pins 10 through 13 for I/O.
|
|
||||||
slcr.mio_pin_10.write(
|
|
||||||
slcr::MioPin10::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_11.write(
|
|
||||||
slcr::MioPin11::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_12.write(
|
|
||||||
slcr::MioPin12::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
slcr.mio_pin_13.write(
|
|
||||||
slcr::MioPin13::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Option: Add Feedback Output Clock
|
|
||||||
// 7. Configure MIO pin 8 for feedback clock.
|
|
||||||
slcr.mio_pin_08.write(
|
|
||||||
slcr::MioPin08::zeroed()
|
|
||||||
.l0_sel(true)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset() {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.lqspi_rst_ctrl.write(
|
|
||||||
slcr::LqspiRstCtrl::zeroed()
|
|
||||||
.ref_rst(true)
|
|
||||||
.cpu1x_rst(true)
|
|
||||||
);
|
|
||||||
slcr.lqspi_rst_ctrl.write(
|
|
||||||
slcr::LqspiRstCtrl::zeroed()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure(&mut self, divider: u32) {
|
|
||||||
// Disable
|
|
||||||
self.regs.enable.write(
|
|
||||||
regs::Enable::zeroed()
|
|
||||||
);
|
|
||||||
self.disable_interrupts();
|
|
||||||
self.regs.lqspi_cfg.write(
|
|
||||||
regs::LqspiCfg::zeroed()
|
|
||||||
);
|
|
||||||
self.clear_rx_fifo();
|
|
||||||
self.clear_interrupt_status();
|
|
||||||
|
|
||||||
// for a baud_rate_div=1 LPBK_DLY_ADJ would be required
|
|
||||||
let mut baud_rate_div = 2u32;
|
|
||||||
while baud_rate_div < 7 && 2u32.pow(1 + baud_rate_div) < divider {
|
|
||||||
baud_rate_div += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.regs.config.write(regs::Config::zeroed()
|
|
||||||
.baud_rate_div(baud_rate_div as u8)
|
|
||||||
.mode_sel(true)
|
|
||||||
.leg_flsh(true)
|
|
||||||
.holdb_dr(true)
|
|
||||||
// 32 bits TX FIFO width
|
|
||||||
.fifo_width(0b11)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize RX/TX pipes thresholds
|
|
||||||
unsafe {
|
|
||||||
self.regs.rx_thres.write(1);
|
|
||||||
self.regs.tx_thres.write(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn linear_addressing_mode(self) -> Flash<LinearAddressing> {
|
|
||||||
// Set manual start enable to auto mode.
|
|
||||||
// Assert the chip select.
|
|
||||||
self.regs.config.modify(|_, w| w
|
|
||||||
.man_start_en(false)
|
|
||||||
.pcs(false)
|
|
||||||
.manual_cs(false)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
|
||||||
// Quad I/O Fast Read
|
|
||||||
.inst_code(INST_4IO_FAST_READ)
|
|
||||||
.dummy_mask(0x2)
|
|
||||||
.mode_en(false)
|
|
||||||
.mode_bits(0xFF)
|
|
||||||
// 2 devices
|
|
||||||
.two_mem(true)
|
|
||||||
.u_page(false)
|
|
||||||
// Quad SPI mode
|
|
||||||
.lq_mode(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.enable.write(
|
|
||||||
regs::Enable::zeroed()
|
|
||||||
.spi_en(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.transition()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn manual_mode(self, chip_index: usize) -> Flash<Manual> {
|
|
||||||
self.regs.config.modify(|_, w| w
|
|
||||||
.man_start_en(true)
|
|
||||||
.manual_cs(true)
|
|
||||||
.endian(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
|
||||||
// Quad I/O Fast Read
|
|
||||||
.inst_code(INST_READ)
|
|
||||||
.dummy_mask(0x2)
|
|
||||||
.mode_en(false)
|
|
||||||
.mode_bits(0xFF)
|
|
||||||
// 2 devices
|
|
||||||
.two_mem(true)
|
|
||||||
.u_page(chip_index != 0)
|
|
||||||
// Quad SPI mode
|
|
||||||
.lq_mode(false)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.transition()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Flash<LinearAddressing> {
|
|
||||||
/// Stop linear addressing mode
|
|
||||||
pub fn stop(self) -> Flash<()> {
|
|
||||||
self.regs.enable.modify(|_, w| w.spi_en(false));
|
|
||||||
// De-assert chip select.
|
|
||||||
self.regs.config.modify(|_, w| w.pcs(true));
|
|
||||||
|
|
||||||
self.transition()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ptr<T>(&mut self) -> *mut T {
|
|
||||||
0xFC00_0000 as *mut _
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&self) -> usize {
|
|
||||||
2 * (SINGLE_CAPACITY as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Flash<Manual> {
|
|
||||||
pub fn stop(self) -> Flash<()> {
|
|
||||||
self.transition()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_reg<R: SpiFlashRegister>(&mut self) -> R {
|
|
||||||
let args = Some(R::inst_code());
|
|
||||||
let transfer = self.transfer(args.into_iter(), 2)
|
|
||||||
.bytes_transfer();
|
|
||||||
R::new(transfer.skip(1).next().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_reg_until<R, F, A>(&mut self, f: F) -> A
|
|
||||||
where
|
|
||||||
R: SpiFlashRegister,
|
|
||||||
F: Fn(R) -> Option<A>,
|
|
||||||
{
|
|
||||||
let mut result = None;
|
|
||||||
while result.is_none() {
|
|
||||||
let args = Some(R::inst_code());
|
|
||||||
for b in self.transfer(args.into_iter(), 32)
|
|
||||||
.bytes_transfer().skip(1) {
|
|
||||||
result = f(R::new(b));
|
|
||||||
|
|
||||||
if result.is_none() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Status Register-1 remains `0x00` immediately after invoking a command.
|
|
||||||
fn wait_while_sr1_zeroed(&mut self) -> SR1 {
|
|
||||||
self.read_reg_until::<SR1, _, SR1>(|sr1|
|
|
||||||
if sr1.is_zeroed() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(sr1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read Identification
|
|
||||||
pub fn rdid(&mut self) -> core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>> {
|
|
||||||
let args = Some((INST_RDID as u32) << 24);
|
|
||||||
self.transfer(args.into_iter(), 0x44)
|
|
||||||
.bytes_transfer().skip(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read flash data
|
|
||||||
pub fn read(&mut self, offset: u32, len: usize
|
|
||||||
) -> core::iter::Take<core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>>>
|
|
||||||
{
|
|
||||||
let args = Some(((INST_READ as u32) << 24) | (offset as u32));
|
|
||||||
self.transfer(args.into_iter(), len + 6)
|
|
||||||
.bytes_transfer().skip(6).take(len)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erase(&mut self, offset: u32) {
|
|
||||||
let args = Some(((INST_BE_4K as u32) << 24) | (offset as u32));
|
|
||||||
self.transfer(args.into_iter(), 4);
|
|
||||||
|
|
||||||
let sr1 = self.wait_while_sr1_zeroed();
|
|
||||||
|
|
||||||
if sr1.e_err() {
|
|
||||||
error!("E_ERR");
|
|
||||||
} else if sr1.p_err() {
|
|
||||||
error!("P_ERR");
|
|
||||||
} else if sr1.wip() {
|
|
||||||
info!("Erase in progress");
|
|
||||||
while self.read_reg::<SR1>().wip() {
|
|
||||||
print!(".");
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
} else {
|
|
||||||
warn!("erased? sr1={:02X}", sr1.inner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn program<I: Iterator<Item=u32>>(&mut self, offset: u32, data: I) {
|
|
||||||
{
|
|
||||||
let len = 4 + 4 * data.size_hint().0;
|
|
||||||
let args = Some(SpiWord::W32(((INST_PP as u32) << 24) | (offset as u32))).into_iter()
|
|
||||||
.chain(data.map(SpiWord::W32));
|
|
||||||
self.transfer(args, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let sr1 = self.wait_while_sr1_zeroed();
|
|
||||||
let sr1 = self.read_reg::<SR1>();
|
|
||||||
|
|
||||||
if sr1.e_err() {
|
|
||||||
error!("E_ERR");
|
|
||||||
} else if sr1.p_err() {
|
|
||||||
error!("P_ERR");
|
|
||||||
} else if sr1.wip() {
|
|
||||||
info!("Program in progress");
|
|
||||||
while self.read_reg::<SR1>().wip() {
|
|
||||||
print!(".");
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
} else {
|
|
||||||
warn!("programmed? sr1={:02X}", sr1.inner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_enabled<F: Fn(&mut Self) -> R, R>(&mut self, f: F) -> R {
|
|
||||||
// Write Enable
|
|
||||||
let args = Some(INST_WREN);
|
|
||||||
self.transfer(args.into_iter(), 1);
|
|
||||||
self.regs.gpio.modify(|_, w| w.wp_n(true));
|
|
||||||
let sr1 = self.wait_while_sr1_zeroed();
|
|
||||||
if !sr1.wel() {
|
|
||||||
panic!("Cannot write-enable flash");
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = f(self);
|
|
||||||
|
|
||||||
// Write Disable
|
|
||||||
let args = Some(INST_WRDI);
|
|
||||||
self.transfer(args.into_iter(), 1);
|
|
||||||
self.regs.gpio.modify(|_, w| w.wp_n(false));
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transfer<'s: 't, 't, Args, W>(&'s mut self, args: Args, len: usize) -> Transfer<'t, Args, W>
|
|
||||||
where
|
|
||||||
Args: Iterator<Item = W>,
|
|
||||||
W: Into<SpiWord>,
|
|
||||||
{
|
|
||||||
Transfer::new(self, args, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dump(&mut self, label: &'_ str, inst_code: u8) {
|
|
||||||
print!("{}:", label);
|
|
||||||
|
|
||||||
let args = Some(u32::from(inst_code) << 24);
|
|
||||||
for b in self.transfer(args.into_iter(), 32).bytes_transfer() {
|
|
||||||
print!(" {:02X}", b);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
use volatile_register::{RO, WO, RW};
|
|
||||||
|
|
||||||
use libregister::{register, register_bit, register_bits};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct RegisterBlock {
|
|
||||||
pub config: Config,
|
|
||||||
pub intr_status: IntrStatus,
|
|
||||||
pub intr_en: IntrEn,
|
|
||||||
pub intr_dis: IntrDis,
|
|
||||||
pub intr_mask: RO<u32>,
|
|
||||||
pub enable: Enable,
|
|
||||||
pub delay: RW<u32>,
|
|
||||||
pub txd0: WO<u32>,
|
|
||||||
pub rx_data: RO<u32>,
|
|
||||||
pub slave_idle_count: RW<u32>,
|
|
||||||
pub tx_thres: RW<u32>,
|
|
||||||
pub rx_thres: RW<u32>,
|
|
||||||
pub gpio: QspiGpio,
|
|
||||||
pub _unused1: RO<u32>,
|
|
||||||
pub lpbk_dly_adj: RW<u32>,
|
|
||||||
pub _unused2: [RO<u32>; 17],
|
|
||||||
pub txd1: WO<u32>,
|
|
||||||
pub txd2: WO<u32>,
|
|
||||||
pub txd3: WO<u32>,
|
|
||||||
pub _unused3: [RO<u32>; 5],
|
|
||||||
pub lqspi_cfg: LqspiCfg,
|
|
||||||
pub lqspi_sts: RW<u32>,
|
|
||||||
pub _unused4: [RO<u32>; 21],
|
|
||||||
pub mod_id: RW<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegisterBlock {
|
|
||||||
const BASE_ADDRESS: *mut Self = 0xE000D000 as *mut _;
|
|
||||||
|
|
||||||
pub fn qspi() -> &'static mut Self {
|
|
||||||
unsafe { &mut *Self::BASE_ADDRESS }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register!(config, Config, RW, u32);
|
|
||||||
register_bit!(config,
|
|
||||||
/// Enables master mode
|
|
||||||
mode_sel, 0);
|
|
||||||
register_bit!(config,
|
|
||||||
/// Clock polarity low/high
|
|
||||||
clk_pol, 1);
|
|
||||||
register_bit!(config,
|
|
||||||
/// Clock phase
|
|
||||||
clk_ph, 2);
|
|
||||||
register_bits!(config,
|
|
||||||
/// divider = 2 ** (1 + baud_rate_div)
|
|
||||||
baud_rate_div, u8, 3, 5);
|
|
||||||
register_bits!(config,
|
|
||||||
/// Must be set to 0b11
|
|
||||||
fifo_width, u8, 6, 7);
|
|
||||||
register_bit!(config,
|
|
||||||
/// Must be 0
|
|
||||||
ref_clk, 8);
|
|
||||||
register_bit!(config,
|
|
||||||
/// Peripheral Chip Select Line
|
|
||||||
pcs, 10);
|
|
||||||
register_bit!(config,
|
|
||||||
/// false: auto mode, true: manual CS mode
|
|
||||||
manual_cs, 14);
|
|
||||||
register_bit!(config,
|
|
||||||
/// false: auto mode, true: enables manual start enable
|
|
||||||
man_start_en, 15);
|
|
||||||
register_bit!(config,
|
|
||||||
/// false: auto mode, true: enables manual start command
|
|
||||||
man_start_com, 16);
|
|
||||||
register_bit!(config, holdb_dr, 19);
|
|
||||||
register_bit!(config,
|
|
||||||
/// false: little, true: endian
|
|
||||||
endian, 26);
|
|
||||||
register_bit!(config,
|
|
||||||
/// false: legacy SPI mode, true: Flash memory interface mode
|
|
||||||
leg_flsh, 31);
|
|
||||||
|
|
||||||
register!(intr_status, IntrStatus, RW, u32);
|
|
||||||
register_bit!(intr_status, rx_overflow, 0);
|
|
||||||
register_bit!(intr_status,
|
|
||||||
/// < tx_thres
|
|
||||||
tx_fifo_not_full, 2);
|
|
||||||
register_bit!(intr_status, tx_fifo_full, 3);
|
|
||||||
register_bit!(intr_status,
|
|
||||||
/// >= rx_thres
|
|
||||||
rx_fifo_not_empty, 4);
|
|
||||||
register_bit!(intr_status, rx_fifo_full, 5);
|
|
||||||
register_bit!(intr_status, tx_fifo_underflow, 6);
|
|
||||||
|
|
||||||
register!(intr_en, IntrEn, WO, u32);
|
|
||||||
register_bit!(intr_en, rx_overflow, 0);
|
|
||||||
register_bit!(intr_en, tx_fifo_not_full, 2);
|
|
||||||
register_bit!(intr_en, tx_fifo_full, 3);
|
|
||||||
register_bit!(intr_en, rx_fifo_not_empty, 4);
|
|
||||||
register_bit!(intr_en, rx_fifo_full, 5);
|
|
||||||
register_bit!(intr_en, tx_fifo_underflow, 6);
|
|
||||||
|
|
||||||
register!(intr_dis, IntrDis, WO, u32);
|
|
||||||
register_bit!(intr_dis, rx_overflow, 0);
|
|
||||||
register_bit!(intr_dis, tx_fifo_not_full, 2);
|
|
||||||
register_bit!(intr_dis, tx_fifo_full, 3);
|
|
||||||
register_bit!(intr_dis, rx_fifo_not_empty, 4);
|
|
||||||
register_bit!(intr_dis, rx_fifo_full, 5);
|
|
||||||
register_bit!(intr_dis, tx_fifo_underflow, 6);
|
|
||||||
|
|
||||||
register!(enable, Enable, RW, u32);
|
|
||||||
register_bit!(enable, spi_en, 0);
|
|
||||||
|
|
||||||
// named to avoid confusion with normal gpio
|
|
||||||
register!(qspi_gpio, QspiGpio, RW, u32);
|
|
||||||
register_bit!(qspi_gpio,
|
|
||||||
/// Write protect pin (inverted)
|
|
||||||
wp_n, 0);
|
|
||||||
|
|
||||||
register!(lqspi_cfg, LqspiCfg, RW, u32);
|
|
||||||
register_bits!(lqspi_cfg, inst_code, u8, 0, 7);
|
|
||||||
register_bits!(lqspi_cfg, dummy_mask, u8, 8, 10);
|
|
||||||
register_bits!(lqspi_cfg, mode_bits, u8, 16, 23);
|
|
||||||
register_bit!(lqspi_cfg, mode_on, 24);
|
|
||||||
register_bit!(lqspi_cfg, mode_en, 25);
|
|
||||||
register_bit!(lqspi_cfg, u_page, 28);
|
|
||||||
register_bit!(lqspi_cfg, sep_bus, 29);
|
|
||||||
register_bit!(lqspi_cfg, two_mem, 30);
|
|
||||||
register_bit!(lqspi_cfg, lq_mode, 31);
|
|
@ -1,62 +0,0 @@
|
|||||||
use bit_field::BitField;
|
|
||||||
|
|
||||||
pub trait SpiFlashRegister {
|
|
||||||
fn inst_code() -> u8;
|
|
||||||
fn new(src: u8) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! u8_register {
|
|
||||||
($name: ident, $doc: tt, $inst_code: expr) => {
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[doc=$doc]
|
|
||||||
pub struct $name {
|
|
||||||
pub inner: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SpiFlashRegister for $name {
|
|
||||||
fn inst_code() -> u8 {
|
|
||||||
$inst_code
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(src: u8) -> Self {
|
|
||||||
$name {
|
|
||||||
inner: src,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn is_zeroed(&self) -> bool {
|
|
||||||
self.inner == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
u8_register!(CR, "Configuration Register", 0x35);
|
|
||||||
u8_register!(SR1, "Status Register-1", 0x05);
|
|
||||||
impl SR1 {
|
|
||||||
/// Write In Progress
|
|
||||||
pub fn wip(&self) -> bool {
|
|
||||||
self.inner.get_bit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write Enable Latch
|
|
||||||
pub fn wel(&self) -> bool {
|
|
||||||
self.inner.get_bit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Erase Error Occurred
|
|
||||||
pub fn e_err(&self) -> bool {
|
|
||||||
self.inner.get_bit(5)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Programming Error Occurred
|
|
||||||
pub fn p_err(&self) -> bool {
|
|
||||||
self.inner.get_bit(6)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u8_register!(SR2, "Status Register-2", 0x07);
|
|
||||||
u8_register!(BA, "Bank Address Register", 0xB9);
|
|
@ -1,125 +0,0 @@
|
|||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
|
||||||
use super::regs;
|
|
||||||
use super::{SpiWord, Flash, Manual};
|
|
||||||
|
|
||||||
pub struct Transfer<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> {
|
|
||||||
flash: &'a mut Flash<Manual>,
|
|
||||||
args: Args,
|
|
||||||
sent: usize,
|
|
||||||
received: usize,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Transfer<'a, Args, W> {
|
|
||||||
pub fn new(flash: &'a mut Flash<Manual>, args: Args, len: usize) -> Self {
|
|
||||||
flash.regs.config.modify(|_, w| w.pcs(false));
|
|
||||||
flash.regs.enable.write(
|
|
||||||
regs::Enable::zeroed()
|
|
||||||
.spi_en(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut xfer = Transfer {
|
|
||||||
flash,
|
|
||||||
args,
|
|
||||||
sent: 0,
|
|
||||||
received: 0,
|
|
||||||
len,
|
|
||||||
};
|
|
||||||
xfer.fill_tx_fifo();
|
|
||||||
xfer.flash.regs.config.modify(|_, w| w.man_start_com(true));
|
|
||||||
xfer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_tx_fifo(&mut self) {
|
|
||||||
while self.sent < self.len && !self.flash.regs.intr_status.read().tx_fifo_full() {
|
|
||||||
let arg = self.args.next()
|
|
||||||
.map(|n| n.into())
|
|
||||||
.unwrap_or(SpiWord::W32(0));
|
|
||||||
match arg {
|
|
||||||
SpiWord::W32(w) => {
|
|
||||||
// println!("txd0 {:08X}", w);
|
|
||||||
unsafe {
|
|
||||||
self.flash.regs.txd0.write(w);
|
|
||||||
}
|
|
||||||
self.sent += 4;
|
|
||||||
}
|
|
||||||
// Only txd0 can be used without flushing
|
|
||||||
_ => {
|
|
||||||
if !self.flash.regs.intr_status.read().tx_fifo_not_full() {
|
|
||||||
// Flush if necessary
|
|
||||||
self.flash.wait_tx_fifo_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
match arg {
|
|
||||||
SpiWord::W8(w) => {
|
|
||||||
// println!("txd1 {:02X}", w);
|
|
||||||
unsafe {
|
|
||||||
self.flash.regs.txd1.write(u32::from(w) << 24);
|
|
||||||
}
|
|
||||||
self.sent += 1;
|
|
||||||
}
|
|
||||||
SpiWord::W16(w) => {
|
|
||||||
unsafe {
|
|
||||||
self.flash.regs.txd2.write(u32::from(w) << 16);
|
|
||||||
}
|
|
||||||
self.sent += 2;
|
|
||||||
}
|
|
||||||
SpiWord::W24(w) => {
|
|
||||||
unsafe {
|
|
||||||
self.flash.regs.txd3.write(w << 8);
|
|
||||||
}
|
|
||||||
self.sent += 3;
|
|
||||||
}
|
|
||||||
SpiWord::W32(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.flash.wait_tx_fifo_flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_read(&mut self) -> bool {
|
|
||||||
self.flash.regs.intr_status.read().rx_fifo_not_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self) -> u32 {
|
|
||||||
let rx = self.flash.regs.rx_data.read();
|
|
||||||
self.received += 4;
|
|
||||||
rx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Drop for Transfer<'a, Args, W> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// Discard remaining rx_data
|
|
||||||
while self.can_read() {
|
|
||||||
self.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop
|
|
||||||
self.flash.regs.enable.write(
|
|
||||||
regs::Enable::zeroed()
|
|
||||||
.spi_en(false)
|
|
||||||
);
|
|
||||||
self.flash.regs.config.modify(|_, w| w
|
|
||||||
.pcs(true)
|
|
||||||
.man_start_com(false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Iterator for Transfer<'a, Args, W> {
|
|
||||||
type Item = u32;
|
|
||||||
|
|
||||||
fn next<'s>(&'s mut self) -> Option<u32> {
|
|
||||||
if self.received >= self.len {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fill_tx_fifo();
|
|
||||||
|
|
||||||
while !self.can_read() {}
|
|
||||||
Some(self.read())
|
|
||||||
}
|
|
||||||
}
|
|
@ -62,7 +62,7 @@ pub struct InterruptController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptController {
|
impl InterruptController {
|
||||||
pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
pub fn gic(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
||||||
InterruptController { mpcore }
|
InterruptController { mpcore }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ impl InterruptController {
|
|||||||
let m = (id.0 >> 2) as usize;
|
let m = (id.0 >> 2) as usize;
|
||||||
let n = (8 * (id.0 & 3)) as usize;
|
let n = (8 * (id.0 & 3)) as usize;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1));
|
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
// sensitivity
|
// sensitivity
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use super::I2C;
|
use super::I2c;
|
||||||
use crate::time::Milliseconds;
|
use crate::time::Milliseconds;
|
||||||
use embedded_hal::timer::CountDown;
|
use embedded_hal::timer::CountDown;
|
||||||
|
|
||||||
pub struct EEPROM<'a> {
|
pub struct EEPROM<'a> {
|
||||||
i2c: &'a mut I2C,
|
i2c: &'a mut I2c,
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
port: u8,
|
port: u8,
|
||||||
address: u8,
|
address: u8,
|
||||||
page_size: u8,
|
page_size: u8,
|
||||||
@ -12,7 +13,7 @@ pub struct EEPROM<'a> {
|
|||||||
|
|
||||||
impl<'a> EEPROM<'a> {
|
impl<'a> EEPROM<'a> {
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
pub fn new(i2c: &'a mut I2C, page_size: u8) -> Self {
|
pub fn new(i2c: &'a mut I2c, page_size: u8) -> Self {
|
||||||
EEPROM {
|
EEPROM {
|
||||||
i2c: i2c,
|
i2c: i2c,
|
||||||
port: 2,
|
port: 2,
|
||||||
@ -22,10 +23,32 @@ impl<'a> EEPROM<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
pub fn new(i2c: &'a mut I2c, page_size: u8) -> Self {
|
||||||
|
EEPROM {
|
||||||
|
i2c: i2c,
|
||||||
|
port: 3,
|
||||||
|
address: 0x57,
|
||||||
|
page_size: page_size,
|
||||||
|
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
fn select(&mut self) -> Result<(), &'static str> {
|
fn select(&mut self) -> Result<(), &'static str> {
|
||||||
let mask: u16 = 1 << self.port;
|
self.i2c.pca954x_select(0b1110100, Some(self.port))?;
|
||||||
self.i2c.pca9548_select(0b1110100, mask as u8)?;
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
fn select(&mut self) -> Result<(), &'static str> {
|
||||||
|
// tca9548 is compatible with pca9548
|
||||||
|
self.i2c.pca954x_select(0b1110001, Some(self.port))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
fn select(&mut self) -> Result<(), &'static str> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,23 +2,33 @@
|
|||||||
|
|
||||||
mod regs;
|
mod regs;
|
||||||
pub mod eeprom;
|
pub mod eeprom;
|
||||||
use super::clocks::Clocks;
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
use super::time::Microseconds;
|
use super::time::Microseconds;
|
||||||
use embedded_hal::timer::CountDown;
|
use embedded_hal::timer::CountDown;
|
||||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
use libregister::{RegisterR, RegisterRW};
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
|
use libregister::RegisterW;
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
use log::info;
|
||||||
|
|
||||||
const INVALID_BUS: &'static str = "Invalid I2C bus";
|
pub enum I2cMultiplexer {
|
||||||
|
PCA9548 = 0,
|
||||||
pub struct I2C {
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
regs: regs::RegisterWrapper,
|
PCA9547 = 1,
|
||||||
count_down: super::timer::global::CountDown<Microseconds>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl I2C {
|
pub struct I2c {
|
||||||
#[cfg(feature = "target_zc706")]
|
regs: regs::RegisterBlock,
|
||||||
pub fn i2c() -> Self {
|
count_down: super::timer::global::CountDown<Microseconds>,
|
||||||
|
pca_type: I2cMultiplexer
|
||||||
|
}
|
||||||
|
|
||||||
|
impl I2c {
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
|
pub fn i2c0() -> Self {
|
||||||
// Route I2C 0 SCL / SDA Signals to MIO Pins 50 / 51
|
// Route I2C 0 SCL / SDA Signals to MIO Pins 50 / 51
|
||||||
|
#[cfg(not(feature = "target_ebaz4205"))]
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// SCL
|
// SCL
|
||||||
slcr.mio_pin_50.write(
|
slcr.mio_pin_50.write(
|
||||||
@ -36,19 +46,28 @@ impl I2C {
|
|||||||
.pullup(true)
|
.pullup(true)
|
||||||
.disable_rcvr(true)
|
.disable_rcvr(true)
|
||||||
);
|
);
|
||||||
// Reset
|
// On Kasli-SoC prototype, leakage through the unconfigured I2C_SW_RESET
|
||||||
slcr.gpio_rst_ctrl.reset_gpio();
|
// MIO pin develops enough voltage on the T21 gate to assert the reset.
|
||||||
|
// Configure the pin to avoid this problem.
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
slcr.mio_pin_33.write(
|
||||||
|
slcr::MioPin33::zeroed()
|
||||||
|
.l3_sel(0b000)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(false)
|
||||||
|
.disable_rcvr(true)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self::ctor_common(0xFFFF - 0x000C)
|
Self::i2c_common(0xFFFF - 0x000C, 0xFFFF - 0x0002)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ctor_common(gpio_output_mask: u16) -> Self {
|
fn i2c_common(gpio_output_mask: u16, _gpio_output_mask_lower: u16) -> Self {
|
||||||
// Setup register block
|
// Setup register block
|
||||||
let clocks = Clocks::get();
|
|
||||||
let self_ = Self {
|
let self_ = Self {
|
||||||
regs: regs::RegisterWrapper::new(),
|
regs: regs::RegisterBlock::i2c(),
|
||||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown()
|
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||||
|
pca_type: I2cMultiplexer::PCA9548 //default for zc706
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup GPIO output mask
|
// Setup GPIO output mask
|
||||||
@ -60,6 +79,17 @@ impl I2C {
|
|||||||
w.scl(true).sda(true)
|
w.scl(true).sda(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Kasli-SoC only: I2C_SW_RESET configuration
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
{
|
||||||
|
self_.regs.gpio_output_mask_lower.modify(|_, w| {
|
||||||
|
w.mask(_gpio_output_mask_lower)
|
||||||
|
});
|
||||||
|
self_.regs.gpio_direction.modify(|_, w| {
|
||||||
|
w.i2cswr(true)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self_
|
self_
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +99,7 @@ impl I2C {
|
|||||||
nb::block!(self.count_down.wait()).unwrap();
|
nb::block!(self.count_down.wait()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn half_period(&mut self) { self.delay_us(100) }
|
fn unit_delay(&mut self) { self.delay_us(100) }
|
||||||
|
|
||||||
fn sda_i(&mut self) -> bool {
|
fn sda_i(&mut self) -> bool {
|
||||||
self.regs.gpio_input.read().sda()
|
self.regs.gpio_input.read().sda()
|
||||||
@ -103,6 +133,48 @@ impl I2C {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
fn i2cswr_oe(&mut self, oe: bool) {
|
||||||
|
self.regs.gpio_output_enable.modify(|_, w| {
|
||||||
|
w.i2cswr(oe)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
fn i2cswr_o(&mut self, o: bool) {
|
||||||
|
self.regs.gpio_output_mask_lower.modify(|_, w| {
|
||||||
|
w.i2cswr_o(o)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
fn pca_autodetect(&mut self) -> Result<I2cMultiplexer, &'static str> {
|
||||||
|
// start with resetting the PCA954X
|
||||||
|
// SDA must be clear (before start)
|
||||||
|
// reset time is 500ns, unit_delay (100us) to account for propagation
|
||||||
|
self.i2cswr_o(true);
|
||||||
|
self.unit_delay();
|
||||||
|
self.i2cswr_o(false);
|
||||||
|
self.unit_delay();
|
||||||
|
|
||||||
|
let pca954x_read_addr = (0x71 << 1) | 0x01;
|
||||||
|
|
||||||
|
self.start()?;
|
||||||
|
// read the config register
|
||||||
|
if !self.write(pca954x_read_addr)? {
|
||||||
|
return Err("PCA954X failed to ack read address");
|
||||||
|
}
|
||||||
|
let config = self.read(false)?;
|
||||||
|
|
||||||
|
let pca = match config {
|
||||||
|
0x00 => { info!("PCA9548 detected"); I2cMultiplexer::PCA9548 },
|
||||||
|
0x08 => { info!("PCA9547 detected"); I2cMultiplexer::PCA9547 },
|
||||||
|
_ => { return Err("Unknown response for PCA954X autodetect")},
|
||||||
|
};
|
||||||
|
self.stop()?;
|
||||||
|
Ok(pca)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(&mut self) -> Result<(), &'static str> {
|
pub fn init(&mut self) -> Result<(), &'static str> {
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.sda_oe(false);
|
self.sda_oe(false);
|
||||||
@ -110,15 +182,15 @@ impl I2C {
|
|||||||
self.sda_o(false);
|
self.sda_o(false);
|
||||||
|
|
||||||
// Check the I2C bus is ready
|
// Check the I2C bus is ready
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
if !self.sda_i() {
|
if !self.sda_i() {
|
||||||
// Try toggling SCL a few times
|
// Try toggling SCL a few times
|
||||||
for _bit in 0..8 {
|
for _bit in 0..8 {
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,23 +198,31 @@ impl I2C {
|
|||||||
return Err("SDA is stuck low and doesn't get unstuck");
|
return Err("SDA is stuck low and doesn't get unstuck");
|
||||||
}
|
}
|
||||||
if !self.scl_i() {
|
if !self.scl_i() {
|
||||||
return Err("SCL is stuck low and doesn't get unstuck");
|
return Err("SCL is stuck low");
|
||||||
}
|
}
|
||||||
// postcondition: SCL and SDA high
|
// postcondition: SCL and SDA high
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
{
|
||||||
|
self.i2cswr_oe(true);
|
||||||
|
self.pca_type = self.pca_autodetect()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<(), &'static str> {
|
pub fn start(&mut self) -> Result<(), &'static str> {
|
||||||
// precondition: SCL and SDA high
|
// precondition: SCL and SDA high
|
||||||
if !self.scl_i() {
|
if !self.scl_i() {
|
||||||
return Err("SCL is stuck low and doesn't get unstuck");
|
return Err("SCL is stuck low");
|
||||||
}
|
}
|
||||||
if !self.sda_i() {
|
if !self.sda_i() {
|
||||||
return Err("SDA arbitration lost");
|
return Err("SDA arbitration lost");
|
||||||
}
|
}
|
||||||
self.sda_oe(true);
|
self.sda_oe(true);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
|
self.unit_delay();
|
||||||
// postcondition: SCL and SDA low
|
// postcondition: SCL and SDA low
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -150,9 +230,9 @@ impl I2C {
|
|||||||
pub fn restart(&mut self) -> Result<(), &'static str> {
|
pub fn restart(&mut self) -> Result<(), &'static str> {
|
||||||
// precondition SCL and SDA low
|
// precondition SCL and SDA low
|
||||||
self.sda_oe(false);
|
self.sda_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.start()?;
|
self.start()?;
|
||||||
// postcondition: SCL and SDA low
|
// postcondition: SCL and SDA low
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -160,11 +240,11 @@ impl I2C {
|
|||||||
|
|
||||||
pub fn stop(&mut self) -> Result<(), &'static str> {
|
pub fn stop(&mut self) -> Result<(), &'static str> {
|
||||||
// precondition: SCL and SDA low
|
// precondition: SCL and SDA low
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.sda_oe(false);
|
self.sda_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
if !self.sda_i() {
|
if !self.sda_i() {
|
||||||
return Err("SDA arbitration lost");
|
return Err("SDA arbitration lost");
|
||||||
}
|
}
|
||||||
@ -177,18 +257,20 @@ impl I2C {
|
|||||||
// MSB first
|
// MSB first
|
||||||
for bit in (0..8).rev() {
|
for bit in (0..8).rev() {
|
||||||
self.sda_oe(data & (1 << bit) == 0);
|
self.sda_oe(data & (1 << bit) == 0);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
|
self.unit_delay();
|
||||||
}
|
}
|
||||||
self.sda_oe(false);
|
self.sda_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
// Read ack/nack
|
// Read ack/nack
|
||||||
let ack = !self.sda_i();
|
let ack = !self.sda_i();
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
|
self.unit_delay();
|
||||||
self.sda_oe(true);
|
self.sda_oe(true);
|
||||||
// postcondition: SCL and SDA low
|
// postcondition: SCL and SDA low
|
||||||
|
|
||||||
@ -203,17 +285,17 @@ impl I2C {
|
|||||||
|
|
||||||
// MSB first
|
// MSB first
|
||||||
for bit in (0..8).rev() {
|
for bit in (0..8).rev() {
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
if self.sda_i() { data |= 1 << bit }
|
if self.sda_i() { data |= 1 << bit }
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
}
|
}
|
||||||
// Send ack/nack
|
// Send ack/nack (true = nack, false = ack)
|
||||||
self.sda_oe(ack);
|
self.sda_oe(ack);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(false);
|
self.scl_oe(false);
|
||||||
self.half_period();
|
self.unit_delay();
|
||||||
self.scl_oe(true);
|
self.scl_oe(true);
|
||||||
self.sda_oe(true);
|
self.sda_oe(true);
|
||||||
// postcondition: SCL and SDA low
|
// postcondition: SCL and SDA low
|
||||||
@ -221,13 +303,32 @@ impl I2C {
|
|||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pca9548_select(&mut self, address: u8, channels: u8) -> Result<(), &'static str> {
|
pub fn pca954x_select(&mut self, address: u8, channel: Option<u8>) -> Result<(), &'static str> {
|
||||||
self.start()?;
|
self.start()?;
|
||||||
if !self.write(address << 1)? {
|
// PCA9547 supports only one channel at a time
|
||||||
return Err("PCA9548 failed to ack write address")
|
// for compatibility, PCA9548 is treated as such too
|
||||||
|
// channel - Some(x) - # of the channel [0,7], or None for all disabled
|
||||||
|
let setting = match self.pca_type {
|
||||||
|
I2cMultiplexer::PCA9548 => {
|
||||||
|
match channel {
|
||||||
|
Some(ch) => 1 << ch,
|
||||||
|
None => 0,
|
||||||
}
|
}
|
||||||
if !self.write(channels)? {
|
},
|
||||||
return Err("PCA9548 failed to ack control word")
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
I2cMultiplexer::PCA9547 => {
|
||||||
|
match channel {
|
||||||
|
Some(ch) => ch | 0x08,
|
||||||
|
None => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.write(address << 1)? {
|
||||||
|
return Err("PCA954X failed to ack write address")
|
||||||
|
}
|
||||||
|
if !self.write(setting)? {
|
||||||
|
return Err("PCA954X failed to ack control word")
|
||||||
}
|
}
|
||||||
self.stop()?;
|
self.stop()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use volatile_register::{RO, WO, RW};
|
|
||||||
|
|
||||||
use libregister::{
|
use libregister::{
|
||||||
register, register_at,
|
register, register_at,
|
||||||
register_bit, register_bits
|
register_bit, register_bits
|
||||||
@ -22,72 +20,116 @@ use libregister::{
|
|||||||
//
|
//
|
||||||
// Current compatibility:
|
// Current compatibility:
|
||||||
// zc706: GPIO 50, 51 == SCL, SDA
|
// zc706: GPIO 50, 51 == SCL, SDA
|
||||||
|
// kasli_soc: GPIO 50, 51 == SCL, SDA; GPIO 33 == I2C_SW_RESET
|
||||||
|
// ebaz4205: GPIO (EMIO)
|
||||||
|
|
||||||
pub struct RegisterWrapper {
|
pub struct RegisterBlock {
|
||||||
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
||||||
pub gpio_input: &'static mut GPIOInput,
|
pub gpio_input: &'static mut GPIOInput,
|
||||||
pub gpio_direction: &'static mut GPIODirection,
|
pub gpio_direction: &'static mut GPIODirection,
|
||||||
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
pub gpio_output_mask_lower: &'static mut GPIOOutputMaskLower,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisterWrapper {
|
impl RegisterBlock {
|
||||||
pub fn new() -> Self {
|
pub fn i2c() -> Self {
|
||||||
Self {
|
Self {
|
||||||
gpio_output_mask: GPIOOutputMask::new(),
|
gpio_output_mask: GPIOOutputMask::new(),
|
||||||
gpio_input: GPIOInput::new(),
|
gpio_input: GPIOInput::new(),
|
||||||
gpio_direction: GPIODirection::new(),
|
gpio_direction: GPIODirection::new(),
|
||||||
gpio_output_enable: GPIOOutputEnable::new()
|
gpio_output_enable: GPIOOutputEnable::new(),
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
gpio_output_mask_lower: GPIOOutputMaskLower::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MASK_DATA_1_MSW:
|
register!(gpio_output_mask,
|
||||||
// Maskable output data for MIO[53:48]
|
/// MASK_DATA_1_MSW:
|
||||||
register!(gpio_output_mask, GPIOOutputMask, RW, u32);
|
/// Maskable output data for MIO[53:48]
|
||||||
#[cfg(feature = "target_zc706")]
|
GPIOOutputMask, RW, u32);
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_at!(GPIOOutputMask, 0xE000A00C, new);
|
register_at!(GPIOOutputMask, 0xE000A00C, new);
|
||||||
// Output for SCL
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
#[cfg(feature = "target_zc706")]
|
register_bit!(gpio_output_mask,
|
||||||
register_bit!(gpio_output_mask, scl_o, 2);
|
/// Output for SCL
|
||||||
// Output for SDA
|
scl_o, 2);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_bit!(gpio_output_mask, sda_o, 3);
|
register_bit!(gpio_output_mask,
|
||||||
// Mask for keeping bits except SCL and SDA unchanged
|
/// Output for SDA
|
||||||
#[cfg(feature = "target_zc706")]
|
sda_o, 3);
|
||||||
register_bits!(gpio_output_mask, mask, u16, 16, 31);
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
|
register_bits!(gpio_output_mask,
|
||||||
|
/// Mask for keeping bits except SCL and SDA unchanged
|
||||||
|
mask, u16, 16, 31);
|
||||||
|
|
||||||
// DATA_1_RO:
|
|
||||||
// Input data for MIO[53:32]
|
register!(gpio_output_mask_lower,
|
||||||
register!(gpio_input, GPIOInput, RO, u32);
|
/// MASK_DATA_1_LSW:
|
||||||
#[cfg(feature = "target_zc706")]
|
/// Maskable output data for MIO[47:32]
|
||||||
|
GPIOOutputMaskLower, RW, u32);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_at!(GPIOOutputMaskLower, 0xE000A008, new);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_output_mask_lower,
|
||||||
|
/// Output for I2C_SW_RESET (MIO[33])
|
||||||
|
i2cswr_o, 1);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bits!(gpio_output_mask_lower,
|
||||||
|
mask, u16, 16, 31);
|
||||||
|
|
||||||
|
register!(gpio_input,
|
||||||
|
/// DATA_1_RO:
|
||||||
|
/// Input data for MIO[53:32]
|
||||||
|
GPIOInput, RO, u32);
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_at!(GPIOInput, 0xE000A064, new);
|
register_at!(GPIOInput, 0xE000A064, new);
|
||||||
// Input for SCL
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
#[cfg(feature = "target_zc706")]
|
register_bit!(gpio_input,
|
||||||
register_bit!(gpio_input, scl, 18);
|
/// Input for SCL
|
||||||
// Input for SDA
|
scl, 18);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_bit!(gpio_input, sda, 19);
|
register_bit!(gpio_input,
|
||||||
|
/// Input for SDA
|
||||||
|
sda, 19);
|
||||||
|
|
||||||
// DIRM_1:
|
|
||||||
// Direction mode for MIO[53:32]; 0/1 = in/out
|
register!(gpio_direction,
|
||||||
register!(gpio_direction, GPIODirection, RW, u32);
|
/// DIRM_1:
|
||||||
#[cfg(feature = "target_zc706")]
|
/// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||||
|
GPIODirection, RW, u32);
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_at!(GPIODirection, 0xE000A244, new);
|
register_at!(GPIODirection, 0xE000A244, new);
|
||||||
// Direction for SCL
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
#[cfg(feature = "target_zc706")]
|
register_bit!(gpio_direction,
|
||||||
register_bit!(gpio_direction, scl, 18);
|
/// Direction for SCL
|
||||||
// Direction for SDA
|
scl, 18);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_bit!(gpio_direction, sda, 19);
|
register_bit!(gpio_direction,
|
||||||
|
/// Direction for SDA
|
||||||
|
sda, 19);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_direction,
|
||||||
|
/// Direction for I2C_SW_RESET
|
||||||
|
i2cswr, 1);
|
||||||
|
|
||||||
// OEN_1:
|
register!(gpio_output_enable,
|
||||||
// Output enable for MIO[53:32]
|
/// OEN_1:
|
||||||
register!(gpio_output_enable, GPIOOutputEnable, RW, u32);
|
/// Output enable for MIO[53:32]
|
||||||
#[cfg(feature = "target_zc706")]
|
GPIOOutputEnable, RW, u32);
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_at!(GPIOOutputEnable, 0xE000A248, new);
|
register_at!(GPIOOutputEnable, 0xE000A248, new);
|
||||||
// Output enable for SCL
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
#[cfg(feature = "target_zc706")]
|
register_bit!(gpio_output_enable,
|
||||||
register_bit!(gpio_output_enable, scl, 18);
|
/// Output enable for SCL
|
||||||
// Output enable for SDA
|
scl, 18);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
register_bit!(gpio_output_enable, sda, 19);
|
register_bit!(gpio_output_enable,
|
||||||
|
/// Output enable for SDA
|
||||||
|
sda, 19);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
register_bit!(gpio_output_enable,
|
||||||
|
/// Output enable for I2C_SW_RESET
|
||||||
|
i2cswr, 1);
|
||||||
|
|
@ -16,11 +16,12 @@ pub mod axi_gp;
|
|||||||
pub mod ddr;
|
pub mod ddr;
|
||||||
pub mod mpcore;
|
pub mod mpcore;
|
||||||
pub mod gic;
|
pub mod gic;
|
||||||
pub mod flash;
|
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod sdio;
|
pub mod sdio;
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||||
pub mod i2c;
|
pub mod i2c;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod ps7_init;
|
pub mod ps7_init;
|
||||||
|
#[cfg(feature="target_kasli_soc")]
|
||||||
|
pub mod error_led;
|
||||||
|
@ -138,7 +138,7 @@ pub struct RegisterBlock {
|
|||||||
pub icdsgir: ICDSGIR,
|
pub icdsgir: ICDSGIR,
|
||||||
}
|
}
|
||||||
|
|
||||||
register_at!(RegisterBlock, 0xF8F00000, new);
|
register_at!(RegisterBlock, 0xF8F00000, mpcore);
|
||||||
|
|
||||||
register!(value_register, ValueRegister, RW, u32);
|
register!(value_register, ValueRegister, RW, u32);
|
||||||
register_bits!(value_register, value, u32, 0, 31);
|
register_bits!(value_register, value, u32, 0, 31);
|
||||||
@ -154,7 +154,7 @@ register_bit!(scu_control, enable, 0);
|
|||||||
|
|
||||||
impl ScuControl {
|
impl ScuControl {
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.modify(|_, w| w.enable(true));
|
self.modify(|_, w| w.enable(true).scu_speculative_linefill_enable(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
#![cfg(feature = "target_zc706")]
|
|
||||||
|
|
||||||
use crate::println;
|
use crate::println;
|
||||||
|
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
mod zc706;
|
mod zc706;
|
||||||
// mod cora_z7_10;
|
#[cfg(not(feature = "target_zc706"))]
|
||||||
|
mod none;
|
||||||
|
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
use zc706 as target;
|
use zc706 as target;
|
||||||
// #[cfg(feature = "target_cora_z7_10")]
|
#[cfg(not(feature = "target_zc706"))]
|
||||||
// use cora_z7_10 as target;
|
use none as target;
|
||||||
|
|
||||||
pub fn report_differences() {
|
pub fn report_differences() {
|
||||||
for (i, op) in target::INIT_DATA.iter().enumerate() {
|
for (i, op) in target::INIT_DATA.iter().enumerate() {
|
||||||
|
4
libboard_zynq/src/ps7_init/none.rs
Normal file
4
libboard_zynq/src/ps7_init/none.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
use super::InitOp;
|
||||||
|
|
||||||
|
pub const INIT_DATA: &'static [InitOp] = &[
|
||||||
|
];
|
@ -1,6 +1,6 @@
|
|||||||
/// ADMA library
|
/// ADMA library
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use super::SDIO;
|
use super::Sdio;
|
||||||
use libcortex_a9::cache;
|
use libcortex_a9::cache;
|
||||||
use libregister::{
|
use libregister::{
|
||||||
register, register_bit,
|
register, register_bit,
|
||||||
@ -32,7 +32,7 @@ impl Adma2DescTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the table and setup `adma_system_address`
|
/// Initialize the table and setup `adma_system_address`
|
||||||
pub fn setup(&mut self, sdio: &mut SDIO, blk_cnt: u32, buffer: &[u8]) {
|
pub fn setup(&mut self, sdio: &mut Sdio, blk_cnt: u32, buffer: &[u8]) {
|
||||||
let descr_table = &mut self.0;
|
let descr_table = &mut self.0;
|
||||||
let blk_size = sdio
|
let blk_size = sdio
|
||||||
.regs
|
.regs
|
||||||
|
@ -12,7 +12,7 @@ use log::{trace, debug};
|
|||||||
use nb;
|
use nb;
|
||||||
|
|
||||||
/// Basic SDIO Struct with common low-level functions.
|
/// Basic SDIO Struct with common low-level functions.
|
||||||
pub struct SDIO {
|
pub struct Sdio {
|
||||||
regs: &'static mut regs::RegisterBlock,
|
regs: &'static mut regs::RegisterBlock,
|
||||||
count_down: super::timer::global::CountDown<Milliseconds>,
|
count_down: super::timer::global::CountDown<Milliseconds>,
|
||||||
input_clk_hz: u32,
|
input_clk_hz: u32,
|
||||||
@ -48,7 +48,7 @@ pub enum CardType {
|
|||||||
CardMmc,
|
CardMmc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SDIO {
|
impl Sdio {
|
||||||
/// Initialize SDIO0
|
/// Initialize SDIO0
|
||||||
/// card_detect means if we would use the card detect pin,
|
/// card_detect means if we would use the card detect pin,
|
||||||
/// false to disable card detection (assume there is card inserted)
|
/// false to disable card detection (assume there is card inserted)
|
||||||
@ -105,7 +105,7 @@ impl SDIO {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// cora card detect pin
|
// cora card detect pin
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_coraz7")]
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
slcr.sd0_wp_cd_sel.write(47 << 16);
|
slcr.sd0_wp_cd_sel.write(47 << 16);
|
||||||
@ -116,12 +116,38 @@ impl SDIO {
|
|||||||
.speed(true),
|
.speed(true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// kasli_soc and redpitaya card detect pin
|
||||||
|
#[cfg(any(feature = "target_kasli_soc", feature = "target_redpitaya"))]
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
slcr.sd0_wp_cd_sel.write(46 << 16);
|
||||||
|
}
|
||||||
|
slcr.mio_pin_46.write(
|
||||||
|
slcr::MioPin46::zeroed()
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos25)
|
||||||
|
.speed(true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// ebaz4205 card detect pin
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
slcr.sd0_wp_cd_sel.write(34 << 16);
|
||||||
|
}
|
||||||
|
slcr.mio_pin_34.write(
|
||||||
|
slcr::MioPin34::zeroed()
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(true)
|
||||||
|
.speed(true),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
slcr.sdio_rst_ctrl.reset_sdio0();
|
slcr.sdio_rst_ctrl.reset_sdio0();
|
||||||
slcr.aper_clk_ctrl.enable_sdio0();
|
slcr.aper_clk_ctrl.enable_sdio0();
|
||||||
slcr.sdio_clk_ctrl.enable_sdio0();
|
slcr.sdio_clk_ctrl.enable_sdio0();
|
||||||
});
|
});
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
let mut self_ = SDIO {
|
let mut self_ = Sdio {
|
||||||
regs: regs::RegisterBlock::sdio0(),
|
regs: regs::RegisterBlock::sdio0(),
|
||||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||||
input_clk_hz: clocks.sdio_ref_clk(),
|
input_clk_hz: clocks.sdio_ref_clk(),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, SDIO};
|
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, Sdio};
|
||||||
use libcortex_a9::cache;
|
use libcortex_a9::cache;
|
||||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||||
use log::{trace, debug};
|
use log::{trace, debug};
|
||||||
@ -37,7 +37,7 @@ enum CardVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SdCard {
|
pub struct SdCard {
|
||||||
sdio: SDIO,
|
sdio: Sdio,
|
||||||
adma2_desc_table: Adma2DescTable,
|
adma2_desc_table: Adma2DescTable,
|
||||||
card_version: CardVersion,
|
card_version: CardVersion,
|
||||||
hcs: bool,
|
hcs: bool,
|
||||||
@ -171,8 +171,8 @@ impl SdCard {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert SDIO into SdCard struct, error if no card inserted or it is not an SD card.
|
/// Convert Sdio into SdCard struct, error if no card inserted or it is not an SD card.
|
||||||
pub fn from_sdio(mut sdio: SDIO) -> Result<Self, CardInitializationError> {
|
pub fn from_sdio(mut sdio: Sdio) -> Result<Self, CardInitializationError> {
|
||||||
match sdio.identify_card()? {
|
match sdio.identify_card()? {
|
||||||
CardType::CardSd => (),
|
CardType::CardSd => (),
|
||||||
_ => return Err(CardInitializationError::NoCardInserted),
|
_ => return Err(CardInitializationError::NoCardInserted),
|
||||||
@ -192,8 +192,8 @@ impl SdCard {
|
|||||||
Ok(_self)
|
Ok(_self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert SdCard struct back to SDIO struct.
|
/// Convert SdCard struct back to Sdio struct.
|
||||||
pub fn to_sdio(self) -> SDIO {
|
pub fn to_sdio(self) -> Sdio {
|
||||||
self.sdio
|
self.sdio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,11 @@ use libregister::{
|
|||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum PllSource {
|
pub enum PllSource {
|
||||||
IoPll = 0b00,
|
IoPll = 0b000,
|
||||||
ArmPll = 0b10,
|
ArmPll = 0b010,
|
||||||
DdrPll = 0b11,
|
DdrPll = 0b011,
|
||||||
|
// Ethernet controller 0 EMIO clock
|
||||||
|
Emio = 0b100,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -253,12 +255,12 @@ pub struct RegisterBlock {
|
|||||||
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
||||||
pub ddriob_dci_status: DdriobDciStatus,
|
pub ddriob_dci_status: DdriobDciStatus,
|
||||||
}
|
}
|
||||||
register_at!(RegisterBlock, 0xF8000000, new);
|
register_at!(RegisterBlock, 0xF8000000, slcr);
|
||||||
|
|
||||||
impl RegisterBlock {
|
impl RegisterBlock {
|
||||||
/// Required to modify any sclr register
|
/// Required to modify any sclr register
|
||||||
pub fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
pub fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||||
let mut self_ = Self::new();
|
let mut self_ = Self::slcr();
|
||||||
self_.slcr_unlock.unlock();
|
self_.slcr_unlock.unlock();
|
||||||
let r = f(&mut self_);
|
let r = f(&mut self_);
|
||||||
self_.slcr_lock.lock();
|
self_.slcr_lock.lock();
|
||||||
@ -587,22 +589,36 @@ register_bit!(a9_cpu_rst_ctrl, a9_clkstop0, 4);
|
|||||||
register_bit!(a9_cpu_rst_ctrl, a9_rst1, 1);
|
register_bit!(a9_cpu_rst_ctrl, a9_rst1, 1);
|
||||||
register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
|
register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
|
||||||
|
|
||||||
|
pub fn reboot() {
|
||||||
|
RegisterBlock::unlocked(|slcr| {
|
||||||
|
unsafe {
|
||||||
|
let reboot = slcr.reboot_status.read();
|
||||||
|
slcr.reboot_status.write(reboot & 0xF0FFFFFF);
|
||||||
|
slcr.pss_rst_ctrl.modify(|_, w| w.soft_rst(true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum BootModePins {
|
pub enum BootModePins {
|
||||||
|
// CAUTION!
|
||||||
|
// The BOOT_MODE bits table 6-4 in UG585 are *out of order*.
|
||||||
Jtag = 0b000,
|
Jtag = 0b000,
|
||||||
Nor = 0b001,
|
Nor = 0b010,
|
||||||
Nand = 0b010,
|
Nand = 0b100,
|
||||||
QuadSpi = 0b100,
|
QuadSpi = 0b001,
|
||||||
SdCard = 0b110,
|
SdCard = 0b101,
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(boot_mode, BootMode, RO, u32);
|
register!(boot_mode, BootMode, RO, u32);
|
||||||
register_bit!(boot_mode, pll_bypass, 4);
|
register_bit!(boot_mode, pll_bypass, 4);
|
||||||
register_bits_typed!(boot_mode, boot_mode_pins, u8, BootModePins, 0, 3);
|
register_bit!(boot_mode, jtag_routing, 3);
|
||||||
|
register_bits_typed!(boot_mode, boot_mode_pins, u8, BootModePins, 0, 2);
|
||||||
|
|
||||||
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
||||||
register_bit!(pss_rst_ctrl, soft_rst, 1);
|
register_bit!(pss_rst_ctrl, soft_rst, 0);
|
||||||
|
|
||||||
/// Used for MioPin*.io_type
|
/// Used for MioPin*.io_type
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
use libcortex_a9::{asm, mutex::{Mutex, MutexGuard}};
|
||||||
use crate::uart::Uart;
|
use crate::uart::Uart;
|
||||||
|
|
||||||
const UART_RATE: u32 = 115_200;
|
const UART_RATE: u32 = 115_200;
|
||||||
@ -10,7 +10,15 @@ pub fn get_uart<'a>() -> MutexGuard<'a, LazyUart> {
|
|||||||
unsafe { UART.lock() }
|
unsafe { UART.lock() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deinitialize so that the Uart will be reinitialized on next
|
||||||
|
/// output.
|
||||||
|
///
|
||||||
|
/// Delays so that an outstanding transmission can finish.
|
||||||
pub fn drop_uart() {
|
pub fn drop_uart() {
|
||||||
|
for _ in 0..1_000_000 {
|
||||||
|
asm::nop();
|
||||||
|
}
|
||||||
|
|
||||||
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +45,14 @@ impl DerefMut for LazyUart {
|
|||||||
fn deref_mut(&mut self) -> &mut Uart {
|
fn deref_mut(&mut self) -> &mut Uart {
|
||||||
match self {
|
match self {
|
||||||
LazyUart::Uninitialized => {
|
LazyUart::Uninitialized => {
|
||||||
let uart = Uart::serial(UART_RATE);
|
#[cfg(any(feature = "target_coraz7", feature = "target_redpitaya"))]
|
||||||
|
let uart = Uart::uart0(UART_RATE);
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "target_zc706",
|
||||||
|
feature = "target_ebaz4205",
|
||||||
|
feature = "target_kasli_soc",
|
||||||
|
))]
|
||||||
|
let uart = Uart::uart1(UART_RATE);
|
||||||
*self = LazyUart::Initialized(uart);
|
*self = LazyUart::Initialized(uart);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,13 @@ pub struct GlobalTimer {
|
|||||||
impl GlobalTimer {
|
impl GlobalTimer {
|
||||||
/// Get the potentially uninitialized timer
|
/// Get the potentially uninitialized timer
|
||||||
pub unsafe fn get() -> GlobalTimer {
|
pub unsafe fn get() -> GlobalTimer {
|
||||||
let regs = mpcore::RegisterBlock::new();
|
let regs = mpcore::RegisterBlock::mpcore();
|
||||||
GlobalTimer { regs }
|
GlobalTimer { regs }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the timer with a reset
|
/// Get the timer with a reset
|
||||||
pub fn start() -> GlobalTimer {
|
pub fn start() -> GlobalTimer {
|
||||||
let mut regs = mpcore::RegisterBlock::new();
|
let mut regs = mpcore::RegisterBlock::mpcore();
|
||||||
Self::reset(&mut regs);
|
Self::reset(&mut regs);
|
||||||
GlobalTimer { regs }
|
GlobalTimer { regs }
|
||||||
}
|
}
|
||||||
|
@ -13,31 +13,8 @@ pub struct Uart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Uart {
|
impl Uart {
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(any(feature = "target_coraz7", feature = "target_redpitaya"))]
|
||||||
pub fn serial(baudrate: u32) -> Self {
|
pub fn uart0(baudrate: u32) -> Self {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
// Route UART 1 RxD/TxD Signals to MIO Pins
|
|
||||||
// TX pin
|
|
||||||
slcr.mio_pin_48.write(
|
|
||||||
slcr::MioPin48::zeroed()
|
|
||||||
.l3_sel(0b111)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
// RX pin
|
|
||||||
slcr.mio_pin_49.write(
|
|
||||||
slcr::MioPin49::zeroed()
|
|
||||||
.tri_enable(true)
|
|
||||||
.l3_sel(0b111)
|
|
||||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
|
||||||
.pullup(true)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Self::uart1(baudrate)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
|
||||||
pub fn serial(baudrate: u32) -> Self {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Route UART 0 RxD/TxD Signals to MIO Pins
|
// Route UART 0 RxD/TxD Signals to MIO Pins
|
||||||
// TX pin
|
// TX pin
|
||||||
@ -56,10 +33,7 @@ impl Uart {
|
|||||||
.pullup(true)
|
.pullup(true)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Self::uart0(baudrate)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uart0(baudrate: u32) -> Self {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.uart_rst_ctrl.reset_uart0();
|
slcr.uart_rst_ctrl.reset_uart0();
|
||||||
slcr.aper_clk_ctrl.enable_uart0();
|
slcr.aper_clk_ctrl.enable_uart0();
|
||||||
@ -72,7 +46,60 @@ impl Uart {
|
|||||||
self_
|
self_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
|
||||||
pub fn uart1(baudrate: u32) -> Self {
|
pub fn uart1(baudrate: u32) -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// Route UART 1 RxD/TxD Signals to MIO Pins
|
||||||
|
// TX pin
|
||||||
|
slcr.mio_pin_48.write(
|
||||||
|
slcr::MioPin48::zeroed()
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
// RX pin
|
||||||
|
slcr.mio_pin_49.write(
|
||||||
|
slcr::MioPin49::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
slcr.uart_rst_ctrl.reset_uart1();
|
||||||
|
slcr.aper_clk_ctrl.enable_uart1();
|
||||||
|
slcr.uart_clk_ctrl.enable_uart1();
|
||||||
|
});
|
||||||
|
let mut self_ = Uart {
|
||||||
|
regs: regs::RegisterBlock::uart1(),
|
||||||
|
};
|
||||||
|
self_.configure(baudrate);
|
||||||
|
self_
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
pub fn uart1(baudrate: u32) -> Self {
|
||||||
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
// Route UART 1 RxD/TxD Signals to MIO Pins
|
||||||
|
// TX pin
|
||||||
|
slcr.mio_pin_24.write(
|
||||||
|
slcr::MioPin24::zeroed()
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
// RX pin
|
||||||
|
slcr.mio_pin_25.write(
|
||||||
|
slcr::MioPin25::zeroed()
|
||||||
|
.tri_enable(true)
|
||||||
|
.l3_sel(0b111)
|
||||||
|
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||||
|
.pullup(true)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.uart_rst_ctrl.reset_uart1();
|
slcr.uart_rst_ctrl.reset_uart1();
|
||||||
slcr.aper_clk_ctrl.enable_uart1();
|
slcr.aper_clk_ctrl.enable_uart1();
|
||||||
|
29
libconfig/Cargo.toml
Normal file
29
libconfig/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
name = "libconfig"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libboard_zynq = { path = "../libboard_zynq" }
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
|
[dependencies.core_io]
|
||||||
|
git = "https://git.m-labs.hk/M-Labs/rs-core_io.git"
|
||||||
|
rev = "e9d3edf027"
|
||||||
|
features = ["collections"]
|
||||||
|
|
||||||
|
[dependencies.fatfs]
|
||||||
|
git = "https://git.m-labs.hk/M-Labs/rust-fatfs.git"
|
||||||
|
rev = "4b5e420084"
|
||||||
|
default-features = false
|
||||||
|
features = ["core_io"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
target_zc706 = []
|
||||||
|
target_coraz7 = []
|
||||||
|
target_ebaz4205 = []
|
||||||
|
target_redpitaya = []
|
||||||
|
target_kasli_soc = []
|
||||||
|
ipv6 = []
|
||||||
|
fat_lfn = [ "fatfs/alloc" ]
|
181
libconfig/src/bootgen.rs
Normal file
181
libconfig/src/bootgen.rs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
use core_io::{Error, Read, Seek, SeekFrom};
|
||||||
|
use libboard_zynq::devc;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BootgenLoadingError {
|
||||||
|
InvalidBootImageHeader,
|
||||||
|
MissingPartition,
|
||||||
|
EncryptedBitstream,
|
||||||
|
IoError(Error),
|
||||||
|
DevcError(devc::DevcError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for BootgenLoadingError {
|
||||||
|
fn from(error: Error) -> Self {
|
||||||
|
BootgenLoadingError::IoError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<devc::DevcError> for BootgenLoadingError {
|
||||||
|
fn from(error: devc::DevcError) -> Self {
|
||||||
|
BootgenLoadingError::DevcError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Display for BootgenLoadingError {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
use BootgenLoadingError::*;
|
||||||
|
match self {
|
||||||
|
InvalidBootImageHeader => write!(
|
||||||
|
f,
|
||||||
|
"Invalid boot image header. Check if the file is correct."
|
||||||
|
),
|
||||||
|
MissingPartition => write!(f, "Partition not found. Check your compile configuration."),
|
||||||
|
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
|
||||||
|
IoError(e) => write!(f, "Error while reading: {}", e),
|
||||||
|
DevcError(e) => write!(f, "PCAP interface error: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct PartitionHeader {
|
||||||
|
pub encrypted_length: u32,
|
||||||
|
pub unencrypted_length: u32,
|
||||||
|
pub word_length: u32,
|
||||||
|
pub dest_load_addr: u32,
|
||||||
|
pub dest_exec_addr: u32,
|
||||||
|
pub data_offset: u32,
|
||||||
|
pub attribute_bits: u32,
|
||||||
|
pub section_count: u32,
|
||||||
|
pub checksum_offset: u32,
|
||||||
|
pub header_offset: u32,
|
||||||
|
pub cert_offset: u32,
|
||||||
|
pub reserved: [u32; 4],
|
||||||
|
pub checksum: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a u32 word from the reader.
|
||||||
|
fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, BootgenLoadingError> {
|
||||||
|
let mut buffer: [u8; 4] = [0; 4];
|
||||||
|
reader.read_exact(&mut buffer)?;
|
||||||
|
let mut result: u32 = 0;
|
||||||
|
for i in 0..4 {
|
||||||
|
result |= (buffer[i] as u32) << (i * 8);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load PL partition header.
|
||||||
|
fn load_pl_header<File: Read + Seek>(
|
||||||
|
file: &mut File,
|
||||||
|
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||||
|
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||||
|
file.read_exact(&mut buffer)?;
|
||||||
|
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||||
|
if header.attribute_bits & (2 << 4) != 0 {
|
||||||
|
Ok(Some(header))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_ps_header<File: Read + Seek>(
|
||||||
|
file: &mut File,
|
||||||
|
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||||
|
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||||
|
file.read_exact(&mut buffer)?;
|
||||||
|
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||||
|
if header.attribute_bits & (1 << 4) != 0 {
|
||||||
|
Ok(Some(header))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Locate the partition from the image, and return the size (in bytes) of the partition if successful.
|
||||||
|
/// This function would seek the file to the location of the partition.
|
||||||
|
fn locate<
|
||||||
|
File: Read + Seek,
|
||||||
|
F: Fn(&mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError>,
|
||||||
|
>(
|
||||||
|
file: &mut File,
|
||||||
|
f: F,
|
||||||
|
) -> Result<usize, BootgenLoadingError> {
|
||||||
|
file.seek(SeekFrom::Start(0))?;
|
||||||
|
const BOOT_HEADER_SIGN: u32 = 0x584C4E58;
|
||||||
|
// read boot header signature
|
||||||
|
file.seek(SeekFrom::Start(0x24))?;
|
||||||
|
if read_u32(file)? != BOOT_HEADER_SIGN {
|
||||||
|
return Err(BootgenLoadingError::InvalidBootImageHeader);
|
||||||
|
}
|
||||||
|
// find fsbl offset
|
||||||
|
file.seek(SeekFrom::Start(0x30))?;
|
||||||
|
// the length is in bytes, we have to convert it to words to compare with the partition offset
|
||||||
|
// later
|
||||||
|
let fsbl = read_u32(file)? / 4;
|
||||||
|
// read partition header offset
|
||||||
|
file.seek(SeekFrom::Start(0x9C))?;
|
||||||
|
let ptr = read_u32(file)?;
|
||||||
|
debug!("Partition header pointer = {:0X}", ptr);
|
||||||
|
file.seek(SeekFrom::Start(ptr as u64))?;
|
||||||
|
|
||||||
|
// at most 3 partition headers
|
||||||
|
for _ in 0..3 {
|
||||||
|
if let Some(header) = f(file)? {
|
||||||
|
let encrypted_length = header.encrypted_length;
|
||||||
|
let unencrypted_length = header.unencrypted_length;
|
||||||
|
debug!("Unencrypted length = {:0X}", unencrypted_length);
|
||||||
|
if encrypted_length != unencrypted_length {
|
||||||
|
return Err(BootgenLoadingError::EncryptedBitstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_addr = header.data_offset;
|
||||||
|
// skip fsbl
|
||||||
|
if start_addr == fsbl {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
debug!("Partition start address: {:0X}", start_addr);
|
||||||
|
file.seek(SeekFrom::Start(start_addr as u64 * 4))?;
|
||||||
|
|
||||||
|
return Ok(unencrypted_length as usize * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(BootgenLoadingError::MissingPartition)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load bitstream from bootgen file.
|
||||||
|
/// This function parses the file, locate the bitstream and load it through the PCAP driver.
|
||||||
|
/// It requires a large buffer, please enable the DDR RAM before using it.
|
||||||
|
pub fn load_bitstream<File: Read + Seek>(file: &mut File) -> Result<(), BootgenLoadingError> {
|
||||||
|
let size = locate(file, load_pl_header)?;
|
||||||
|
unsafe {
|
||||||
|
// align to 64 bytes
|
||||||
|
let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, 64).unwrap());
|
||||||
|
let buffer = core::slice::from_raw_parts_mut(ptr, size);
|
||||||
|
file.read_exact(buffer).map_err(|e| {
|
||||||
|
core::ptr::drop_in_place(ptr);
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
let mut devcfg = devc::DevC::new();
|
||||||
|
devcfg.enable();
|
||||||
|
devcfg.program(&buffer).map_err(|e| {
|
||||||
|
core::ptr::drop_in_place(ptr);
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
core::ptr::drop_in_place(ptr);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_runtime<File: Read + Seek>(file: &mut File) -> Result<Vec<u8>, BootgenLoadingError> {
|
||||||
|
let size = locate(file, load_ps_header)?;
|
||||||
|
let mut buffer = Vec::with_capacity(size);
|
||||||
|
unsafe {
|
||||||
|
buffer.set_len(size);
|
||||||
|
}
|
||||||
|
file.read_exact(&mut buffer)?;
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
174
libconfig/src/lib.rs
Normal file
174
libconfig/src/lib.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#![no_std]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
|
||||||
|
use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, SeekFrom};
|
||||||
|
use libboard_zynq::sdio;
|
||||||
|
|
||||||
|
pub mod sd_reader;
|
||||||
|
pub mod net_settings;
|
||||||
|
pub mod bootgen;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error<'a> {
|
||||||
|
SdError(sdio::sd_card::CardInitializationError),
|
||||||
|
IoError(io::Error),
|
||||||
|
Utf8Error(FromUtf8Error),
|
||||||
|
KeyNotFoundError(&'a str),
|
||||||
|
NoConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<'a, T> = core::result::Result<T, Error<'a>>;
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for Error<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::SdError(error) => write!(f, "SD error: {}", error),
|
||||||
|
Error::IoError(error) => write!(f, "I/O error: {}", error),
|
||||||
|
Error::Utf8Error(error) => write!(f, "UTF-8 error: {}", error),
|
||||||
|
Error::KeyNotFoundError(name) => write!(f, "Configuration key `{}` not found", name),
|
||||||
|
Error::NoConfig => write!(f, "Configuration not present"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<sdio::sd_card::CardInitializationError> for Error<'a> {
|
||||||
|
fn from(error: sdio::sd_card::CardInitializationError) -> Self {
|
||||||
|
Error::SdError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<io::Error> for Error<'a> {
|
||||||
|
fn from(error: io::Error) -> Self {
|
||||||
|
Error::IoError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<FromUtf8Error> for Error<'a> {
|
||||||
|
fn from(error: FromUtf8Error) -> Self {
|
||||||
|
Error::Utf8Error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_config<'a>(
|
||||||
|
key: &'a str,
|
||||||
|
buffer: &mut Vec<u8>,
|
||||||
|
file: fatfs::File<sd_reader::SdReader>,
|
||||||
|
) -> Result<'a, ()> {
|
||||||
|
let prefix = [key, "="].concat().to_ascii_lowercase();
|
||||||
|
for line in BufReader::new(file).lines() {
|
||||||
|
let line = line?.to_ascii_lowercase();
|
||||||
|
if line.starts_with(&prefix) {
|
||||||
|
buffer.extend(line[prefix.len()..].as_bytes());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::KeyNotFoundError(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const NEWLINE: &[u8] = b"\n";
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new() -> Result<'static, Self> {
|
||||||
|
let sdio = sdio::Sdio::sdio0(true);
|
||||||
|
if !sdio.is_card_inserted() {
|
||||||
|
Err(sdio::sd_card::CardInitializationError::NoCardInserted)?;
|
||||||
|
}
|
||||||
|
let sd = sdio::sd_card::SdCard::from_sdio(sdio)?;
|
||||||
|
let reader = sd_reader::SdReader::new(sd);
|
||||||
|
|
||||||
|
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
|
||||||
|
Ok(Config { fs: Some(Rc::new(fs)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fs(fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>) -> Self {
|
||||||
|
Config { fs }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_dummy() -> Self {
|
||||||
|
Config { fs: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<'b>(&self, key: &'b str) -> Result<'b, Vec<u8>> {
|
||||||
|
if let Some(fs) = &self.fs {
|
||||||
|
let root_dir = fs.root_dir();
|
||||||
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
|
match root_dir.open_file(&["/CONFIG/", key, ".BIN"].concat()) {
|
||||||
|
Ok(mut f) => f.read_to_end(&mut buffer).map(|_| ())?,
|
||||||
|
Err(_) => match root_dir.open_file("/CONFIG.TXT") {
|
||||||
|
Ok(f) => parse_config(key, &mut buffer, f)?,
|
||||||
|
Err(_) => return Err(Error::KeyNotFoundError(key)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(buffer)
|
||||||
|
} else {
|
||||||
|
Err(Error::NoConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
|
||||||
|
Ok(String::from_utf8(self.read(key)?)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove<'b>(&self, key: &'b str) -> Result<'b, ()> {
|
||||||
|
if let Some(fs) = &self.fs {
|
||||||
|
let root_dir = fs.root_dir();
|
||||||
|
match root_dir.remove(&["/CONFIG/", key, ".BIN"].concat()) {
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
Err(_) => {
|
||||||
|
let prefix = [key, "="].concat().to_ascii_lowercase();
|
||||||
|
match root_dir.create_file("/CONFIG.TXT") {
|
||||||
|
Ok(mut f) => {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
f.read_to_string(&mut buffer)?;
|
||||||
|
f.seek(SeekFrom::Start(0))?;
|
||||||
|
f.truncate()?;
|
||||||
|
for line in buffer.lines() {
|
||||||
|
if line.len() > 0 && !line.to_ascii_lowercase().starts_with(&prefix) {
|
||||||
|
f.write(line.as_bytes())?;
|
||||||
|
f.write(NEWLINE)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
Err(_) => Err(Error::KeyNotFoundError(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(Error::NoConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<'b>(&self, key: &'b str, value: Vec<u8>) -> Result<'b, ()> {
|
||||||
|
if self.fs.is_none() {
|
||||||
|
return Err(Error::NoConfig);
|
||||||
|
}
|
||||||
|
let fs = self.fs.as_ref().unwrap();
|
||||||
|
let root_dir = fs.root_dir();
|
||||||
|
let is_str = value.len() <= 100 && value.is_ascii() && !value.contains(&b'\n');
|
||||||
|
if key == "boot" {
|
||||||
|
let mut f = root_dir.create_file("/BOOT.BIN")?;
|
||||||
|
f.truncate()?;
|
||||||
|
f.write_all(&value)?;
|
||||||
|
drop(f);
|
||||||
|
} else {
|
||||||
|
let _ = self.remove(key);
|
||||||
|
if is_str {
|
||||||
|
let mut f = root_dir.create_file("/CONFIG.TXT")?;
|
||||||
|
f.seek(SeekFrom::End(0))?;
|
||||||
|
write!(f, "{}={}\n", key, String::from_utf8(value).unwrap())?;
|
||||||
|
} else {
|
||||||
|
let dir = root_dir.create_dir("/CONFIG")?;
|
||||||
|
let mut f = dir.create_file(&[key, ".BIN"].concat())?;
|
||||||
|
f.write_all(&value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
92
libconfig/src/net_settings.rs
Normal file
92
libconfig/src/net_settings.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use libboard_zynq::smoltcp::wire::{EthernetAddress, IpAddress};
|
||||||
|
|
||||||
|
use super::Config;
|
||||||
|
|
||||||
|
pub struct NetAddresses {
|
||||||
|
pub hardware_addr: EthernetAddress,
|
||||||
|
pub ipv4_addr: IpAddress,
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
pub ipv6_ll_addr: IpAddress,
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
pub ipv6_addr: Option<IpAddress>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NetAddresses {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "MAC={} IPv4={} ",
|
||||||
|
self.hardware_addr, self.ipv4_addr)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
{
|
||||||
|
write!(f, "IPv6-LL={}", self.ipv6_ll_addr)?;
|
||||||
|
match self.ipv6_addr {
|
||||||
|
Some(addr) => write!(f, " {}", addr)?,
|
||||||
|
None => write!(f, " IPv6: no configured address")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
fn get_address_from_eeprom() -> EthernetAddress {
|
||||||
|
use libboard_zynq::i2c::{I2c, eeprom};
|
||||||
|
|
||||||
|
let mut i2c = I2c::i2c0();
|
||||||
|
i2c.init().unwrap();
|
||||||
|
let mut eeprom = eeprom::EEPROM::new(&mut i2c, 16);
|
||||||
|
let address = eeprom.read_eui48().unwrap_or([0x02, 0x00, 0x00, 0x00, 0x00, 0x56]);
|
||||||
|
|
||||||
|
EthernetAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_addresses(cfg: &Config) -> NetAddresses {
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x52]);
|
||||||
|
#[cfg(feature = "target_zc706")]
|
||||||
|
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 52);
|
||||||
|
#[cfg(feature = "target_coraz7")]
|
||||||
|
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x54]);
|
||||||
|
#[cfg(feature = "target_coraz7")]
|
||||||
|
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 54);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x55]);
|
||||||
|
#[cfg(feature = "target_redpitaya")]
|
||||||
|
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 55);
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
let mut hardware_addr = get_address_from_eeprom();
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 56);
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x57]);
|
||||||
|
#[cfg(feature = "target_ebaz4205")]
|
||||||
|
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 57);
|
||||||
|
|
||||||
|
if let Ok(Ok(addr)) = cfg.read_str("mac").map(|s| s.parse()) {
|
||||||
|
hardware_addr = addr;
|
||||||
|
}
|
||||||
|
if let Ok(Ok(addr)) = cfg.read_str("ip").map(|s| s.parse()) {
|
||||||
|
ipv4_addr = addr;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
let ipv6_addr = cfg.read_str("ip6").ok().and_then(|s| s.parse().ok());
|
||||||
|
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
let ipv6_ll_addr = IpAddress::v6(
|
||||||
|
0xfe80, 0x0000, 0x0000, 0x0000,
|
||||||
|
(((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16),
|
||||||
|
((hardware_addr.0[2] as u16) << 8) | 0x00ff,
|
||||||
|
0xfe00 | (hardware_addr.0[3] as u16),
|
||||||
|
((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16));
|
||||||
|
|
||||||
|
NetAddresses {
|
||||||
|
hardware_addr,
|
||||||
|
ipv4_addr,
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
ipv6_ll_addr,
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
ipv6_addr
|
||||||
|
}
|
||||||
|
}
|
304
libconfig/src/sd_reader.rs
Normal file
304
libconfig/src/sd_reader.rs
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
|
||||||
|
use fatfs;
|
||||||
|
use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError};
|
||||||
|
use log::debug;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
const MBR_SIGNATURE: [u8; 2] = [0x55, 0xAA];
|
||||||
|
const PARTID_FAT12: u8 = 0x01;
|
||||||
|
const PARTID_FAT16_LESS32M: u8 = 0x04;
|
||||||
|
const PARTID_FAT16: u8 = 0x06;
|
||||||
|
const PARTID_FAT32: u8 = 0x0B;
|
||||||
|
const PARTID_FAT32_LBA: u8 = 0x0C;
|
||||||
|
const PARTID_FAT16_LBA: u8 = 0x0E;
|
||||||
|
|
||||||
|
fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
|
||||||
|
Error::new(ErrorKind::Other, "Command transfer error")
|
||||||
|
}
|
||||||
|
|
||||||
|
const BLOCK_SIZE: usize = 512;
|
||||||
|
|
||||||
|
/// SdReader struct implementing `Read + BufRead + Write + Seek` traits for `core_io`.
|
||||||
|
/// Used as an adaptor for fatfs crate, but could be used directly for raw data access.
|
||||||
|
///
|
||||||
|
/// Implementation: all read/writes would be split into unaligned and block-aligned parts,
|
||||||
|
/// unaligned read/writes would do a buffered read/write using a block-sized internal buffer,
|
||||||
|
/// while aligned transactions would be sent to the SD card directly for performance reason.
|
||||||
|
pub struct SdReader {
|
||||||
|
/// Internal SdCard handle.
|
||||||
|
sd: SdCard,
|
||||||
|
/// Read buffer with the size of 1 block.
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
/// Address for the next byte.
|
||||||
|
byte_addr: u32,
|
||||||
|
/// Internal index for the next byte.
|
||||||
|
/// Normally in range `[0, BLOCK_SIZE - 1]`.
|
||||||
|
///
|
||||||
|
/// `index = BLOCK_SIZE` means that the `buffer` is invalid for the current `byte_addr`,
|
||||||
|
/// the next `fill_buf` call would fill the buffer.
|
||||||
|
index: usize,
|
||||||
|
/// Dirty flag indicating the content has to be flushed.
|
||||||
|
dirty: bool,
|
||||||
|
/// Base offset for translation from logical address to physical address.
|
||||||
|
offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(unused)]
|
||||||
|
// Partition entry enum, normally we would use entry1.
|
||||||
|
pub enum PartitionEntry {
|
||||||
|
Entry1 = 0x1BE,
|
||||||
|
Entry2 = 0x1CE,
|
||||||
|
Entry3 = 0x1DE,
|
||||||
|
Entry4 = 0x1EE,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SdReader {
|
||||||
|
/// Create SdReader from SdCard
|
||||||
|
pub fn new(sd: SdCard) -> SdReader {
|
||||||
|
let mut vec: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
|
||||||
|
unsafe {
|
||||||
|
vec.set_len(vec.capacity());
|
||||||
|
}
|
||||||
|
SdReader {
|
||||||
|
sd,
|
||||||
|
buffer: vec,
|
||||||
|
byte_addr: 0,
|
||||||
|
index: BLOCK_SIZE,
|
||||||
|
dirty: false,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal read function for unaligned read.
|
||||||
|
/// The read must not cross block boundary.
|
||||||
|
fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
let filled_buffer = self.fill_buf()?;
|
||||||
|
for (dest, src) in buf.iter_mut().zip(filled_buffer.iter()) {
|
||||||
|
*dest = *src;
|
||||||
|
}
|
||||||
|
self.consume(buf.len());
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal write function for unaligned write.
|
||||||
|
/// The write must not cross block boundary.
|
||||||
|
fn write_unaligned(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
// update buffer if needed, as we will flush the entire block later.
|
||||||
|
self.fill_buf()?;
|
||||||
|
self.dirty = true;
|
||||||
|
let dest_buffer = &mut self.buffer[self.index..];
|
||||||
|
for (src, dest) in buf.iter().zip(dest_buffer.iter_mut()) {
|
||||||
|
*dest = *src;
|
||||||
|
}
|
||||||
|
self.consume(buf.len());
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split the slice into three segments, with the middle block-aligned.
|
||||||
|
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
||||||
|
fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) {
|
||||||
|
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
||||||
|
if head_len > buf.len() {
|
||||||
|
(buf, &[], &[])
|
||||||
|
} else {
|
||||||
|
let remaining_length = buf.len() - head_len;
|
||||||
|
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
|
||||||
|
let (head, remaining) = buf.split_at(head_len);
|
||||||
|
let (mid, tail) = remaining.split_at(mid_length);
|
||||||
|
(head, mid, tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split the mutable slice into three segments, with the middle block-aligned.
|
||||||
|
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
|
||||||
|
fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) {
|
||||||
|
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
|
||||||
|
if head_len > buf.len() {
|
||||||
|
(buf, &mut [], &mut [])
|
||||||
|
} else {
|
||||||
|
let remaining_length = buf.len() - head_len;
|
||||||
|
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
|
||||||
|
let (head, remaining) = buf.split_at_mut(head_len);
|
||||||
|
let (mid, tail) = remaining.split_at_mut(mid_length);
|
||||||
|
(head, mid, tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Invalidate the buffer, so later unaligned read/write would reload the buffer from SD card.
|
||||||
|
fn invalidate_buffer(&mut self) {
|
||||||
|
self.index = BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the base offset of the SD card, to transform from physical address to logical address.
|
||||||
|
fn set_base_offset(&mut self, offset: u32) -> IoResult<u64> {
|
||||||
|
self.offset = offset;
|
||||||
|
self.seek(SeekFrom::Start(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mount fatfs from partition entry, and return the fatfs object if success.
|
||||||
|
/// This takes the ownership of self, so currently there is no way to recover from an error,
|
||||||
|
/// except creating a new SD card instance.
|
||||||
|
pub fn mount_fatfs(mut self, entry: PartitionEntry) -> IoResult<fatfs::FileSystem<Self>> {
|
||||||
|
let mut buffer: [u8; 4] = [0; 4];
|
||||||
|
self.seek(SeekFrom::Start(0x1FE))?;
|
||||||
|
self.read_exact(&mut buffer[..2])?;
|
||||||
|
// check MBR signature
|
||||||
|
if buffer[..2] != MBR_SIGNATURE {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"Incorrect signature for MBR sector.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// Read partition ID.
|
||||||
|
self.seek(SeekFrom::Start(entry as u64 + 0x4))?;
|
||||||
|
self.read_exact(&mut buffer[..1])?;
|
||||||
|
debug!("Partition ID: {:0X}", buffer[0]);
|
||||||
|
match buffer[0] {
|
||||||
|
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 |
|
||||||
|
PARTID_FAT16_LBA | PARTID_FAT32 | PARTID_FAT32_LBA => {}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"No FAT partition found for the specified entry.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Read LBA
|
||||||
|
self.seek(SeekFrom::Current(0x3))?;
|
||||||
|
self.read_exact(&mut buffer)?;
|
||||||
|
let mut lba: u32 = 0;
|
||||||
|
// Little endian
|
||||||
|
for i in 0..4 {
|
||||||
|
lba |= (buffer[i] as u32) << (i * 8);
|
||||||
|
}
|
||||||
|
// Set to logical address
|
||||||
|
self.set_base_offset(lba * BLOCK_SIZE as u32)?;
|
||||||
|
// setup fatfs
|
||||||
|
fatfs::FileSystem::new(self, fatfs::FsOptions::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for SdReader {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
||||||
|
let total_length = buf.len();
|
||||||
|
let (a, b, c) = self.block_align_mut(buf);
|
||||||
|
self.read_unaligned(a)?;
|
||||||
|
if b.len() > 0 {
|
||||||
|
// invalidate internal buffer
|
||||||
|
self.invalidate_buffer();
|
||||||
|
if let Err(_) = self.sd.read_block(
|
||||||
|
self.byte_addr / BLOCK_SIZE as u32,
|
||||||
|
(b.len() / BLOCK_SIZE) as u16,
|
||||||
|
b,
|
||||||
|
) {
|
||||||
|
// we have to allow partial read, as per the trait required
|
||||||
|
return Ok(a.len());
|
||||||
|
}
|
||||||
|
self.byte_addr += b.len() as u32;
|
||||||
|
}
|
||||||
|
if let Err(_) = self.read_unaligned(c) {
|
||||||
|
// we have to allow partial read, as per the trait required
|
||||||
|
return Ok(a.len() + b.len());
|
||||||
|
}
|
||||||
|
Ok(total_length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufRead for SdReader {
|
||||||
|
fn fill_buf(&mut self) -> IoResult<&[u8]> {
|
||||||
|
if self.index == BLOCK_SIZE {
|
||||||
|
// flush the buffer if it is dirty before overwriting it with new data
|
||||||
|
if self.dirty {
|
||||||
|
self.flush()?;
|
||||||
|
}
|
||||||
|
// reload buffer
|
||||||
|
self.sd
|
||||||
|
.read_block(self.byte_addr / (BLOCK_SIZE as u32), 1, &mut self.buffer)
|
||||||
|
.map_err(cmd_error_to_io_error)?;
|
||||||
|
self.index = (self.byte_addr as usize) % BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
Ok(&self.buffer[self.index..])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume(&mut self, amt: usize) {
|
||||||
|
self.index += amt;
|
||||||
|
self.byte_addr += amt as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for SdReader {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||||
|
let (a, b, c) = self.block_align(buf);
|
||||||
|
self.write_unaligned(a)?;
|
||||||
|
if b.len() > 0 {
|
||||||
|
self.flush()?;
|
||||||
|
self.invalidate_buffer();
|
||||||
|
if let Err(_) = self.sd.write_block(
|
||||||
|
self.byte_addr / BLOCK_SIZE as u32,
|
||||||
|
(b.len() / BLOCK_SIZE) as u16,
|
||||||
|
b,
|
||||||
|
) {
|
||||||
|
return Ok(a.len());
|
||||||
|
}
|
||||||
|
self.byte_addr += b.len() as u32;
|
||||||
|
}
|
||||||
|
if let Err(_) = self.write_unaligned(c) {
|
||||||
|
return Ok(a.len() + b.len());
|
||||||
|
}
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> IoResult<()> {
|
||||||
|
if self.dirty {
|
||||||
|
let block_addr = (self.byte_addr - self.index as u32) / (BLOCK_SIZE as u32);
|
||||||
|
self.sd
|
||||||
|
.write_block(block_addr, 1, &self.buffer)
|
||||||
|
.map_err(cmd_error_to_io_error)?;
|
||||||
|
self.dirty = false;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Seek for SdReader {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
|
||||||
|
let raw_target = match pos {
|
||||||
|
SeekFrom::Start(x) => self.offset as i64 + x as i64,
|
||||||
|
SeekFrom::Current(x) => self.byte_addr as i64 + x,
|
||||||
|
SeekFrom::End(_) => panic!("SD card does not support seek from end"),
|
||||||
|
};
|
||||||
|
if raw_target < self.offset as i64 || raw_target > core::u32::MAX as i64 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidInput, "Invalid address"));
|
||||||
|
}
|
||||||
|
let target_byte_addr = raw_target as u32;
|
||||||
|
let address_same_block =
|
||||||
|
self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32);
|
||||||
|
// if the buffer was invalidated, we consider seek as different block
|
||||||
|
let same_block = address_same_block && self.index != BLOCK_SIZE;
|
||||||
|
if !same_block {
|
||||||
|
self.flush()?;
|
||||||
|
}
|
||||||
|
self.byte_addr = target_byte_addr;
|
||||||
|
self.index = if same_block {
|
||||||
|
target_byte_addr as usize % BLOCK_SIZE
|
||||||
|
} else {
|
||||||
|
// invalidate the buffer as we moved to a different block
|
||||||
|
BLOCK_SIZE
|
||||||
|
};
|
||||||
|
Ok((self.byte_addr - self.offset) as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SdReader {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// just try to flush it, ignore error if any
|
||||||
|
self.flush().unwrap_or(());
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = []
|
|
||||||
target_cora_z7_10 = []
|
|
||||||
power_saving = []
|
power_saving = []
|
||||||
default = ["target_zc706"]
|
default = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bit_field = "0.10"
|
bit_field = "0.10"
|
||||||
|
volatile-register = "0.2"
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
|
@ -1,53 +1,60 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
/// The classic no-op
|
/// The classic no-op
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn nop() {
|
pub fn nop() {
|
||||||
unsafe { llvm_asm!("nop" :::: "volatile") }
|
unsafe { asm!("nop") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait For Event
|
/// Wait For Event
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wfe() {
|
pub fn wfe() {
|
||||||
unsafe { llvm_asm!("wfe" :::: "volatile") }
|
unsafe { asm!("wfe") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send Event
|
/// Send Event
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sev() {
|
pub fn sev() {
|
||||||
unsafe { llvm_asm!("sev" :::: "volatile") }
|
unsafe { asm!("sev") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data Memory Barrier
|
/// Data Memory Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dmb() {
|
pub fn dmb() {
|
||||||
unsafe { llvm_asm!("dmb" :::: "volatile") }
|
unsafe { asm!("dmb") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data Synchronization Barrier
|
/// Data Synchronization Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dsb() {
|
pub fn dsb() {
|
||||||
unsafe { llvm_asm!("dsb" :::: "volatile") }
|
unsafe { asm!("dsb") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instruction Synchronization Barrier
|
/// Instruction Synchronization Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn isb() {
|
pub fn isb() {
|
||||||
unsafe { llvm_asm!("isb" :::: "volatile") }
|
unsafe { asm!("isb") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable FIQ
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn enable_fiq() {
|
||||||
|
asm!("cpsie f");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable IRQ
|
/// Enable IRQ
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn enable_irq() {
|
pub unsafe fn enable_irq() {
|
||||||
llvm_asm!("cpsie i":::: "volatile");
|
asm!("cpsie i");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disable IRQ, return if IRQ was originally enabled.
|
/// Disable IRQ, return if IRQ was originally enabled.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn enter_critical() -> bool {
|
pub unsafe fn enter_critical() -> bool {
|
||||||
let mut cpsr: u32;
|
let mut cpsr: u32;
|
||||||
llvm_asm!(
|
asm!(
|
||||||
"mrs $0, cpsr
|
"mrs {}, cpsr
|
||||||
cpsid i"
|
cpsid i", lateout(reg) cpsr);
|
||||||
: "=r"(cpsr) ::: "volatile");
|
|
||||||
(cpsr & (1 << 7)) == 0
|
(cpsr & (1 << 7)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,18 +66,18 @@ pub unsafe fn exit_critical(enable: bool) {
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
llvm_asm!(
|
asm!(
|
||||||
"mrs r1, cpsr
|
"mrs r1, cpsr
|
||||||
bic r1, r1, $0
|
bic r1, r1, {}
|
||||||
msr cpsr_c, r1"
|
msr cpsr_c, r1"
|
||||||
:: "r"(mask) : "r1");
|
, in(reg) mask, out("r1") _);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exiting IRQ
|
/// Exiting IRQ
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn exit_irq() {
|
pub unsafe fn exit_irq() {
|
||||||
llvm_asm!("
|
asm!("
|
||||||
mrs r0, SPSR
|
mrs r0, SPSR
|
||||||
msr CPSR, r0
|
msr CPSR, r0
|
||||||
" ::: "r0");
|
", out("r0") _);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use super::asm::{dmb, dsb};
|
use super::asm::{dmb, dsb};
|
||||||
|
use super::l2c::*;
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
/// Invalidate TLBs
|
/// Invalidate TLBs
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn tlbiall() {
|
pub fn tlbiall() {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c8, c7, 0" :: "r" (0) :: "volatile");
|
asm!("mcr p15, 0, {}, c8, c7, 0", in(reg) 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,7 +14,7 @@ pub fn tlbiall() {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn iciallu() {
|
pub fn iciallu() {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c5, 0" :: "r" (0) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c5, 0", in(reg) 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ pub fn iciallu() {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bpiall() {
|
pub fn bpiall() {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c5, 6" :: "r" (0) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c5, 6", in(reg) 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ pub fn bpiall() {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccsw(setway: u32) {
|
pub fn dccsw(setway: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c10, 2" :: "r" (setway) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c10, 2", in(reg) setway);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ pub fn dcisw(setway: u32) {
|
|||||||
// also see example code (for DCCISW, but DCISW will be
|
// also see example code (for DCCISW, but DCISW will be
|
||||||
// analogous) "Example code for cache maintenance operations"
|
// analogous) "Example code for cache maintenance operations"
|
||||||
// on pages B2-1286 and B2-1287.
|
// on pages B2-1286 and B2-1287.
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c6, 2" :: "r" (setway) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c6, 2", in(reg) setway);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,14 +50,13 @@ pub fn dcisw(setway: u32) {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccisw(setway: u32) {
|
pub fn dccisw(setway: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c14, 2" :: "r" (setway) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c14, 2", in(reg) setway);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dciall() {
|
pub fn dciall_l1() {
|
||||||
// the cache associativity could be read from a register, but will
|
// the cache associativity could be read from a register, but will
|
||||||
// always be 4 in L1 data cache of a cortex a9
|
// always be 4 in L1 data cache of a cortex a9
|
||||||
let ways = 4;
|
let ways = 4;
|
||||||
@ -69,7 +70,7 @@ pub fn dciall() {
|
|||||||
|
|
||||||
// select L1 data cache
|
// select L1 data cache
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
asm!("mcr p15, 2, {}, c0, c0, 0", in(reg) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate entire D-Cache by iterating every set and every way
|
// Invalidate entire D-Cache by iterating every set and every way
|
||||||
@ -80,9 +81,17 @@ pub fn dciall() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A made-up "instruction": invalidate all of the L1 L2 D-Cache
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dciall() {
|
||||||
|
dmb();
|
||||||
|
l2_cache_invalidate_all();
|
||||||
|
dciall_l1();
|
||||||
|
}
|
||||||
|
|
||||||
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dcciall() {
|
pub fn dcciall_l1() {
|
||||||
// the cache associativity could be read from a register, but will
|
// the cache associativity could be read from a register, but will
|
||||||
// always be 4 in L1 data cache of a cortex a9
|
// always be 4 in L1 data cache of a cortex a9
|
||||||
let ways = 4;
|
let ways = 4;
|
||||||
@ -96,7 +105,7 @@ pub fn dcciall() {
|
|||||||
|
|
||||||
// select L1 data cache
|
// select L1 data cache
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
asm!("mcr p15, 2, {}, c0, c0, 0", in(reg) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate entire D-Cache by iterating every set and every way
|
// Invalidate entire D-Cache by iterating every set and every way
|
||||||
@ -107,6 +116,15 @@ pub fn dcciall() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn dcciall() {
|
||||||
|
dmb();
|
||||||
|
dcciall_l1();
|
||||||
|
dsb();
|
||||||
|
l2_cache_clean_invalidate_all();
|
||||||
|
dcciall_l1();
|
||||||
|
dsb();
|
||||||
|
}
|
||||||
|
|
||||||
const CACHE_LINE: usize = 0x20;
|
const CACHE_LINE: usize = 0x20;
|
||||||
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||||
@ -139,13 +157,22 @@ fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccimvac(addr: usize) {
|
pub fn dccimvac(addr: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c14, 1" :: "r" (addr) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c14, 1", in(reg) addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean and invalidate for an object.
|
/// Data cache clean and invalidate for an object.
|
||||||
pub fn dcci<T>(object: &T) {
|
pub fn dcci<T>(object: &T) {
|
||||||
|
// ref: L2C310 TRM 3.3.10
|
||||||
dmb();
|
dmb();
|
||||||
|
for addr in object_cache_line_addrs(object) {
|
||||||
|
dccmvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
for addr in object_cache_line_addrs(object) {
|
||||||
|
l2_cache_clean_invalidate(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
for addr in object_cache_line_addrs(object) {
|
for addr in object_cache_line_addrs(object) {
|
||||||
dccimvac(addr);
|
dccimvac(addr);
|
||||||
}
|
}
|
||||||
@ -154,6 +181,14 @@ pub fn dcci<T>(object: &T) {
|
|||||||
|
|
||||||
pub fn dcci_slice<T>(slice: &[T]) {
|
pub fn dcci_slice<T>(slice: &[T]) {
|
||||||
dmb();
|
dmb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
dccmvac(addr);
|
||||||
|
}
|
||||||
|
dsb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
l2_cache_clean_invalidate(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
dccimvac(addr);
|
dccimvac(addr);
|
||||||
}
|
}
|
||||||
@ -164,10 +199,9 @@ pub fn dcci_slice<T>(slice: &[T]) {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccmvac(addr: usize) {
|
pub fn dccmvac(addr: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c10, 1" :: "r" (addr) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c10, 1", in(reg) addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean for an object.
|
/// Data cache clean for an object.
|
||||||
pub fn dcc<T>(object: &T) {
|
pub fn dcc<T>(object: &T) {
|
||||||
dmb();
|
dmb();
|
||||||
@ -175,17 +209,28 @@ pub fn dcc<T>(object: &T) {
|
|||||||
dccmvac(addr);
|
dccmvac(addr);
|
||||||
}
|
}
|
||||||
dsb();
|
dsb();
|
||||||
|
for addr in object_cache_line_addrs(object) {
|
||||||
|
l2_cache_clean(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean for an object. Panics if not properly
|
/// Data cache clean for an object. Panics if not properly
|
||||||
/// aligned and properly sized to be contained in an exact number of
|
/// aligned and properly sized to be contained in an exact number of
|
||||||
/// cache lines.
|
/// cache lines.
|
||||||
pub fn dcc_slice<T>(slice: &[T]) {
|
pub fn dcc_slice<T>(slice: &[T]) {
|
||||||
|
if slice.len() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
dmb();
|
dmb();
|
||||||
for addr in slice_cache_line_addrs(slice) {
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
dccmvac(addr);
|
dccmvac(addr);
|
||||||
}
|
}
|
||||||
dsb();
|
dsb();
|
||||||
|
for addr in slice_cache_line_addrs(slice) {
|
||||||
|
l2_cache_clean(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache invalidate by memory virtual address. This and
|
/// Data cache invalidate by memory virtual address. This and
|
||||||
@ -194,7 +239,7 @@ pub fn dcc_slice<T>(slice: &[T]) {
|
|||||||
/// affecting more data than intended.
|
/// affecting more data than intended.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn dcimvac(addr: usize) {
|
pub unsafe fn dcimvac(addr: usize) {
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c6, 1" :: "r" (addr) :: "volatile");
|
asm!("mcr p15, 0, {}, c7, c6, 1", in(reg) addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean and invalidate for an object.
|
/// Data cache clean and invalidate for an object.
|
||||||
@ -205,6 +250,10 @@ pub unsafe fn dci<T>(object: &mut T) {
|
|||||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
||||||
|
|
||||||
dmb();
|
dmb();
|
||||||
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
|
l2_cache_invalidate(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
dcimvac(addr);
|
dcimvac(addr);
|
||||||
}
|
}
|
||||||
@ -219,6 +268,10 @@ pub unsafe fn dci_slice<T>(slice: &mut [T]) {
|
|||||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
||||||
|
|
||||||
dmb();
|
dmb();
|
||||||
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
|
l2_cache_invalidate(addr);
|
||||||
|
}
|
||||||
|
l2_cache_sync();
|
||||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||||
dcimvac(addr);
|
dcimvac(addr);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use core::arch::asm;
|
||||||
/// Enable FPU in the current core.
|
/// Enable FPU in the current core.
|
||||||
pub fn enable_fpu() {
|
pub fn enable_fpu() {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("
|
asm!("
|
||||||
mrc p15, 0, r1, c1, c0, 2
|
mrc p15, 0, r1, c1, c0, 2
|
||||||
orr r1, r1, (0b1111<<20)
|
orr r1, r1, (0b1111<<20)
|
||||||
mcr p15, 0, r1, c1, c0, 2
|
mcr p15, 0, r1, c1, c0, 2
|
||||||
@ -9,6 +10,6 @@ pub fn enable_fpu() {
|
|||||||
vmrs r1, fpexc
|
vmrs r1, fpexc
|
||||||
orr r1, r1, (1<<30)
|
orr r1, r1, (1<<30)
|
||||||
vmsr fpexc, r1
|
vmsr fpexc, r1
|
||||||
":::"r1");
|
", out("r1") _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
333
libcortex_a9/src/l2c.rs
Normal file
333
libcortex_a9/src/l2c.rs
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
use libregister::{register, register_at, register_bit, register_bits, RegisterRW, RegisterR, RegisterW};
|
||||||
|
use super::asm::dmb;
|
||||||
|
use volatile_register::RW;
|
||||||
|
|
||||||
|
/// enable L2 cache with specific prefetch offset
|
||||||
|
/// prefetch offset requires manual tuning, it seems that 8 is good for ZC706 current settings
|
||||||
|
pub fn enable_l2_cache(offset: u8) {
|
||||||
|
dmb();
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
// disable L2 cache
|
||||||
|
regs.reg1_control.modify(|_, w| w.l2_enable(false));
|
||||||
|
|
||||||
|
regs.reg15_prefetch_ctrl.modify(|_, w|
|
||||||
|
w.instr_prefetch_en(true)
|
||||||
|
.data_prefetch_en(true)
|
||||||
|
.double_linefill_en(true)
|
||||||
|
.incr_double_linefill_en(true)
|
||||||
|
.pref_drop_en(true)
|
||||||
|
.prefetch_offset(offset)
|
||||||
|
);
|
||||||
|
regs.reg1_aux_control.modify(|_, w| {
|
||||||
|
w.early_bresp_en(true)
|
||||||
|
.instr_prefetch_en(true)
|
||||||
|
.data_prefetch_en(true)
|
||||||
|
.cache_replace_policy(true)
|
||||||
|
.way_size(3)
|
||||||
|
});
|
||||||
|
regs.reg1_tag_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(1).ram_setup_lat(1));
|
||||||
|
regs.reg1_data_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(2).ram_setup_lat(1));
|
||||||
|
// invalidate L2 ways
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_inv_way.write(0xFFFF);
|
||||||
|
}
|
||||||
|
// poll for completion
|
||||||
|
while regs.reg7_cache_sync.read().c() {}
|
||||||
|
// write to a magic memory location with a magic sequence
|
||||||
|
// required in UG585 Section 3.4.10 Initialization Sequence
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(0xF8000008usize as *mut u32, 0xDF0D);
|
||||||
|
core::ptr::write_volatile(0xF8000A1Cusize as *mut u32, 0x020202);
|
||||||
|
core::ptr::write_volatile(0xF8000004usize as *mut u32, 0x767B);
|
||||||
|
}
|
||||||
|
regs.reg1_control.modify(|_, w| w.l2_enable(true));
|
||||||
|
dmb();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_invalidate_all() {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_inv_way.write(0xFFFF);
|
||||||
|
}
|
||||||
|
// poll for completion
|
||||||
|
while regs.reg7_cache_sync.read().c() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_clean_all() {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_clean_way.write(0xFFFF);
|
||||||
|
}
|
||||||
|
// poll for completion
|
||||||
|
while regs.reg7_cache_sync.read().c() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_clean_invalidate_all() {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_clean_inv_way.write(0xFFFF);
|
||||||
|
}
|
||||||
|
// poll for completion
|
||||||
|
while regs.reg7_cache_sync.read().c() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// L2 cache sync, similar to dsb for L1 cache
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_sync() {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
regs.reg7_cache_sync.write(Reg7CacheSync::zeroed().c(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_clean(addr: usize) {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_clean_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_invalidate(addr: usize) {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn l2_cache_clean_invalidate(addr: usize) {
|
||||||
|
let regs = RegisterBlock::new();
|
||||||
|
unsafe {
|
||||||
|
regs.reg7_clean_inv_pa.write(addr as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct RegisterBlock {
|
||||||
|
/// cache ID register, Returns the 32-bit device ID code it reads off the CACHEID input bus.
|
||||||
|
/// The value is specified by the system integrator. Reset value: 0x410000c8
|
||||||
|
pub reg0_cache_id: Reg0CacheId,
|
||||||
|
/// cache type register, Returns the 32-bit cache type. Reset value: 0x1c100100
|
||||||
|
pub reg0_cache_type: Reg0CacheType,
|
||||||
|
unused0: [u32; 62],
|
||||||
|
/// control register, reset value: 0x0
|
||||||
|
pub reg1_control: Reg1Control,
|
||||||
|
/// auxilary control register, reset value: 0x02020000
|
||||||
|
pub reg1_aux_control: Reg1AuxControl,
|
||||||
|
/// Configures Tag RAM latencies
|
||||||
|
pub reg1_tag_ram_control: Reg1TagRamControl,
|
||||||
|
/// configures data RAM latencies
|
||||||
|
pub reg1_data_ram_control: Reg1DataRamControl,
|
||||||
|
unused1: [u32; 60],
|
||||||
|
/// Permits the event counters to be enabled and reset.
|
||||||
|
pub reg2_ev_counter_ctrl: Reg2EvCounterCtrl,
|
||||||
|
/// Enables event counter 1 to be driven by a specific event. Counter 1 increments when the
|
||||||
|
/// event occurs.
|
||||||
|
pub reg2_ev_counter1_cfg: Reg2EvCounter1Cfg,
|
||||||
|
/// Enables event counter 0 to be driven by a specific event. Counter 0 increments when the
|
||||||
|
/// event occurs.
|
||||||
|
pub reg2_ev_counter0_cfg: Reg2EvCounter0Cfg,
|
||||||
|
/// Enable the programmer to read off the counter value. The counter counts an event as
|
||||||
|
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
||||||
|
/// is disabled and reset by the Event Counter Control Register.
|
||||||
|
pub reg2_ev_counter1: RW<u32>,
|
||||||
|
/// Enable the programmer to read off the counter value. The counter counts an event as
|
||||||
|
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
||||||
|
/// is disabled and reset by the Event Counter Control Register.
|
||||||
|
pub reg2_ev_counter0: RW<u32>,
|
||||||
|
/// This register enables or masks interrupts from being triggered on the external pins of the
|
||||||
|
/// cache controller. Figure 3-8 on page 3-17 shows the register bit assignments. The bit
|
||||||
|
/// assignments enables the masking of the interrupts on both their individual outputs and the
|
||||||
|
/// combined L2CCINTR line. Clearing a bit by writing a 0, disables the interrupt triggering on
|
||||||
|
/// that pin. All bits are cleared by a reset. You must write to the register bits with a 1 to
|
||||||
|
/// enable the generation of interrupts. 1 = Enabled. 0 = Masked. This is the default.
|
||||||
|
pub reg2_int_mask: Reg2IntMask,
|
||||||
|
/// This register is a read-only.It returns the masked interrupt status. This register can be
|
||||||
|
/// accessed by secure and non-secure operations. The register gives an AND function of the raw
|
||||||
|
/// interrupt status with the values of the interrupt mask register. All the bits are cleared
|
||||||
|
/// by a reset. A write to this register is ignored. Bits read can be HIGH or LOW: HIGH If the
|
||||||
|
/// bits read HIGH, they reflect the status of the input lines triggering an interrupt. LOW If
|
||||||
|
/// the bits read LOW, either no interrupt has been generated, or the interrupt is masked.
|
||||||
|
pub reg2_int_mask_status: Reg2IntMaskStatus,
|
||||||
|
/// The Raw Interrupt Status Register enables the interrupt status that excludes the masking
|
||||||
|
/// logic. Bits read can be HIGH or LOW: HIGH If the bits read HIGH, they reflect the status of
|
||||||
|
/// the input lines triggering an interrupt. LOW If the bits read LOW, no interrupt has been
|
||||||
|
/// generated.
|
||||||
|
pub reg2_int_raw_status: Reg2IntRawStatus,
|
||||||
|
/// Clears the Raw Interrupt Status Register bits. When a bit is written as 1, it clears the
|
||||||
|
/// corresponding bit in the Raw Interrupt Status Register. When a bit is written as 0, it has
|
||||||
|
/// no effect
|
||||||
|
pub reg2_int_clear: Reg2IntClear,
|
||||||
|
unused2: [u32; 323],
|
||||||
|
/// Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and EB, are empty
|
||||||
|
pub reg7_cache_sync: Reg7CacheSync,
|
||||||
|
unused3: [u32; 15],
|
||||||
|
/// Invalidate Line by PA: Specific L2 cache line is marked as not valid
|
||||||
|
pub reg7_inv_pa: RW<u32>,
|
||||||
|
unused4: [u32; 2],
|
||||||
|
/// Invalidate by Way Invalidate all data in specified ways, including dirty data. An
|
||||||
|
/// Invalidate by way while selecting all cache ways is equivalent to invalidating all cache
|
||||||
|
/// entries. Completes as a background task with the way, or ways, locked, preventing
|
||||||
|
/// allocation.
|
||||||
|
pub reg7_inv_way: RW<u32>,
|
||||||
|
unused5: [u32; 12],
|
||||||
|
/// Clean Line by PA Write the specific L2 cache line to L3 main memory if the line is marked
|
||||||
|
/// as valid and dirty. The line is marked as not dirty. The valid bit is unchanged
|
||||||
|
pub reg7_clean_pa: RW<u32>,
|
||||||
|
unused6: [u32; 1],
|
||||||
|
/// Clean Line by Set/Way Write the specific L2 cache line within the specified way to L3 main
|
||||||
|
/// memory if the line is marked as valid and dirty. The line is marked as not dirty. The valid
|
||||||
|
/// bit is unchanged
|
||||||
|
pub reg7_clean_index: Reg7CleanIndex,
|
||||||
|
/// Clean by Way Writes each line of the specified L2 cache ways to L3 main memory if the line
|
||||||
|
/// is marked as valid and dirty. The lines are marked as not dirty. The valid bits are
|
||||||
|
/// unchanged. Completes as a background task with the way, or ways, locked, preventing
|
||||||
|
/// allocation.
|
||||||
|
pub reg7_clean_way: RW<u32>,
|
||||||
|
unused7: [u32; 12],
|
||||||
|
/// Clean and Invalidate Line by PA Write the specific L2 cache line to L3 main memory if the
|
||||||
|
/// line is marked as valid and dirty. The line is marked as not valid
|
||||||
|
pub reg7_clean_inv_pa: RW<u32>,
|
||||||
|
unused8: [u32; 1],
|
||||||
|
/// Clean and Invalidate Line by Set/Way Write the specific L2 cache line within the specified
|
||||||
|
/// way to L3 main memory if the line is marked as valid and dirty. The line is marked as not
|
||||||
|
/// valid
|
||||||
|
pub reg7_clean_inv_index: Reg7CleanInvIndex,
|
||||||
|
/// Clean and Invalidate by Way Writes each line of the specified L2 cache ways to L3 main
|
||||||
|
/// memory if the line is marked as valid and dirty. The lines are marked as not valid.
|
||||||
|
/// Completes as a background task with the way, or ways, locked, preventing allocation.
|
||||||
|
pub reg7_clean_inv_way: RW<u32>,
|
||||||
|
unused9: [u32; 0x1D8],
|
||||||
|
pub reg15_prefetch_ctrl: Reg15PrefetechCtrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
register_at!(RegisterBlock, 0xF8F02000, new);
|
||||||
|
|
||||||
|
register!(reg0_cache_id, Reg0CacheId, RW, u32);
|
||||||
|
register_bits!(reg0_cache_id, implementer, u8, 24, 31);
|
||||||
|
register_bits!(reg0_cache_id, cache_id, u8, 10, 15);
|
||||||
|
register_bits!(reg0_cache_id, part_num, u8, 6, 9);
|
||||||
|
register_bits!(reg0_cache_id, rtl_release, u8, 0, 5);
|
||||||
|
|
||||||
|
register!(reg0_cache_type, Reg0CacheType, RW, u32);
|
||||||
|
register_bit!(reg0_cache_type, data_banking, 31);
|
||||||
|
register_bits!(reg0_cache_type, ctype, u8, 25, 28);
|
||||||
|
register_bit!(reg0_cache_type, h, 24);
|
||||||
|
register_bits!(reg0_cache_type, dsize_middsize_19, u8, 20, 22);
|
||||||
|
register_bit!(reg0_cache_type, l2_assoc_d, 18);
|
||||||
|
register_bits!(reg0_cache_type, l2cache_line_len_disize_11, u8, 12, 13);
|
||||||
|
register_bits!(reg0_cache_type, isize_midisize_7, u8, 8, 10);
|
||||||
|
register_bit!(reg0_cache_type, l2_assoc_i, 6);
|
||||||
|
register_bits!(reg0_cache_type, l2cache_line_len_i, u8, 0, 1);
|
||||||
|
|
||||||
|
register!(reg1_control, Reg1Control, RW, u32);
|
||||||
|
register_bit!(reg1_control, l2_enable, 0);
|
||||||
|
|
||||||
|
register!(reg1_aux_control, Reg1AuxControl, RW, u32);
|
||||||
|
register_bit!(reg1_aux_control, early_bresp_en, 30);
|
||||||
|
register_bit!(reg1_aux_control, instr_prefetch_en, 29);
|
||||||
|
register_bit!(reg1_aux_control, data_prefetch_en, 28);
|
||||||
|
register_bit!(reg1_aux_control, nonsec_inte_access_ctrl, 27);
|
||||||
|
register_bit!(reg1_aux_control, nonsec_lockdown_en, 26);
|
||||||
|
register_bit!(reg1_aux_control, cache_replace_policy, 25);
|
||||||
|
register_bits!(reg1_aux_control, force_write_alloc, u8, 23, 24);
|
||||||
|
register_bit!(reg1_aux_control, shared_attr_override_en, 22);
|
||||||
|
register_bit!(reg1_aux_control, parity_en, 21);
|
||||||
|
register_bit!(reg1_aux_control, event_mon_bus_en, 20);
|
||||||
|
register_bits!(reg1_aux_control, way_size, u8, 17, 19);
|
||||||
|
register_bit!(reg1_aux_control, associativity, 16);
|
||||||
|
register_bit!(reg1_aux_control, shared_attr_inva_en, 13);
|
||||||
|
register_bit!(reg1_aux_control, ex_cache_config, 12);
|
||||||
|
register_bit!(reg1_aux_control, store_buff_dev_lim_en, 11);
|
||||||
|
register_bit!(reg1_aux_control, high_pr_so_dev_rd_en, 10);
|
||||||
|
register_bit!(reg1_aux_control, full_line_zero_enable, 0);
|
||||||
|
|
||||||
|
register!(reg1_tag_ram_control, Reg1TagRamControl, RW, u32);
|
||||||
|
register_bits!(reg1_tag_ram_control, ram_wr_access_lat, u8, 8, 10);
|
||||||
|
register_bits!(reg1_tag_ram_control, ram_rd_access_lat, u8, 4, 6);
|
||||||
|
register_bits!(reg1_tag_ram_control, ram_setup_lat, u8, 0, 2);
|
||||||
|
|
||||||
|
register!(reg1_data_ram_control, Reg1DataRamControl, RW, u32);
|
||||||
|
register_bits!(reg1_data_ram_control, ram_wr_access_lat, u8, 8, 10);
|
||||||
|
register_bits!(reg1_data_ram_control, ram_rd_access_lat, u8, 4, 6);
|
||||||
|
register_bits!(reg1_data_ram_control, ram_setup_lat, u8, 0, 2);
|
||||||
|
|
||||||
|
register!(reg2_ev_counter_ctrl, Reg2EvCounterCtrl, RW, u32);
|
||||||
|
register_bit!(reg2_ev_counter_ctrl, ev_ctr_en, 0);
|
||||||
|
|
||||||
|
register!(reg2_ev_counter1_cfg, Reg2EvCounter1Cfg, RW, u32);
|
||||||
|
register_bits!(reg2_ev_counter1_cfg, ctr_ev_src, u8, 2, 5);
|
||||||
|
register_bits!(reg2_ev_counter1_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
||||||
|
|
||||||
|
register!(reg2_ev_counter0_cfg, Reg2EvCounter0Cfg, RW, u32);
|
||||||
|
register_bits!(reg2_ev_counter0_cfg, ctr_ev_src, u8, 2, 5);
|
||||||
|
register_bits!(reg2_ev_counter0_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
||||||
|
|
||||||
|
register!(reg2_int_mask, Reg2IntMask, RW, u32);
|
||||||
|
register_bit!(reg2_int_mask, decerr, 8);
|
||||||
|
register_bit!(reg2_int_mask, slverr, 7);
|
||||||
|
register_bit!(reg2_int_mask, errrd, 6);
|
||||||
|
register_bit!(reg2_int_mask, errrt, 5);
|
||||||
|
register_bit!(reg2_int_mask, errwd, 4);
|
||||||
|
register_bit!(reg2_int_mask, errwt, 3);
|
||||||
|
register_bit!(reg2_int_mask, parrd, 2);
|
||||||
|
register_bit!(reg2_int_mask, parrt, 1);
|
||||||
|
register_bit!(reg2_int_mask, ecntr, 0);
|
||||||
|
|
||||||
|
register!(reg2_int_mask_status, Reg2IntMaskStatus, RW, u32);
|
||||||
|
register_bit!(reg2_int_mask_status, decerr, 8);
|
||||||
|
register_bit!(reg2_int_mask_status, slverr, 7);
|
||||||
|
register_bit!(reg2_int_mask_status, errrd, 6);
|
||||||
|
register_bit!(reg2_int_mask_status, errrt, 5);
|
||||||
|
register_bit!(reg2_int_mask_status, errwd, 4);
|
||||||
|
register_bit!(reg2_int_mask_status, errwt, 3);
|
||||||
|
register_bit!(reg2_int_mask_status, parrd, 2);
|
||||||
|
register_bit!(reg2_int_mask_status, parrt, 1);
|
||||||
|
register_bit!(reg2_int_mask_status, ecntr, 0);
|
||||||
|
|
||||||
|
register!(reg2_int_raw_status, Reg2IntRawStatus, RW, u32);
|
||||||
|
register_bit!(reg2_int_raw_status, decerr, 8);
|
||||||
|
register_bit!(reg2_int_raw_status, slverr, 7);
|
||||||
|
register_bit!(reg2_int_raw_status, errrd, 6);
|
||||||
|
register_bit!(reg2_int_raw_status, errrt, 5);
|
||||||
|
register_bit!(reg2_int_raw_status, errwd, 4);
|
||||||
|
register_bit!(reg2_int_raw_status, errwt, 3);
|
||||||
|
register_bit!(reg2_int_raw_status, parrd, 2);
|
||||||
|
register_bit!(reg2_int_raw_status, parrt, 1);
|
||||||
|
register_bit!(reg2_int_raw_status, ecntr, 0);
|
||||||
|
|
||||||
|
register!(reg2_int_clear, Reg2IntClear, RW, u32, 0);
|
||||||
|
register_bit!(reg2_int_clear, decerr, 8, WTC);
|
||||||
|
register_bit!(reg2_int_clear, slverr, 7, WTC);
|
||||||
|
register_bit!(reg2_int_clear, errrd, 6, WTC);
|
||||||
|
register_bit!(reg2_int_clear, errrt, 5, WTC);
|
||||||
|
register_bit!(reg2_int_clear, errwd, 4, WTC);
|
||||||
|
register_bit!(reg2_int_clear, errwt, 3, WTC);
|
||||||
|
register_bit!(reg2_int_clear, parrd, 2, WTC);
|
||||||
|
register_bit!(reg2_int_clear, parrt, 1, WTC);
|
||||||
|
register_bit!(reg2_int_clear, ecntr, 0, WTC);
|
||||||
|
|
||||||
|
register!(reg7_cache_sync, Reg7CacheSync, RW, u32);
|
||||||
|
register_bit!(reg7_cache_sync, c, 0);
|
||||||
|
|
||||||
|
register!(reg7_clean_index, Reg7CleanIndex, RW, u32);
|
||||||
|
register_bits!(reg7_clean_index, way, u8, 28, 30);
|
||||||
|
register_bits!(reg7_clean_index, index, u8, 5, 11);
|
||||||
|
register_bit!(reg7_clean_index, c, 0);
|
||||||
|
|
||||||
|
register!(reg7_clean_inv_index, Reg7CleanInvIndex, RW, u32);
|
||||||
|
register_bits!(reg7_clean_inv_index, way, u8, 28, 30);
|
||||||
|
register_bits!(reg7_clean_inv_index, index, u8, 5, 11);
|
||||||
|
register_bit!(reg7_clean_inv_index, c, 0);
|
||||||
|
|
||||||
|
register!(reg15_prefetch_ctrl, Reg15PrefetechCtrl, RW, u32);
|
||||||
|
register_bit!(reg15_prefetch_ctrl, double_linefill_en, 30);
|
||||||
|
register_bit!(reg15_prefetch_ctrl, instr_prefetch_en, 29);
|
||||||
|
register_bit!(reg15_prefetch_ctrl, data_prefetch_en, 28);
|
||||||
|
register_bit!(reg15_prefetch_ctrl, pref_drop_en, 24);
|
||||||
|
register_bit!(reg15_prefetch_ctrl, incr_double_linefill_en, 23);
|
||||||
|
register_bits!(reg15_prefetch_ctrl, prefetch_offset, u8, 0, 4);
|
||||||
|
|
@ -1,21 +1,26 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(llvm_asm, global_asm)]
|
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(const_fn)]
|
#![feature(global_asm)]
|
||||||
|
#![feature(asm)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
#![feature(const_fn_trait_bound)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod regs;
|
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
mod fpu;
|
||||||
|
pub mod l2c;
|
||||||
pub mod mmu;
|
pub mod mmu;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod sync_channel;
|
pub mod regs;
|
||||||
pub mod semaphore;
|
pub mod semaphore;
|
||||||
|
pub mod sync_channel;
|
||||||
mod uncached;
|
mod uncached;
|
||||||
mod fpu;
|
|
||||||
pub use uncached::UncachedSlice;
|
|
||||||
pub use fpu::enable_fpu;
|
pub use fpu::enable_fpu;
|
||||||
|
pub use uncached::UncachedSlice;
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
global_asm!(include_str!("exceptions.s"));
|
global_asm!(include_str!("exceptions.s"));
|
||||||
|
|
||||||
@ -34,3 +39,47 @@ pub fn notify_spin_lock() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Interrupt handler, which setup the stack and preserve registers before jumping to actual interrupt handler.
|
||||||
|
/// Registers r0-r12, PC, SP and CPSR are restored after the actual handler.
|
||||||
|
///
|
||||||
|
/// - `name` is the name of the interrupt, should be the same as the one defined in vector table.
|
||||||
|
/// - `name2` is the name for the actual handler, should be different from name.
|
||||||
|
/// - `stack0` is the stack for the interrupt handler when called from core0.
|
||||||
|
/// - `stack1` is the stack for the interrupt handler when called from core1.
|
||||||
|
/// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function
|
||||||
|
/// body.
|
||||||
|
///
|
||||||
|
/// Note that the interrupt handler would use the same stack as normal programs by default.
|
||||||
|
macro_rules! interrupt_handler {
|
||||||
|
($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => {
|
||||||
|
#[link_section = ".text.boot"]
|
||||||
|
#[no_mangle]
|
||||||
|
#[naked]
|
||||||
|
pub unsafe extern "C" fn $name() -> ! {
|
||||||
|
asm!(
|
||||||
|
// setup SP, depending on CPU 0 or 1
|
||||||
|
// and preserve registers
|
||||||
|
"sub lr, lr, #4",
|
||||||
|
"stmfd sp!, {{r0-r12, lr}}",
|
||||||
|
"mrc p15, #0, r0, c0, c0, #5",
|
||||||
|
concat!("movw r1, :lower16:", stringify!($stack0)),
|
||||||
|
concat!("movt r1, :upper16:", stringify!($stack0)),
|
||||||
|
"tst r0, #3",
|
||||||
|
concat!("movwne r1, :lower16:", stringify!($stack1)),
|
||||||
|
concat!("movtne r1, :upper16:", stringify!($stack1)),
|
||||||
|
"mov r0, sp",
|
||||||
|
"mov sp, r1",
|
||||||
|
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
|
||||||
|
concat!("bl ", stringify!($name2)),
|
||||||
|
"pop {{r0, r1}}",
|
||||||
|
"mov sp, r0",
|
||||||
|
"ldmfd sp!, {{r0-r12, pc}}^", // caret ^ : copy SPSR to the CPSR
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn $name2() $body
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -158,7 +158,7 @@ impl L1Table {
|
|||||||
global: true,
|
global: true,
|
||||||
shareable: true,
|
shareable: true,
|
||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0b101,
|
tex: 0b0,
|
||||||
domain: 0b1111,
|
domain: 0b1111,
|
||||||
exec: true,
|
exec: true,
|
||||||
cacheable: true,
|
cacheable: true,
|
||||||
@ -213,7 +213,7 @@ impl L1Table {
|
|||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0,
|
tex: 0,
|
||||||
domain: 0,
|
domain: 0,
|
||||||
exec: true,
|
exec: false,
|
||||||
cacheable: false,
|
cacheable: false,
|
||||||
bufferable: true,
|
bufferable: true,
|
||||||
});
|
});
|
||||||
@ -410,6 +410,7 @@ pub fn with_mmu<F: FnMut() -> !>(l1table: &L1Table, mut f: F) -> ! {
|
|||||||
.a(false)
|
.a(false)
|
||||||
.c(true)
|
.c(true)
|
||||||
.i(true)
|
.i(true)
|
||||||
|
.z(true)
|
||||||
.unaligned(true)
|
.unaligned(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::sync::atomic::{AtomicU32, Ordering};
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
|
use core::task::{Context, Poll};
|
||||||
|
use core::pin::Pin;
|
||||||
|
use core::future::Future;
|
||||||
use super::{
|
use super::{
|
||||||
spin_lock_yield, notify_spin_lock,
|
spin_lock_yield, notify_spin_lock,
|
||||||
asm::{dmb, enter_critical, exit_critical}
|
asm::{enter_critical, exit_critical}
|
||||||
};
|
};
|
||||||
|
|
||||||
const LOCKED: u32 = 1;
|
const LOCKED: u32 = 1;
|
||||||
@ -20,6 +23,23 @@ pub struct Mutex<T> {
|
|||||||
unsafe impl<T: Send> Sync for Mutex<T> {}
|
unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||||
unsafe impl<T: Send> Send for Mutex<T> {}
|
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||||
|
|
||||||
|
struct Fut<'a, T>(&'a Mutex<T>);
|
||||||
|
|
||||||
|
impl<'a, T> Future for Fut<'a, T> {
|
||||||
|
type Output = MutexGuard<'a, T>;
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
let irq = unsafe { enter_critical() };
|
||||||
|
if self.0.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||||
|
unsafe { exit_critical(irq) };
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Poll::Ready(MutexGuard { mutex: self.0, irq })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Mutex<T> {
|
impl<T> Mutex<T> {
|
||||||
/// Constructor, const-fn
|
/// Constructor, const-fn
|
||||||
pub const fn new(inner: T) -> Self {
|
pub const fn new(inner: T) -> Self {
|
||||||
@ -32,30 +52,31 @@ impl<T> Mutex<T> {
|
|||||||
/// Lock the Mutex, blocks when already locked
|
/// Lock the Mutex, blocks when already locked
|
||||||
pub fn lock(&self) -> MutexGuard<T> {
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
let mut irq = unsafe { enter_critical() };
|
let mut irq = unsafe { enter_critical() };
|
||||||
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
|
while self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||||
unsafe {
|
unsafe {
|
||||||
exit_critical(irq);
|
exit_critical(irq);
|
||||||
spin_lock_yield();
|
spin_lock_yield();
|
||||||
irq = enter_critical();
|
irq = enter_critical();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dmb();
|
|
||||||
MutexGuard { mutex: self, irq }
|
MutexGuard { mutex: self, irq }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn async_lock(&self) -> MutexGuard<'_, T> {
|
||||||
|
Fut(&self).await
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
||||||
let irq = unsafe { enter_critical() };
|
let irq = unsafe { enter_critical() };
|
||||||
if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
|
if self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||||
unsafe { exit_critical(irq) };
|
unsafe { exit_critical(irq) };
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
dmb();
|
|
||||||
Some(MutexGuard { mutex: self, irq })
|
Some(MutexGuard { mutex: self, irq })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(&self) {
|
fn unlock(&self) {
|
||||||
dmb();
|
|
||||||
self.locked.store(UNLOCKED, Ordering::Release);
|
self.locked.store(UNLOCKED, Ordering::Release);
|
||||||
|
|
||||||
notify_spin_lock();
|
notify_spin_lock();
|
||||||
|
@ -2,6 +2,7 @@ use libregister::{
|
|||||||
register_bit, register_bits,
|
register_bit, register_bits,
|
||||||
RegisterR, RegisterW, RegisterRW,
|
RegisterR, RegisterW, RegisterRW,
|
||||||
};
|
};
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
macro_rules! def_reg_r {
|
macro_rules! def_reg_r {
|
||||||
($name:tt, $type: ty, $asm_instr:tt) => {
|
($name:tt, $type: ty, $asm_instr:tt) => {
|
||||||
@ -11,7 +12,7 @@ macro_rules! def_reg_r {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn read(&self) -> Self::R {
|
fn read(&self) -> Self::R {
|
||||||
let mut value: u32;
|
let mut value: u32;
|
||||||
unsafe { llvm_asm!($asm_instr : "=r" (value) ::: "volatile") }
|
unsafe { asm!($asm_instr, lateout(reg) value) }
|
||||||
value.into()
|
value.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +27,7 @@ macro_rules! def_reg_w {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, value: Self::W) {
|
fn write(&mut self, value: Self::W) {
|
||||||
let value: u32 = value.into();
|
let value: u32 = value.into();
|
||||||
unsafe { llvm_asm!($asm_instr :: "r" (value) :: "volatile") }
|
unsafe { asm!($asm_instr, in(reg) value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -71,29 +72,29 @@ macro_rules! wrap_reg {
|
|||||||
|
|
||||||
/// Stack Pointer
|
/// Stack Pointer
|
||||||
pub struct SP;
|
pub struct SP;
|
||||||
def_reg_r!(SP, u32, "mov $0, sp");
|
def_reg_r!(SP, u32, "mov {}, sp");
|
||||||
def_reg_w!(SP, u32, "mov sp, $0");
|
def_reg_w!(SP, u32, "mov sp, {}");
|
||||||
|
|
||||||
/// Link register (function call return address)
|
/// Link register (function call return address)
|
||||||
pub struct LR;
|
pub struct LR;
|
||||||
def_reg_r!(LR, u32, "mov $0, lr");
|
def_reg_r!(LR, u32, "mov {}, lr");
|
||||||
def_reg_w!(LR, u32, "mov lr, $0");
|
def_reg_w!(LR, u32, "mov lr, {}");
|
||||||
|
|
||||||
pub struct VBAR;
|
pub struct VBAR;
|
||||||
def_reg_r!(VBAR, u32, "mrc p15, 0, $0, c12, c0, 0");
|
def_reg_r!(VBAR, u32, "mrc p15, 0, {}, c12, c0, 0");
|
||||||
def_reg_w!(VBAR, u32, "mcr p15, 0, $0, c12, c0, 0");
|
def_reg_w!(VBAR, u32, "mcr p15, 0, {}, c12, c0, 0");
|
||||||
|
|
||||||
pub struct MVBAR;
|
pub struct MVBAR;
|
||||||
def_reg_r!(MVBAR, u32, "mrc p15, 0, $0, c12, c0, 1");
|
def_reg_r!(MVBAR, u32, "mrc p15, 0, {}, c12, c0, 1");
|
||||||
def_reg_w!(MVBAR, u32, "mcr p15, 0, $0, c12, c0, 1");
|
def_reg_w!(MVBAR, u32, "mcr p15, 0, {}, c12, c0, 1");
|
||||||
|
|
||||||
pub struct HVBAR;
|
pub struct HVBAR;
|
||||||
def_reg_r!(HVBAR, u32, "mrc p15, 4, $0, c12, c0, 0");
|
def_reg_r!(HVBAR, u32, "mrc p15, 4, {}, c12, c0, 0");
|
||||||
def_reg_w!(HVBAR, u32, "mcr p15, 4, $0, c12, c0, 0");
|
def_reg_w!(HVBAR, u32, "mcr p15, 4, {}, c12, c0, 0");
|
||||||
|
|
||||||
/// Multiprocess Affinity Register
|
/// Multiprocess Affinity Register
|
||||||
pub struct MPIDR;
|
pub struct MPIDR;
|
||||||
def_reg_r!(MPIDR, mpidr::Read, "mrc p15, 0, $0, c0, c0, 5");
|
def_reg_r!(MPIDR, mpidr::Read, "mrc p15, 0, {}, c0, c0, 5");
|
||||||
wrap_reg!(mpidr);
|
wrap_reg!(mpidr);
|
||||||
register_bits!(mpidr,
|
register_bits!(mpidr,
|
||||||
/// CPU core index
|
/// CPU core index
|
||||||
@ -106,15 +107,15 @@ register_bit!(mpidr,
|
|||||||
u, 30);
|
u, 30);
|
||||||
|
|
||||||
pub struct DFAR;
|
pub struct DFAR;
|
||||||
def_reg_r!(DFAR, u32, "mrc p15, 0, $0, c6, c0, 0");
|
def_reg_r!(DFAR, u32, "mrc p15, 0, {}, c6, c0, 0");
|
||||||
|
|
||||||
pub struct DFSR;
|
pub struct DFSR;
|
||||||
def_reg_r!(DFSR, u32, "mrc p15, 0, $0, c5, c0, 0");
|
def_reg_r!(DFSR, u32, "mrc p15, 0, {}, c5, c0, 0");
|
||||||
|
|
||||||
pub struct SCTLR;
|
pub struct SCTLR;
|
||||||
wrap_reg!(sctlr);
|
wrap_reg!(sctlr);
|
||||||
def_reg_r!(SCTLR, sctlr::Read, "mrc p15, 0, $0, c1, c0, 0");
|
def_reg_r!(SCTLR, sctlr::Read, "mrc p15, 0, {}, c1, c0, 0");
|
||||||
def_reg_w!(SCTLR, sctlr::Write, "mcr p15, 0, $0, c1, c0, 0");
|
def_reg_w!(SCTLR, sctlr::Write, "mcr p15, 0, {}, c1, c0, 0");
|
||||||
register_bit!(sctlr,
|
register_bit!(sctlr,
|
||||||
/// Enables MMU
|
/// Enables MMU
|
||||||
m, 0);
|
m, 0);
|
||||||
@ -147,8 +148,8 @@ register_bit!(sctlr,
|
|||||||
/// Auxiliary Control Register
|
/// Auxiliary Control Register
|
||||||
pub struct ACTLR;
|
pub struct ACTLR;
|
||||||
wrap_reg!(actlr);
|
wrap_reg!(actlr);
|
||||||
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, $0, c1, c0, 1");
|
def_reg_r!(ACTLR, actlr::Read, "mrc p15, 0, {}, c1, c0, 1");
|
||||||
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, $0, c1, c0, 1");
|
def_reg_w!(ACTLR, actlr::Write, "mcr p15, 0, {}, c1, c0, 1");
|
||||||
// SMP bit
|
// SMP bit
|
||||||
register_bit!(actlr, parity_on, 9);
|
register_bit!(actlr, parity_on, 9);
|
||||||
register_bit!(actlr, alloc_one_way, 8);
|
register_bit!(actlr, alloc_one_way, 8);
|
||||||
@ -156,6 +157,8 @@ register_bit!(actlr, excl, 7);
|
|||||||
register_bit!(actlr, smp, 6);
|
register_bit!(actlr, smp, 6);
|
||||||
register_bit!(actlr, write_full_line_of_zeros, 3);
|
register_bit!(actlr, write_full_line_of_zeros, 3);
|
||||||
register_bit!(actlr, l1_prefetch_enable, 2);
|
register_bit!(actlr, l1_prefetch_enable, 2);
|
||||||
|
// L2 cache prefetch hint, in UG585 section 3.4.8
|
||||||
|
register_bit!(actlr, l2_prefetch_enable, 1);
|
||||||
// Cache/TLB maintenance broadcast
|
// Cache/TLB maintenance broadcast
|
||||||
register_bit!(actlr, fw, 0);
|
register_bit!(actlr, fw, 0);
|
||||||
|
|
||||||
@ -171,23 +174,27 @@ impl RegisterRW for ACTLR {
|
|||||||
|
|
||||||
impl ACTLR {
|
impl ACTLR {
|
||||||
pub fn enable_smp(&mut self) {
|
pub fn enable_smp(&mut self) {
|
||||||
self.modify(|_, w| w.smp(true).fw(true));
|
self.modify(|_, w| w.smp(true).fw(true).alloc_one_way(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_prefetch(&mut self) {
|
||||||
|
self.modify(|_, w| w.l1_prefetch_enable(true).l2_prefetch_enable(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Domain Access Control Register
|
/// Domain Access Control Register
|
||||||
pub struct DACR;
|
pub struct DACR;
|
||||||
def_reg_r!(DACR, u32, "mrc p15, 0, $0, c3, c0, 0");
|
def_reg_r!(DACR, u32, "mrc p15, 0, {}, c3, c0, 0");
|
||||||
def_reg_w!(DACR, u32, "mcr p15, 0, $0, c3, c0, 0");
|
def_reg_w!(DACR, u32, "mcr p15, 0, {}, c3, c0, 0");
|
||||||
|
|
||||||
/// Translation Table Base Register 0
|
/// Translation Table Base Register 0
|
||||||
pub struct TTBR0;
|
pub struct TTBR0;
|
||||||
/// Translation Table Base Register 1
|
/// Translation Table Base Register 1
|
||||||
pub struct TTBR1;
|
pub struct TTBR1;
|
||||||
def_reg_r!(TTBR0, ttbr::Read, "mrc p15, 0, $0, c2, c0, 0");
|
def_reg_r!(TTBR0, ttbr::Read, "mrc p15, 0, {}, c2, c0, 0");
|
||||||
def_reg_w!(TTBR0, ttbr::Write, "mcr p15, 0, $0, c2, c0, 0");
|
def_reg_w!(TTBR0, ttbr::Write, "mcr p15, 0, {}, c2, c0, 0");
|
||||||
def_reg_r!(TTBR1, ttbr::Read, "mrc p15, 0, $0, c2, c0, 1");
|
def_reg_r!(TTBR1, ttbr::Read, "mrc p15, 0, {}, c2, c0, 1");
|
||||||
def_reg_w!(TTBR1, ttbr::Write, "mcr p15, 0, $0, c2, c0, 1");
|
def_reg_w!(TTBR1, ttbr::Write, "mcr p15, 0, {}, c2, c0, 1");
|
||||||
wrap_reg!(ttbr);
|
wrap_reg!(ttbr);
|
||||||
register_bits!(ttbr, table_base, u32, 14, 31);
|
register_bits!(ttbr, table_base, u32, 14, 31);
|
||||||
register_bit!(ttbr, irgn0, 6);
|
register_bit!(ttbr, irgn0, 6);
|
||||||
|
@ -12,7 +12,7 @@ pub struct Semaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Semaphore {
|
impl Semaphore {
|
||||||
pub fn new(value: i32, max: i32) -> Self {
|
pub const fn new(value: i32, max: i32) -> Self {
|
||||||
Semaphore { value: AtomicI32::new(value), max}
|
Semaphore { value: AtomicI32::new(value), max}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ impl Semaphore {
|
|||||||
loop {
|
loop {
|
||||||
let value = self.value.load(Ordering::Relaxed);
|
let value = self.value.load(Ordering::Relaxed);
|
||||||
if value > 0 {
|
if value > 0 {
|
||||||
if self.value.compare_and_swap(value, value - 1, Ordering::SeqCst) == value {
|
if self.value.compare_exchange_weak(value, value - 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -58,7 +58,7 @@ impl Semaphore {
|
|||||||
loop {
|
loop {
|
||||||
let value = self.value.load(Ordering::Relaxed);
|
let value = self.value.load(Ordering::Relaxed);
|
||||||
if value < self.max {
|
if value < self.max {
|
||||||
if self.value.compare_and_swap(value, value + 1, Ordering::SeqCst) == value {
|
if self.value.compare_exchange_weak(value, value + 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
|
||||||
notify_spin_lock();
|
notify_spin_lock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use core::{
|
use core::{
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
future::Future,
|
future::Future,
|
||||||
ptr::drop_in_place,
|
|
||||||
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
|
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
@ -38,7 +37,7 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
|||||||
notify_spin_lock();
|
notify_spin_lock();
|
||||||
if !prev.is_null() {
|
if !prev.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
drop_in_place(prev);
|
Box::from_raw(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -92,7 +91,7 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
|||||||
for v in self.list.iter() {
|
for v in self.list.iter() {
|
||||||
let original = v.swap(core::ptr::null_mut(), Ordering::Relaxed);
|
let original = v.swap(core::ptr::null_mut(), Ordering::Relaxed);
|
||||||
if !original.is_null() {
|
if !original.is_null() {
|
||||||
drop_in_place(original);
|
Box::from_raw(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,13 +172,15 @@ impl<'a, T> Iterator for Receiver<'a, T> where T: Clone {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
/// Macro for initializing the sync_channel with static buffer and indexes.
|
/// Macro for initializing the sync_channel with static buffer and indexes.
|
||||||
/// Note that this requires `#![feature(const_in_array_repeat_expressions)]`
|
|
||||||
macro_rules! sync_channel {
|
macro_rules! sync_channel {
|
||||||
($t: ty, $cap: expr) => {
|
($t: ty, $cap: expr) => {
|
||||||
{
|
{
|
||||||
use core::sync::atomic::{AtomicUsize, AtomicPtr};
|
use core::sync::atomic::{AtomicUsize, AtomicPtr};
|
||||||
use $crate::sync_channel::{Sender, Receiver};
|
use $crate::sync_channel::{Sender, Receiver};
|
||||||
static LIST: [AtomicPtr<$t>; $cap + 1] = [AtomicPtr::new(core::ptr::null_mut()); $cap + 1];
|
const fn new_atomic() -> AtomicPtr<$t> {
|
||||||
|
AtomicPtr::new(core::ptr::null_mut())
|
||||||
|
}
|
||||||
|
static LIST: [AtomicPtr<$t>; $cap + 1] = [const { new_atomic() }; $cap + 1];
|
||||||
static WRITE: AtomicUsize = AtomicUsize::new(0);
|
static WRITE: AtomicUsize = AtomicUsize::new(0);
|
||||||
static READ: AtomicUsize = AtomicUsize::new(0);
|
static READ: AtomicUsize = AtomicUsize::new(0);
|
||||||
(Sender::new(&LIST, &WRITE, &READ), Receiver::new(&LIST, &WRITE, &READ))
|
(Sender::new(&LIST, &WRITE, &READ), Receiver::new(&LIST, &WRITE, &READ))
|
||||||
|
@ -2,7 +2,7 @@ use core::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
mem::{align_of, size_of},
|
mem::{align_of, size_of},
|
||||||
};
|
};
|
||||||
use alloc::alloc::{dealloc, Layout, LayoutErr};
|
use alloc::alloc::{dealloc, Layout, LayoutError};
|
||||||
use crate::mmu::{L1_PAGE_SIZE, L1Table};
|
use crate::mmu::{L1_PAGE_SIZE, L1Table};
|
||||||
|
|
||||||
pub struct UncachedSlice<T: 'static> {
|
pub struct UncachedSlice<T: 'static> {
|
||||||
@ -12,7 +12,7 @@ pub struct UncachedSlice<T: 'static> {
|
|||||||
|
|
||||||
impl<T> UncachedSlice<T> {
|
impl<T> UncachedSlice<T> {
|
||||||
/// allocates in chunks of 1 MB
|
/// allocates in chunks of 1 MB
|
||||||
pub fn new<F: Fn() -> T>(len: usize, default: F) -> Result<Self, LayoutErr> {
|
pub fn new<F: Fn() -> T>(len: usize, default: F) -> Result<Self, LayoutError> {
|
||||||
// round to full pages
|
// round to full pages
|
||||||
let size = ((len * size_of::<T>() - 1) | (L1_PAGE_SIZE - 1)) + 1;
|
let size = ((len * size_of::<T>() - 1) | (L1_PAGE_SIZE - 1)) + 1;
|
||||||
let align = align_of::<T>()
|
let align = align_of::<T>()
|
||||||
@ -23,10 +23,11 @@ impl<T> UncachedSlice<T> {
|
|||||||
assert_eq!(start & (L1_PAGE_SIZE - 1), 0);
|
assert_eq!(start & (L1_PAGE_SIZE - 1), 0);
|
||||||
|
|
||||||
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
||||||
|
// non-shareable device
|
||||||
L1Table::get()
|
L1Table::get()
|
||||||
.update(page_start as *const (), |l1_section| {
|
.update(page_start as *const (), |l1_section| {
|
||||||
l1_section.tex = 0b100;
|
l1_section.tex = 0b10;
|
||||||
l1_section.cacheable = false;
|
l1_section.cacheable = true;
|
||||||
l1_section.bufferable = false;
|
l1_section.bufferable = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -30,8 +30,9 @@ pub trait RegisterRW: RegisterR + RegisterW {
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_common {
|
macro_rules! register_common {
|
||||||
($mod_name: ident, $struct_name: ident, $access: ty, $inner: ty) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, $access: ty, $inner: ty) => (
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
$(#[$outer])*
|
||||||
pub struct $struct_name {
|
pub struct $struct_name {
|
||||||
inner: $access,
|
inner: $access,
|
||||||
}
|
}
|
||||||
@ -52,7 +53,7 @@ macro_rules! register_common {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_r {
|
macro_rules! register_r {
|
||||||
($mod_name: ident, $struct_name: ident) => (
|
($mod_name: ident, $struct_name: ident) => (
|
||||||
impl libregister::RegisterR for $struct_name {
|
impl $crate::RegisterR for $struct_name {
|
||||||
type R = $mod_name::Read;
|
type R = $mod_name::Read;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -67,7 +68,7 @@ macro_rules! register_r {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_w {
|
macro_rules! register_w {
|
||||||
($mod_name: ident, $struct_name: ident) => (
|
($mod_name: ident, $struct_name: ident) => (
|
||||||
impl libregister::RegisterW for $struct_name {
|
impl $crate::RegisterW for $struct_name {
|
||||||
type W = $mod_name::Write;
|
type W = $mod_name::Write;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -88,7 +89,7 @@ macro_rules! register_w {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_rw {
|
macro_rules! register_rw {
|
||||||
($mod_name: ident, $struct_name: ident) => (
|
($mod_name: ident, $struct_name: ident) => (
|
||||||
impl libregister::RegisterRW for $struct_name {
|
impl $crate::RegisterRW for $struct_name {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -101,7 +102,7 @@ macro_rules! register_rw {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
($mod_name: ident, $struct_name: ident, $mask: expr) => (
|
($mod_name: ident, $struct_name: ident, $mask: expr) => (
|
||||||
impl libregister::RegisterRW for $struct_name {
|
impl $crate::RegisterRW for $struct_name {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -119,7 +120,7 @@ macro_rules! register_rw {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_vcell {
|
macro_rules! register_vcell {
|
||||||
($mod_name: ident, $struct_name: ident) => (
|
($mod_name: ident, $struct_name: ident) => (
|
||||||
impl libregister::RegisterR for $struct_name {
|
impl $crate::RegisterR for $struct_name {
|
||||||
type R = $mod_name::Read;
|
type R = $mod_name::Read;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -128,7 +129,7 @@ macro_rules! register_vcell {
|
|||||||
$mod_name::Read { inner }
|
$mod_name::Read { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl libregister::RegisterW for $struct_name {
|
impl $crate::RegisterW for $struct_name {
|
||||||
type W = $mod_name::Write;
|
type W = $mod_name::Write;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -141,7 +142,7 @@ macro_rules! register_vcell {
|
|||||||
self.inner.set(w.inner);
|
self.inner.set(w.inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl libregister::RegisterRW for $struct_name {
|
impl $crate::RegisterRW for $struct_name {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||||
let r = self.read();
|
let r = self.read();
|
||||||
@ -157,37 +158,37 @@ macro_rules! register_vcell {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register {
|
macro_rules! register {
|
||||||
// Define read-only register
|
// Define read-only register
|
||||||
($mod_name: ident, $struct_name: ident, RO, $inner: ty) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RO, $inner: ty) => (
|
||||||
libregister::register_common!($mod_name, $struct_name, libregister::RO<$inner>, $inner);
|
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, $crate::RO<$inner>, $inner);
|
||||||
libregister::register_r!($mod_name, $struct_name);
|
$crate::register_r!($mod_name, $struct_name);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Define write-only register
|
// Define write-only register
|
||||||
($mod_name: ident, $struct_name: ident, WO, $inner: ty) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, WO, $inner: ty) => (
|
||||||
libregister::register_common!($mod_name, $struct_name, volatile_register::WO<$inner>, $inner);
|
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::WO<$inner>, $inner);
|
||||||
libregister::register_w!($mod_name, $struct_name);
|
$crate::register_w!($mod_name, $struct_name);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Define read-write register
|
// Define read-write register
|
||||||
($mod_name: ident, $struct_name: ident, RW, $inner: ty) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RW, $inner: ty) => (
|
||||||
libregister::register_common!($mod_name, $struct_name, volatile_register::RW<$inner>, $inner);
|
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::RW<$inner>, $inner);
|
||||||
libregister::register_r!($mod_name, $struct_name);
|
$crate::register_r!($mod_name, $struct_name);
|
||||||
libregister::register_w!($mod_name, $struct_name);
|
$crate::register_w!($mod_name, $struct_name);
|
||||||
libregister::register_rw!($mod_name, $struct_name);
|
$crate::register_rw!($mod_name, $struct_name);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Define read-write register
|
// Define read-write register
|
||||||
($mod_name: ident, $struct_name: ident, VolatileCell, $inner: ty) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, VolatileCell, $inner: ty) => (
|
||||||
libregister::register_common!($mod_name, $struct_name, VolatileCell<$inner>, $inner);
|
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, VolatileCell<$inner>, $inner);
|
||||||
libregister::register_vcell!($mod_name, $struct_name);
|
$crate::register_vcell!($mod_name, $struct_name);
|
||||||
);
|
);
|
||||||
|
|
||||||
// Define read-write register with mask on write (for WTC mixed access.)
|
// Define read-write register with mask on write (for WTC mixed access.)
|
||||||
($mod_name: ident, $struct_name: ident, RW, $inner: ty, $mask: expr) => (
|
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RW, $inner: ty, $mask: expr) => (
|
||||||
libregister::register_common!($mod_name, $struct_name, volatile_register::RW<$inner>, $inner);
|
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::RW<$inner>, $inner);
|
||||||
libregister::register_r!($mod_name, $struct_name);
|
$crate::register_r!($mod_name, $struct_name);
|
||||||
libregister::register_w!($mod_name, $struct_name);
|
$crate::register_w!($mod_name, $struct_name);
|
||||||
libregister::register_rw!($mod_name, $struct_name, $mask);
|
$crate::register_rw!($mod_name, $struct_name, $mask);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,22 +2,29 @@
|
|||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
description = "Software support for running in the Zynq PS"
|
description = "Software support for running in the Zynq PS"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Astro <astro@spaceboyz.net>"]
|
authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706"]
|
||||||
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10"]
|
target_coraz7 = ["libboard_zynq/target_coraz7"]
|
||||||
|
target_ebaz4205 = ["libboard_zynq/target_ebaz4205"]
|
||||||
|
target_redpitaya = ["libboard_zynq/target_redpitaya"]
|
||||||
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc"]
|
||||||
panic_handler = []
|
panic_handler = []
|
||||||
dummy_irq_handler = []
|
dummy_irq_handler = []
|
||||||
|
dummy_fiq_handler = []
|
||||||
alloc_core = []
|
alloc_core = []
|
||||||
|
|
||||||
default = ["panic_handler", "dummy_irq_handler"]
|
default = ["panic_handler", "dummy_irq_handler", "dummy_fiq_handler"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r0 = "1"
|
r0 = "1"
|
||||||
compiler_builtins = "0.1"
|
compiler_builtins = "=0.1.49"
|
||||||
linked_list_allocator = { version = "0.8", default-features = false }
|
linked_list_allocator = { version = "0.8", default-features = false, features = ["const_mut_refs"] }
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
libboard_zynq = { path = "../libboard_zynq" }
|
libboard_zynq = { path = "../libboard_zynq" }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0" }
|
||||||
|
24
libsupport_zynq/build.rs
Normal file
24
libsupport_zynq/build.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
compile_memcpy();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_memcpy() {
|
||||||
|
use std::path::Path;
|
||||||
|
extern crate cc;
|
||||||
|
let cfg = &mut cc::Build::new();
|
||||||
|
cfg.compiler("clang");
|
||||||
|
cfg.no_default_flags(true);
|
||||||
|
cfg.warnings(false);
|
||||||
|
cfg.flag("--target=armv7-none-eabihf");
|
||||||
|
let sources = vec![
|
||||||
|
"memcpy.S",
|
||||||
|
];
|
||||||
|
let root = Path::new("src/asm");
|
||||||
|
for src in sources {
|
||||||
|
println!("cargo:rerun-if-changed={}", src);
|
||||||
|
cfg.file(root.join(src));
|
||||||
|
}
|
||||||
|
cfg.compile("memcpy");
|
||||||
|
}
|
||||||
|
|
@ -1,70 +0,0 @@
|
|||||||
use libregister::RegisterR;
|
|
||||||
use libcortex_a9::regs::{DFSR, MPIDR};
|
|
||||||
use libboard_zynq::{println, stdio};
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn UndefinedInstruction() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("UndefinedInstruction");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn SoftwareInterrupt() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("SoftwareInterrupt");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn PrefetchAbort() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("PrefetchAbort");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn DataAbort() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
|
|
||||||
println!("DataAbort on core {}", MPIDR.read().cpu_id());
|
|
||||||
println!("DFSR: {:03X}", DFSR.read());
|
|
||||||
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn ReservedException() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("ReservedException");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
#[cfg(feature = "dummy_irq_handler")]
|
|
||||||
pub unsafe extern "C" fn IRQ() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("IRQ");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
|
||||||
#[no_mangle]
|
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn FIQ() {
|
|
||||||
stdio::drop_uart();
|
|
||||||
println!("FIQ");
|
|
||||||
loop {}
|
|
||||||
}
|
|
626
libsupport_zynq/src/asm/memcpy.S
Normal file
626
libsupport_zynq/src/asm/memcpy.S
Normal file
@ -0,0 +1,626 @@
|
|||||||
|
/* Copyright (c) 2013, Linaro Limited
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Linaro Limited nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
This memcpy routine is optimised for Cortex-A15 cores and takes advantage
|
||||||
|
of VFP or NEON when built with the appropriate flags.
|
||||||
|
|
||||||
|
Assumptions:
|
||||||
|
|
||||||
|
ARMv6 (ARMv7-a if using Neon)
|
||||||
|
ARM state
|
||||||
|
Unaligned accesses
|
||||||
|
LDRD/STRD support unaligned word accesses
|
||||||
|
|
||||||
|
If compiled with GCC, this file should be enclosed within following
|
||||||
|
pre-processing check:
|
||||||
|
if defined (__ARM_ARCH_7A__) && defined (__ARM_FEATURE_UNALIGNED)
|
||||||
|
|
||||||
|
*/
|
||||||
|
.syntax unified
|
||||||
|
/* This implementation requires ARM state. */
|
||||||
|
.arm
|
||||||
|
|
||||||
|
#ifdef __ARM_NEON__
|
||||||
|
|
||||||
|
.fpu neon
|
||||||
|
.arch armv7-a
|
||||||
|
# define FRAME_SIZE 4
|
||||||
|
# define USE_VFP
|
||||||
|
# define USE_NEON
|
||||||
|
|
||||||
|
#elif !defined (__SOFTFP__)
|
||||||
|
|
||||||
|
.arch armv6
|
||||||
|
.fpu vfpv2
|
||||||
|
# define FRAME_SIZE 32
|
||||||
|
# define USE_VFP
|
||||||
|
|
||||||
|
#else
|
||||||
|
.arch armv6
|
||||||
|
# define FRAME_SIZE 32
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Old versions of GAS incorrectly implement the NEON align semantics. */
|
||||||
|
#ifdef BROKEN_ASM_NEON_ALIGN
|
||||||
|
#define ALIGN(addr, align) addr,:align
|
||||||
|
#else
|
||||||
|
#define ALIGN(addr, align) addr:align
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PC_OFFSET 8 /* PC pipeline compensation. */
|
||||||
|
#define INSN_SIZE 4
|
||||||
|
|
||||||
|
/* Call parameters. */
|
||||||
|
#define dstin r0
|
||||||
|
#define src r1
|
||||||
|
#define count r2
|
||||||
|
|
||||||
|
/* Locals. */
|
||||||
|
#define tmp1 r3
|
||||||
|
#define dst ip
|
||||||
|
#define tmp2 r10
|
||||||
|
|
||||||
|
#ifndef USE_NEON
|
||||||
|
/* For bulk copies using GP registers. */
|
||||||
|
#define A_l r2 /* Call-clobbered. */
|
||||||
|
#define A_h r3 /* Call-clobbered. */
|
||||||
|
#define B_l r4
|
||||||
|
#define B_h r5
|
||||||
|
#define C_l r6
|
||||||
|
#define C_h r7
|
||||||
|
#define D_l r8
|
||||||
|
#define D_h r9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Number of lines ahead to pre-fetch data. If you change this the code
|
||||||
|
below will need adjustment to compensate. */
|
||||||
|
|
||||||
|
#define prefetch_lines 5
|
||||||
|
|
||||||
|
#ifdef USE_VFP
|
||||||
|
.macro cpy_line_vfp vreg, base
|
||||||
|
vstr \vreg, [dst, #\base]
|
||||||
|
vldr \vreg, [src, #\base]
|
||||||
|
vstr d0, [dst, #\base + 8]
|
||||||
|
vldr d0, [src, #\base + 8]
|
||||||
|
vstr d1, [dst, #\base + 16]
|
||||||
|
vldr d1, [src, #\base + 16]
|
||||||
|
vstr d2, [dst, #\base + 24]
|
||||||
|
vldr d2, [src, #\base + 24]
|
||||||
|
vstr \vreg, [dst, #\base + 32]
|
||||||
|
vldr \vreg, [src, #\base + prefetch_lines * 64 - 32]
|
||||||
|
vstr d0, [dst, #\base + 40]
|
||||||
|
vldr d0, [src, #\base + 40]
|
||||||
|
vstr d1, [dst, #\base + 48]
|
||||||
|
vldr d1, [src, #\base + 48]
|
||||||
|
vstr d2, [dst, #\base + 56]
|
||||||
|
vldr d2, [src, #\base + 56]
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro cpy_tail_vfp vreg, base
|
||||||
|
vstr \vreg, [dst, #\base]
|
||||||
|
vldr \vreg, [src, #\base]
|
||||||
|
vstr d0, [dst, #\base + 8]
|
||||||
|
vldr d0, [src, #\base + 8]
|
||||||
|
vstr d1, [dst, #\base + 16]
|
||||||
|
vldr d1, [src, #\base + 16]
|
||||||
|
vstr d2, [dst, #\base + 24]
|
||||||
|
vldr d2, [src, #\base + 24]
|
||||||
|
vstr \vreg, [dst, #\base + 32]
|
||||||
|
vstr d0, [dst, #\base + 40]
|
||||||
|
vldr d0, [src, #\base + 40]
|
||||||
|
vstr d1, [dst, #\base + 48]
|
||||||
|
vldr d1, [src, #\base + 48]
|
||||||
|
vstr d2, [dst, #\base + 56]
|
||||||
|
vldr d2, [src, #\base + 56]
|
||||||
|
.endm
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.macro def_fn f p2align=0
|
||||||
|
.text
|
||||||
|
.p2align \p2align
|
||||||
|
.global \f
|
||||||
|
.type \f, %function
|
||||||
|
\f:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.global __aeabi_memcpy
|
||||||
|
.global __aeabi_memcpy4
|
||||||
|
.global __aeabi_memcpy8
|
||||||
|
.set __aeabi_memcpy, fast_memcpy
|
||||||
|
.set __aeabi_memcpy4, fast_memcpy
|
||||||
|
.set __aeabi_memcpy8, fast_memcpy
|
||||||
|
def_fn fast_memcpy p2align=6
|
||||||
|
|
||||||
|
mov dst, dstin /* Preserve dstin, we need to return it. */
|
||||||
|
cmp count, #64
|
||||||
|
bge .Lcpy_not_short
|
||||||
|
/* Deal with small copies quickly by dropping straight into the
|
||||||
|
exit block. */
|
||||||
|
|
||||||
|
.Ltail63unaligned:
|
||||||
|
#ifdef USE_NEON
|
||||||
|
and tmp1, count, #0x38
|
||||||
|
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||||
|
add pc, pc, tmp1
|
||||||
|
vld1.8 {d0}, [src]! /* 14 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 12 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 10 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 8 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 6 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 4 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
vld1.8 {d0}, [src]! /* 2 words to go. */
|
||||||
|
vst1.8 {d0}, [dst]!
|
||||||
|
|
||||||
|
tst count, #4
|
||||||
|
ldrne tmp1, [src], #4
|
||||||
|
strne tmp1, [dst], #4
|
||||||
|
#else
|
||||||
|
/* Copy up to 15 full words of data. May not be aligned. */
|
||||||
|
/* Cannot use VFP for unaligned data. */
|
||||||
|
and tmp1, count, #0x3c
|
||||||
|
add dst, dst, tmp1
|
||||||
|
add src, src, tmp1
|
||||||
|
rsb tmp1, tmp1, #(60 - PC_OFFSET/2 + INSN_SIZE/2)
|
||||||
|
/* Jump directly into the sequence below at the correct offset. */
|
||||||
|
add pc, pc, tmp1, lsl #1
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-60] /* 15 words to go. */
|
||||||
|
str tmp1, [dst, #-60]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-56] /* 14 words to go. */
|
||||||
|
str tmp1, [dst, #-56]
|
||||||
|
ldr tmp1, [src, #-52]
|
||||||
|
str tmp1, [dst, #-52]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-48] /* 12 words to go. */
|
||||||
|
str tmp1, [dst, #-48]
|
||||||
|
ldr tmp1, [src, #-44]
|
||||||
|
str tmp1, [dst, #-44]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-40] /* 10 words to go. */
|
||||||
|
str tmp1, [dst, #-40]
|
||||||
|
ldr tmp1, [src, #-36]
|
||||||
|
str tmp1, [dst, #-36]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-32] /* 8 words to go. */
|
||||||
|
str tmp1, [dst, #-32]
|
||||||
|
ldr tmp1, [src, #-28]
|
||||||
|
str tmp1, [dst, #-28]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-24] /* 6 words to go. */
|
||||||
|
str tmp1, [dst, #-24]
|
||||||
|
ldr tmp1, [src, #-20]
|
||||||
|
str tmp1, [dst, #-20]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-16] /* 4 words to go. */
|
||||||
|
str tmp1, [dst, #-16]
|
||||||
|
ldr tmp1, [src, #-12]
|
||||||
|
str tmp1, [dst, #-12]
|
||||||
|
|
||||||
|
ldr tmp1, [src, #-8] /* 2 words to go. */
|
||||||
|
str tmp1, [dst, #-8]
|
||||||
|
ldr tmp1, [src, #-4]
|
||||||
|
str tmp1, [dst, #-4]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lsls count, count, #31
|
||||||
|
ldrhcs tmp1, [src], #2
|
||||||
|
ldrbne src, [src] /* Src is dead, use as a scratch. */
|
||||||
|
strhcs tmp1, [dst], #2
|
||||||
|
strbne src, [dst]
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.Lcpy_not_short:
|
||||||
|
/* At least 64 bytes to copy, but don't know the alignment yet. */
|
||||||
|
str tmp2, [sp, #-FRAME_SIZE]!
|
||||||
|
and tmp2, src, #7
|
||||||
|
and tmp1, dst, #7
|
||||||
|
cmp tmp1, tmp2
|
||||||
|
bne .Lcpy_notaligned
|
||||||
|
|
||||||
|
#ifdef USE_VFP
|
||||||
|
/* Magic dust alert! Force VFP on Cortex-A9. Experiments show
|
||||||
|
that the FP pipeline is much better at streaming loads and
|
||||||
|
stores. This is outside the critical loop. */
|
||||||
|
vmov.f32 s0, s0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* SRC and DST have the same mutual 32-bit alignment, but we may
|
||||||
|
still need to pre-copy some bytes to get to natural alignment.
|
||||||
|
We bring DST into full 64-bit alignment. */
|
||||||
|
lsls tmp2, dst, #29
|
||||||
|
beq 1f
|
||||||
|
rsbs tmp2, tmp2, #0
|
||||||
|
sub count, count, tmp2, lsr #29
|
||||||
|
ldrmi tmp1, [src], #4
|
||||||
|
strmi tmp1, [dst], #4
|
||||||
|
lsls tmp2, tmp2, #2
|
||||||
|
ldrhcs tmp1, [src], #2
|
||||||
|
ldrbne tmp2, [src], #1
|
||||||
|
strhcs tmp1, [dst], #2
|
||||||
|
strbne tmp2, [dst], #1
|
||||||
|
|
||||||
|
1:
|
||||||
|
subs tmp2, count, #64 /* Use tmp2 for count. */
|
||||||
|
blt .Ltail63aligned
|
||||||
|
|
||||||
|
cmp tmp2, #512
|
||||||
|
bge .Lcpy_body_long
|
||||||
|
|
||||||
|
.Lcpy_body_medium: /* Count in tmp2. */
|
||||||
|
#ifdef USE_VFP
|
||||||
|
1:
|
||||||
|
vldr d0, [src, #0]
|
||||||
|
subs tmp2, tmp2, #64
|
||||||
|
vldr d1, [src, #8]
|
||||||
|
vstr d0, [dst, #0]
|
||||||
|
vldr d0, [src, #16]
|
||||||
|
vstr d1, [dst, #8]
|
||||||
|
vldr d1, [src, #24]
|
||||||
|
vstr d0, [dst, #16]
|
||||||
|
vldr d0, [src, #32]
|
||||||
|
vstr d1, [dst, #24]
|
||||||
|
vldr d1, [src, #40]
|
||||||
|
vstr d0, [dst, #32]
|
||||||
|
vldr d0, [src, #48]
|
||||||
|
vstr d1, [dst, #40]
|
||||||
|
vldr d1, [src, #56]
|
||||||
|
vstr d0, [dst, #48]
|
||||||
|
add src, src, #64
|
||||||
|
vstr d1, [dst, #56]
|
||||||
|
add dst, dst, #64
|
||||||
|
bge 1b
|
||||||
|
tst tmp2, #0x3f
|
||||||
|
beq .Ldone
|
||||||
|
|
||||||
|
.Ltail63aligned: /* Count in tmp2. */
|
||||||
|
and tmp1, tmp2, #0x38
|
||||||
|
add dst, dst, tmp1
|
||||||
|
add src, src, tmp1
|
||||||
|
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||||
|
add pc, pc, tmp1
|
||||||
|
|
||||||
|
vldr d0, [src, #-56] /* 14 words to go. */
|
||||||
|
vstr d0, [dst, #-56]
|
||||||
|
vldr d0, [src, #-48] /* 12 words to go. */
|
||||||
|
vstr d0, [dst, #-48]
|
||||||
|
vldr d0, [src, #-40] /* 10 words to go. */
|
||||||
|
vstr d0, [dst, #-40]
|
||||||
|
vldr d0, [src, #-32] /* 8 words to go. */
|
||||||
|
vstr d0, [dst, #-32]
|
||||||
|
vldr d0, [src, #-24] /* 6 words to go. */
|
||||||
|
vstr d0, [dst, #-24]
|
||||||
|
vldr d0, [src, #-16] /* 4 words to go. */
|
||||||
|
vstr d0, [dst, #-16]
|
||||||
|
vldr d0, [src, #-8] /* 2 words to go. */
|
||||||
|
vstr d0, [dst, #-8]
|
||||||
|
#else
|
||||||
|
sub src, src, #8
|
||||||
|
sub dst, dst, #8
|
||||||
|
1:
|
||||||
|
ldrd A_l, A_h, [src, #8]
|
||||||
|
strd A_l, A_h, [dst, #8]
|
||||||
|
ldrd A_l, A_h, [src, #16]
|
||||||
|
strd A_l, A_h, [dst, #16]
|
||||||
|
ldrd A_l, A_h, [src, #24]
|
||||||
|
strd A_l, A_h, [dst, #24]
|
||||||
|
ldrd A_l, A_h, [src, #32]
|
||||||
|
strd A_l, A_h, [dst, #32]
|
||||||
|
ldrd A_l, A_h, [src, #40]
|
||||||
|
strd A_l, A_h, [dst, #40]
|
||||||
|
ldrd A_l, A_h, [src, #48]
|
||||||
|
strd A_l, A_h, [dst, #48]
|
||||||
|
ldrd A_l, A_h, [src, #56]
|
||||||
|
strd A_l, A_h, [dst, #56]
|
||||||
|
ldrd A_l, A_h, [src, #64]!
|
||||||
|
strd A_l, A_h, [dst, #64]!
|
||||||
|
subs tmp2, tmp2, #64
|
||||||
|
bge 1b
|
||||||
|
tst tmp2, #0x3f
|
||||||
|
bne 1f
|
||||||
|
ldr tmp2,[sp], #FRAME_SIZE
|
||||||
|
bx lr
|
||||||
|
1:
|
||||||
|
add src, src, #8
|
||||||
|
add dst, dst, #8
|
||||||
|
|
||||||
|
.Ltail63aligned: /* Count in tmp2. */
|
||||||
|
/* Copy up to 7 d-words of data. Similar to Ltail63unaligned, but
|
||||||
|
we know that the src and dest are 32-bit aligned so we can use
|
||||||
|
LDRD/STRD to improve efficiency. */
|
||||||
|
/* TMP2 is now negative, but we don't care about that. The bottom
|
||||||
|
six bits still tell us how many bytes are left to copy. */
|
||||||
|
|
||||||
|
and tmp1, tmp2, #0x38
|
||||||
|
add dst, dst, tmp1
|
||||||
|
add src, src, tmp1
|
||||||
|
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
|
||||||
|
add pc, pc, tmp1
|
||||||
|
ldrd A_l, A_h, [src, #-56] /* 14 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-56]
|
||||||
|
ldrd A_l, A_h, [src, #-48] /* 12 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-48]
|
||||||
|
ldrd A_l, A_h, [src, #-40] /* 10 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-40]
|
||||||
|
ldrd A_l, A_h, [src, #-32] /* 8 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-32]
|
||||||
|
ldrd A_l, A_h, [src, #-24] /* 6 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-24]
|
||||||
|
ldrd A_l, A_h, [src, #-16] /* 4 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-16]
|
||||||
|
ldrd A_l, A_h, [src, #-8] /* 2 words to go. */
|
||||||
|
strd A_l, A_h, [dst, #-8]
|
||||||
|
|
||||||
|
#endif
|
||||||
|
tst tmp2, #4
|
||||||
|
ldrne tmp1, [src], #4
|
||||||
|
strne tmp1, [dst], #4
|
||||||
|
lsls tmp2, tmp2, #31 /* Count (tmp2) now dead. */
|
||||||
|
ldrhcs tmp1, [src], #2
|
||||||
|
ldrbne tmp2, [src]
|
||||||
|
strhcs tmp1, [dst], #2
|
||||||
|
strbne tmp2, [dst]
|
||||||
|
|
||||||
|
.Ldone:
|
||||||
|
ldr tmp2, [sp], #FRAME_SIZE
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.Lcpy_body_long: /* Count in tmp2. */
|
||||||
|
|
||||||
|
/* Long copy. We know that there's at least (prefetch_lines * 64)
|
||||||
|
bytes to go. */
|
||||||
|
#ifdef USE_VFP
|
||||||
|
/* Don't use PLD. Instead, read some data in advance of the current
|
||||||
|
copy position into a register. This should act like a PLD
|
||||||
|
operation but we won't have to repeat the transfer. */
|
||||||
|
|
||||||
|
vldr d3, [src, #0]
|
||||||
|
vldr d4, [src, #64]
|
||||||
|
vldr d5, [src, #128]
|
||||||
|
vldr d6, [src, #192]
|
||||||
|
vldr d7, [src, #256]
|
||||||
|
|
||||||
|
vldr d0, [src, #8]
|
||||||
|
vldr d1, [src, #16]
|
||||||
|
vldr d2, [src, #24]
|
||||||
|
add src, src, #32
|
||||||
|
|
||||||
|
subs tmp2, tmp2, #prefetch_lines * 64 * 2
|
||||||
|
blt 2f
|
||||||
|
1:
|
||||||
|
cpy_line_vfp d3, 0
|
||||||
|
cpy_line_vfp d4, 64
|
||||||
|
cpy_line_vfp d5, 128
|
||||||
|
add dst, dst, #3 * 64
|
||||||
|
add src, src, #3 * 64
|
||||||
|
cpy_line_vfp d6, 0
|
||||||
|
cpy_line_vfp d7, 64
|
||||||
|
add dst, dst, #2 * 64
|
||||||
|
add src, src, #2 * 64
|
||||||
|
subs tmp2, tmp2, #prefetch_lines * 64
|
||||||
|
bge 1b
|
||||||
|
|
||||||
|
2:
|
||||||
|
cpy_tail_vfp d3, 0
|
||||||
|
cpy_tail_vfp d4, 64
|
||||||
|
cpy_tail_vfp d5, 128
|
||||||
|
add src, src, #3 * 64
|
||||||
|
add dst, dst, #3 * 64
|
||||||
|
cpy_tail_vfp d6, 0
|
||||||
|
vstr d7, [dst, #64]
|
||||||
|
vldr d7, [src, #64]
|
||||||
|
vstr d0, [dst, #64 + 8]
|
||||||
|
vldr d0, [src, #64 + 8]
|
||||||
|
vstr d1, [dst, #64 + 16]
|
||||||
|
vldr d1, [src, #64 + 16]
|
||||||
|
vstr d2, [dst, #64 + 24]
|
||||||
|
vldr d2, [src, #64 + 24]
|
||||||
|
vstr d7, [dst, #64 + 32]
|
||||||
|
add src, src, #96
|
||||||
|
vstr d0, [dst, #64 + 40]
|
||||||
|
vstr d1, [dst, #64 + 48]
|
||||||
|
vstr d2, [dst, #64 + 56]
|
||||||
|
add dst, dst, #128
|
||||||
|
add tmp2, tmp2, #prefetch_lines * 64
|
||||||
|
b .Lcpy_body_medium
|
||||||
|
#else
|
||||||
|
/* Long copy. Use an SMS style loop to maximize the I/O
|
||||||
|
bandwidth of the core. We don't have enough spare registers
|
||||||
|
to synthesise prefetching, so use PLD operations. */
|
||||||
|
/* Pre-bias src and dst. */
|
||||||
|
sub src, src, #8
|
||||||
|
sub dst, dst, #8
|
||||||
|
pld [src, #8]
|
||||||
|
pld [src, #72]
|
||||||
|
subs tmp2, tmp2, #64
|
||||||
|
pld [src, #136]
|
||||||
|
ldrd A_l, A_h, [src, #8]
|
||||||
|
strd B_l, B_h, [sp, #8]
|
||||||
|
ldrd B_l, B_h, [src, #16]
|
||||||
|
strd C_l, C_h, [sp, #16]
|
||||||
|
ldrd C_l, C_h, [src, #24]
|
||||||
|
strd D_l, D_h, [sp, #24]
|
||||||
|
pld [src, #200]
|
||||||
|
ldrd D_l, D_h, [src, #32]!
|
||||||
|
b 1f
|
||||||
|
.p2align 6
|
||||||
|
2:
|
||||||
|
pld [src, #232]
|
||||||
|
strd A_l, A_h, [dst, #40]
|
||||||
|
ldrd A_l, A_h, [src, #40]
|
||||||
|
strd B_l, B_h, [dst, #48]
|
||||||
|
ldrd B_l, B_h, [src, #48]
|
||||||
|
strd C_l, C_h, [dst, #56]
|
||||||
|
ldrd C_l, C_h, [src, #56]
|
||||||
|
strd D_l, D_h, [dst, #64]!
|
||||||
|
ldrd D_l, D_h, [src, #64]!
|
||||||
|
subs tmp2, tmp2, #64
|
||||||
|
1:
|
||||||
|
strd A_l, A_h, [dst, #8]
|
||||||
|
ldrd A_l, A_h, [src, #8]
|
||||||
|
strd B_l, B_h, [dst, #16]
|
||||||
|
ldrd B_l, B_h, [src, #16]
|
||||||
|
strd C_l, C_h, [dst, #24]
|
||||||
|
ldrd C_l, C_h, [src, #24]
|
||||||
|
strd D_l, D_h, [dst, #32]
|
||||||
|
ldrd D_l, D_h, [src, #32]
|
||||||
|
bcs 2b
|
||||||
|
/* Save the remaining bytes and restore the callee-saved regs. */
|
||||||
|
strd A_l, A_h, [dst, #40]
|
||||||
|
add src, src, #40
|
||||||
|
strd B_l, B_h, [dst, #48]
|
||||||
|
ldrd B_l, B_h, [sp, #8]
|
||||||
|
strd C_l, C_h, [dst, #56]
|
||||||
|
ldrd C_l, C_h, [sp, #16]
|
||||||
|
strd D_l, D_h, [dst, #64]
|
||||||
|
ldrd D_l, D_h, [sp, #24]
|
||||||
|
add dst, dst, #72
|
||||||
|
tst tmp2, #0x3f
|
||||||
|
bne .Ltail63aligned
|
||||||
|
ldr tmp2, [sp], #FRAME_SIZE
|
||||||
|
bx lr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.Lcpy_notaligned:
|
||||||
|
pld [src]
|
||||||
|
pld [src, #64]
|
||||||
|
/* There's at least 64 bytes to copy, but there is no mutual
|
||||||
|
alignment. */
|
||||||
|
/* Bring DST to 64-bit alignment. */
|
||||||
|
lsls tmp2, dst, #29
|
||||||
|
pld [src, #(2 * 64)]
|
||||||
|
beq 1f
|
||||||
|
rsbs tmp2, tmp2, #0
|
||||||
|
sub count, count, tmp2, lsr #29
|
||||||
|
ldrmi tmp1, [src], #4
|
||||||
|
strmi tmp1, [dst], #4
|
||||||
|
lsls tmp2, tmp2, #2
|
||||||
|
ldrbne tmp1, [src], #1
|
||||||
|
ldrhcs tmp2, [src], #2
|
||||||
|
strbne tmp1, [dst], #1
|
||||||
|
strhcs tmp2, [dst], #2
|
||||||
|
1:
|
||||||
|
pld [src, #(3 * 64)]
|
||||||
|
subs count, count, #64
|
||||||
|
ldrmi tmp2, [sp], #FRAME_SIZE
|
||||||
|
bmi .Ltail63unaligned
|
||||||
|
pld [src, #(4 * 64)]
|
||||||
|
|
||||||
|
#ifdef USE_NEON
|
||||||
|
vld1.8 {d0-d3}, [src]!
|
||||||
|
vld1.8 {d4-d7}, [src]!
|
||||||
|
subs count, count, #64
|
||||||
|
bmi 2f
|
||||||
|
1:
|
||||||
|
pld [src, #(4 * 64)]
|
||||||
|
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
|
||||||
|
vld1.8 {d0-d3}, [src]!
|
||||||
|
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
|
||||||
|
vld1.8 {d4-d7}, [src]!
|
||||||
|
subs count, count, #64
|
||||||
|
bpl 1b
|
||||||
|
2:
|
||||||
|
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
|
||||||
|
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
|
||||||
|
ands count, count, #0x3f
|
||||||
|
#else
|
||||||
|
/* Use an SMS style loop to maximize the I/O bandwidth. */
|
||||||
|
sub src, src, #4
|
||||||
|
sub dst, dst, #8
|
||||||
|
subs tmp2, count, #64 /* Use tmp2 for count. */
|
||||||
|
ldr A_l, [src, #4]
|
||||||
|
ldr A_h, [src, #8]
|
||||||
|
strd B_l, B_h, [sp, #8]
|
||||||
|
ldr B_l, [src, #12]
|
||||||
|
ldr B_h, [src, #16]
|
||||||
|
strd C_l, C_h, [sp, #16]
|
||||||
|
ldr C_l, [src, #20]
|
||||||
|
ldr C_h, [src, #24]
|
||||||
|
strd D_l, D_h, [sp, #24]
|
||||||
|
ldr D_l, [src, #28]
|
||||||
|
ldr D_h, [src, #32]!
|
||||||
|
b 1f
|
||||||
|
.p2align 6
|
||||||
|
2:
|
||||||
|
pld [src, #(5 * 64) - (32 - 4)]
|
||||||
|
strd A_l, A_h, [dst, #40]
|
||||||
|
ldr A_l, [src, #36]
|
||||||
|
ldr A_h, [src, #40]
|
||||||
|
strd B_l, B_h, [dst, #48]
|
||||||
|
ldr B_l, [src, #44]
|
||||||
|
ldr B_h, [src, #48]
|
||||||
|
strd C_l, C_h, [dst, #56]
|
||||||
|
ldr C_l, [src, #52]
|
||||||
|
ldr C_h, [src, #56]
|
||||||
|
strd D_l, D_h, [dst, #64]!
|
||||||
|
ldr D_l, [src, #60]
|
||||||
|
ldr D_h, [src, #64]!
|
||||||
|
subs tmp2, tmp2, #64
|
||||||
|
1:
|
||||||
|
strd A_l, A_h, [dst, #8]
|
||||||
|
ldr A_l, [src, #4]
|
||||||
|
ldr A_h, [src, #8]
|
||||||
|
strd B_l, B_h, [dst, #16]
|
||||||
|
ldr B_l, [src, #12]
|
||||||
|
ldr B_h, [src, #16]
|
||||||
|
strd C_l, C_h, [dst, #24]
|
||||||
|
ldr C_l, [src, #20]
|
||||||
|
ldr C_h, [src, #24]
|
||||||
|
strd D_l, D_h, [dst, #32]
|
||||||
|
ldr D_l, [src, #28]
|
||||||
|
ldr D_h, [src, #32]
|
||||||
|
bcs 2b
|
||||||
|
|
||||||
|
/* Save the remaining bytes and restore the callee-saved regs. */
|
||||||
|
strd A_l, A_h, [dst, #40]
|
||||||
|
add src, src, #36
|
||||||
|
strd B_l, B_h, [dst, #48]
|
||||||
|
ldrd B_l, B_h, [sp, #8]
|
||||||
|
strd C_l, C_h, [dst, #56]
|
||||||
|
ldrd C_l, C_h, [sp, #16]
|
||||||
|
strd D_l, D_h, [dst, #64]
|
||||||
|
ldrd D_l, D_h, [sp, #24]
|
||||||
|
add dst, dst, #72
|
||||||
|
ands count, tmp2, #0x3f
|
||||||
|
#endif
|
||||||
|
ldr tmp2, [sp], #FRAME_SIZE
|
||||||
|
bne .Ltail63unaligned
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.size memcpy, . - memcpy
|
||||||
|
|
@ -1,10 +1,11 @@
|
|||||||
use r0::zero_bss;
|
use r0::zero_bss;
|
||||||
use core::ptr::write_volatile;
|
use core::ptr::write_volatile;
|
||||||
|
use core::arch::asm;
|
||||||
use libregister::{
|
use libregister::{
|
||||||
VolatileCell,
|
VolatileCell,
|
||||||
RegisterR, RegisterW, RegisterRW,
|
RegisterR, RegisterRW,
|
||||||
};
|
};
|
||||||
use libcortex_a9::{asm, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock};
|
use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock, enable_fpu, interrupt_handler};
|
||||||
use libboard_zynq::{slcr, mpcore};
|
use libboard_zynq::{slcr, mpcore};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -18,32 +19,28 @@ extern "C" {
|
|||||||
|
|
||||||
static mut CORE1_ENABLED: VolatileCell<bool> = VolatileCell::new(false);
|
static mut CORE1_ENABLED: VolatileCell<bool> = VolatileCell::new(false);
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
interrupt_handler!(Reset, reset_irq, __stack0_start, __stack1_start, {
|
||||||
#[no_mangle]
|
// no need to setup stack here, as we already did when entering the handler
|
||||||
#[naked]
|
|
||||||
pub unsafe extern "C" fn Reset() -> ! {
|
|
||||||
match MPIDR.read().cpu_id() {
|
match MPIDR.read().cpu_id() {
|
||||||
0 => {
|
0 => {
|
||||||
SP.write(&mut __stack0_start as *mut _ as u32);
|
|
||||||
boot_core0();
|
boot_core0();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
while !CORE1_ENABLED.get() {
|
while !CORE1_ENABLED.get() {
|
||||||
spin_lock_yield();
|
spin_lock_yield();
|
||||||
}
|
}
|
||||||
SP.write(&mut __stack1_start as *mut _ as u32);
|
|
||||||
boot_core1();
|
boot_core1();
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
#[naked]
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn boot_core0() -> ! {
|
unsafe extern "C" fn boot_core0() -> ! {
|
||||||
l1_cache_init();
|
l1_cache_init();
|
||||||
|
|
||||||
let mpcore = mpcore::RegisterBlock::new();
|
enable_fpu();
|
||||||
|
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||||
mpcore.scu_invalidate.invalidate_all_cores();
|
mpcore.scu_invalidate.invalidate_all_cores();
|
||||||
|
|
||||||
zero_bss(&mut __bss_start, &mut __bss_end);
|
zero_bss(&mut __bss_start, &mut __bss_end);
|
||||||
@ -53,31 +50,34 @@ unsafe fn boot_core0() -> ! {
|
|||||||
mmu::with_mmu(mmu_table, || {
|
mmu::with_mmu(mmu_table, || {
|
||||||
mpcore.scu_control.start();
|
mpcore.scu_control.start();
|
||||||
ACTLR.enable_smp();
|
ACTLR.enable_smp();
|
||||||
|
ACTLR.enable_prefetch();
|
||||||
// TODO: Barriers reqd when core1 is not yet starting?
|
// TODO: Barriers reqd when core1 is not yet starting?
|
||||||
asm::dmb();
|
asm::dmb();
|
||||||
asm::dsb();
|
asm::dsb();
|
||||||
|
|
||||||
|
asm::enable_fiq();
|
||||||
asm::enable_irq();
|
asm::enable_irq();
|
||||||
main_core0();
|
main_core0();
|
||||||
panic!("return from main");
|
panic!("return from main");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn boot_core1() -> ! {
|
unsafe extern "C" fn boot_core1() -> ! {
|
||||||
l1_cache_init();
|
l1_cache_init();
|
||||||
|
|
||||||
let mpcore = mpcore::RegisterBlock::new();
|
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||||
mpcore.scu_invalidate.invalidate_core1();
|
mpcore.scu_invalidate.invalidate_core1();
|
||||||
|
|
||||||
let mmu_table = mmu::L1Table::get();
|
let mmu_table = mmu::L1Table::get();
|
||||||
mmu::with_mmu(mmu_table, || {
|
mmu::with_mmu(mmu_table, || {
|
||||||
ACTLR.enable_smp();
|
ACTLR.enable_smp();
|
||||||
|
ACTLR.enable_prefetch();
|
||||||
// TODO: Barriers reqd when core1 is not yet starting?
|
// TODO: Barriers reqd when core1 is not yet starting?
|
||||||
asm::dmb();
|
asm::dmb();
|
||||||
asm::dsb();
|
asm::dsb();
|
||||||
|
|
||||||
|
asm::enable_fiq();
|
||||||
asm::enable_irq();
|
asm::enable_irq();
|
||||||
main_core1();
|
main_core1();
|
||||||
panic!("return from main_core1");
|
panic!("return from main_core1");
|
||||||
@ -101,7 +101,7 @@ fn l1_cache_init() {
|
|||||||
// for all of the L1 data cache rather than a (previously
|
// for all of the L1 data cache rather than a (previously
|
||||||
// unspecified) combination of one cache set and one cache
|
// unspecified) combination of one cache set and one cache
|
||||||
// way.
|
// way.
|
||||||
dciall();
|
dciall_l1();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Core1 {
|
pub struct Core1 {
|
||||||
@ -131,12 +131,13 @@ impl Core1 {
|
|||||||
unsafe {
|
unsafe {
|
||||||
CORE1_ENABLED.set(true);
|
CORE1_ENABLED.set(true);
|
||||||
}
|
}
|
||||||
// Ensure values have been written to cache
|
|
||||||
asm::dmb();
|
|
||||||
// Flush cache-line
|
// Flush cache-line
|
||||||
cache::dccmvac(unsafe { &CORE1_ENABLED } as *const _ as usize);
|
cache::dcc(unsafe { &CORE1_ENABLED });
|
||||||
if sdram {
|
if sdram {
|
||||||
cache::dccmvac(0);
|
cache::dccmvac(0);
|
||||||
|
asm::dsb();
|
||||||
|
l2c::l2_cache_clean(0);
|
||||||
|
l2c::l2_cache_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
// wake up core1
|
// wake up core1
|
||||||
|
55
libsupport_zynq/src/exception_vectors.rs
Normal file
55
libsupport_zynq/src/exception_vectors.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use libregister::{RegisterR, RegisterW};
|
||||||
|
use libcortex_a9::{regs::{DFSR, MPIDR, VBAR}, interrupt_handler};
|
||||||
|
use libboard_zynq::{println, stdio};
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub fn set_vector_table(base_addr: u32){
|
||||||
|
VBAR.write(base_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt_handler!(UndefinedInstruction, undefined_instruction, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("UndefinedInstruction");
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_handler!(SoftwareInterrupt, software_interrupt, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("SoftwareInterrupt");
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_handler!(PrefetchAbort, prefetch_abort, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("PrefetchAbort");
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_handler!(DataAbort, data_abort, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
|
||||||
|
println!("DataAbort on core {}", MPIDR.read().cpu_id());
|
||||||
|
println!("DFSR: {:03X}", DFSR.read());
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
interrupt_handler!(ReservedException, reserved_exception, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("ReservedException");
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(feature = "dummy_irq_handler")]
|
||||||
|
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("IRQ");
|
||||||
|
loop {}
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(feature = "dummy_fiq_handler")]
|
||||||
|
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
|
||||||
|
stdio::drop_uart();
|
||||||
|
println!("FIQ");
|
||||||
|
loop {}
|
||||||
|
});
|
@ -1,14 +1,17 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#![feature(naked_functions)]
|
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
#![feature(global_asm)]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
pub extern crate alloc;
|
pub extern crate alloc;
|
||||||
pub extern crate compiler_builtins;
|
pub extern crate compiler_builtins;
|
||||||
|
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
mod abort;
|
pub mod exception_vectors;
|
||||||
#[cfg(feature = "panic_handler")]
|
#[cfg(feature = "panic_handler")]
|
||||||
mod panic;
|
mod panic;
|
||||||
pub mod ram;
|
pub mod ram;
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use libboard_zynq::{print, println};
|
use libboard_zynq::{print, println};
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
use libboard_zynq::error_led::ErrorLED;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
@ -13,6 +15,10 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
|||||||
} else {
|
} else {
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
|
{
|
||||||
|
let mut err_led = ErrorLED::error_led();
|
||||||
|
err_led.toggle(true);
|
||||||
|
}
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,10 @@ unsafe impl GlobalAlloc for CortexA9Alloc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
if cfg!(not(feature = "alloc_core")) || MPIDR.read().cpu_id() == 0 {
|
if cfg!(not(feature = "alloc_core"))
|
||||||
|
|| ((&__heap0_start as *const usize as usize <= ptr as usize)
|
||||||
|
&& ((ptr as usize) < &__heap0_end as *const usize as usize))
|
||||||
|
{
|
||||||
&self.0
|
&self.0
|
||||||
} else {
|
} else {
|
||||||
&self.1
|
&self.1
|
||||||
|
20
openocd/common.cfg
Normal file
20
openocd/common.cfg
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
set XC7_JSHUTDOWN 0x0d
|
||||||
|
set XC7_JPROGRAM 0x0b
|
||||||
|
set XC7_JSTART 0x0c
|
||||||
|
set XC7_BYPASS 0x3f
|
||||||
|
|
||||||
|
proc xc7_program {tap} {
|
||||||
|
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
|
||||||
|
irscan $tap $XC7_JSHUTDOWN
|
||||||
|
irscan $tap $XC7_JPROGRAM
|
||||||
|
runtest 60000
|
||||||
|
#JSTART prevents this from working...
|
||||||
|
#irscan $tap $XC7_JSTART
|
||||||
|
runtest 2000
|
||||||
|
irscan $tap $XC7_BYPASS
|
||||||
|
runtest 2000
|
||||||
|
}
|
||||||
|
|
||||||
|
pld device virtex2 zynq.tap 1
|
||||||
|
init
|
||||||
|
xc7_program zynq.tap
|
@ -5,37 +5,15 @@ set PL_TAPID 0x13722093
|
|||||||
set SMP 1
|
set SMP 1
|
||||||
|
|
||||||
source ./zynq-7000.cfg
|
source ./zynq-7000.cfg
|
||||||
source ./xilinx-tcl.cfg
|
|
||||||
source ./ps7_init.tcl
|
|
||||||
|
|
||||||
reset_config srst_only srst_push_pull
|
reset_config srst_only srst_push_pull
|
||||||
|
|
||||||
set XC7_JSHUTDOWN 0x0d
|
source ./common.cfg
|
||||||
set XC7_JPROGRAM 0x0b
|
|
||||||
set XC7_JSTART 0x0c
|
|
||||||
set XC7_BYPASS 0x3f
|
|
||||||
|
|
||||||
proc xc7_program {tap} {
|
reset halt
|
||||||
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
|
|
||||||
irscan $tap $XC7_JSHUTDOWN
|
|
||||||
irscan $tap $XC7_JPROGRAM
|
|
||||||
runtest 60000
|
|
||||||
#JSTART prevents this from working...
|
|
||||||
#irscan $tap $XC7_JSTART
|
|
||||||
runtest 2000
|
|
||||||
irscan $tap $XC7_BYPASS
|
|
||||||
runtest 2000
|
|
||||||
}
|
|
||||||
|
|
||||||
pld device virtex2 zynq.tap 1
|
|
||||||
init
|
|
||||||
xc7_program zynq.tap
|
|
||||||
|
|
||||||
xilinx_ps7_init
|
|
||||||
|
|
||||||
# Disable MMU
|
# Disable MMU
|
||||||
targets $_TARGETNAME_1
|
targets $_TARGETNAME_1
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
targets $_TARGETNAME_0
|
targets $_TARGETNAME_0
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
|
|
||||||
|
12
openocd/digilent-hs2.cfg
Normal file
12
openocd/digilent-hs2.cfg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# this is the original file from OpenOCD, but with ftdi_device_desc
|
||||||
|
# removed because some cables don't have it programmed.
|
||||||
|
|
||||||
|
# this supports JTAG-HS2 (and apparently Nexys4 as well)
|
||||||
|
|
||||||
|
adapter driver ftdi
|
||||||
|
ftdi_vid_pid 0x0403 0x6014
|
||||||
|
|
||||||
|
ftdi_channel 0
|
||||||
|
ftdi_layout_init 0x00e8 0x60eb
|
||||||
|
|
||||||
|
reset_config none
|
@ -1,18 +0,0 @@
|
|||||||
#
|
|
||||||
# Digilent JTAG-SMT2-NC
|
|
||||||
#
|
|
||||||
# http://store.digilentinc.com/jtag-smt2-nc-surface-mount-programming-module/
|
|
||||||
# https://reference.digilentinc.com/_media/jtag_smt2nc/jtag-smt2-nc_rm.pdf
|
|
||||||
#
|
|
||||||
# Based on reference sheet (above) and Xilinx KCU105 schematics
|
|
||||||
# https://www.xilinx.com/products/boards-and-kits/kcu105.html#documentation
|
|
||||||
#
|
|
||||||
# Note that the digilent_jtag_smt2 layout does not work and hangs while
|
|
||||||
# the ftdi_device_desc from digilent_hs2 is wrong.
|
|
||||||
|
|
||||||
interface ftdi
|
|
||||||
ftdi_device_desc "Digilent USB Device"
|
|
||||||
ftdi_vid_pid 0x0403 0x6014
|
|
||||||
ftdi_channel 0
|
|
||||||
ftdi_layout_init 0x00e8 0x60eb
|
|
||||||
ftdi_layout_signal nSRST -data 0x2000
|
|
33
openocd/ebaz4205.cfg
Normal file
33
openocd/ebaz4205.cfg
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# The contents of this file are partially dependend on
|
||||||
|
# the adapter that you have. Please modify accordingly.
|
||||||
|
adapter driver ftdi
|
||||||
|
ftdi vid_pid 0x0403 0x6010
|
||||||
|
ftdi channel 0
|
||||||
|
# Every pin set as high impedance except TCK, TDI, TDO and TMS
|
||||||
|
ftdi layout_init 0x0088 0x008b
|
||||||
|
|
||||||
|
# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)
|
||||||
|
# This choice is arbitrary. Use other GPIO pin if desired.
|
||||||
|
ftdi layout_signal nSRST -data 0x0020 -oe 0x0020
|
||||||
|
|
||||||
|
transport select jtag
|
||||||
|
adapter speed 10000
|
||||||
|
|
||||||
|
set PL_TAPID 0x13722093
|
||||||
|
set SMP 1
|
||||||
|
|
||||||
|
source ./zynq-7000.cfg
|
||||||
|
|
||||||
|
reset_config srst_only srst_open_drain
|
||||||
|
adapter srst pulse_width 250
|
||||||
|
adapter srst delay 400
|
||||||
|
|
||||||
|
source ./common.cfg
|
||||||
|
|
||||||
|
reset halt
|
||||||
|
|
||||||
|
# Disable MMU
|
||||||
|
targets $_TARGETNAME_1
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
|
targets $_TARGETNAME_0
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
@ -1,28 +0,0 @@
|
|||||||
def zynq-connect
|
|
||||||
target remote :3333
|
|
||||||
end
|
|
||||||
|
|
||||||
def zynq-fsbl-restart
|
|
||||||
mon xilinx_ps7_init
|
|
||||||
end
|
|
||||||
|
|
||||||
def zynq-restart
|
|
||||||
mon xilinx_ps7_init
|
|
||||||
load
|
|
||||||
end
|
|
||||||
|
|
||||||
# easily typed shortcuts
|
|
||||||
# device connect
|
|
||||||
def dc
|
|
||||||
zynq-connect
|
|
||||||
end
|
|
||||||
# device restart
|
|
||||||
def dr
|
|
||||||
zynq-restart
|
|
||||||
end
|
|
||||||
|
|
||||||
def dfr
|
|
||||||
zynq-fsbl-restart
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
28
openocd/kasli_soc.cfg
Normal file
28
openocd/kasli_soc.cfg
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
adapter driver ftdi
|
||||||
|
ftdi_device_desc "Quad RS232-HS"
|
||||||
|
ftdi_vid_pid 0x0403 0x6011
|
||||||
|
ftdi_channel 0
|
||||||
|
# some GPIOs need to be set, otherwise the FTDI chip craps out for some reason.
|
||||||
|
ftdi_layout_init 0x0098 0x008b
|
||||||
|
transport select jtag
|
||||||
|
adapter speed 1000
|
||||||
|
|
||||||
|
set PL_TAPID 0x1372c093
|
||||||
|
set SMP 1
|
||||||
|
|
||||||
|
source ./zynq-7000.cfg
|
||||||
|
|
||||||
|
ftdi_layout_signal nSRST -oe 0x0004
|
||||||
|
reset_config srst_only srst_open_drain
|
||||||
|
adapter srst pulse_width 250
|
||||||
|
adapter srst delay 400
|
||||||
|
|
||||||
|
source ./common.cfg
|
||||||
|
|
||||||
|
reset halt
|
||||||
|
|
||||||
|
# Disable MMU
|
||||||
|
targets $_TARGETNAME_1
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
|
targets $_TARGETNAME_0
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
@ -1,771 +0,0 @@
|
|||||||
proc ps7_pll_init_data_3_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
|
||||||
mask_write 0XF8000100 0x0007F000 0x00028000
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
|
||||||
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
|
||||||
mask_write 0XF8000104 0x0007F000 0x00020000
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000002
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
|
||||||
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
|
||||||
mask_write 0XF8000108 0x0007F000 0x0001E000
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000004
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_clock_init_data_3_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
|
||||||
mask_write 0XF8000138 0x00000011 0x00000001
|
|
||||||
mask_write 0XF8000140 0x03F03F71 0x00100801
|
|
||||||
mask_write 0XF800014C 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000150 0x00003F33 0x00001401
|
|
||||||
mask_write 0XF8000154 0x00003F33 0x00001402
|
|
||||||
mask_write 0XF8000168 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000170 0x03F03F30 0x00200500
|
|
||||||
mask_write 0XF80001C4 0x00000001 0x00000001
|
|
||||||
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_ddr_init_data_3_0 {} {
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
|
||||||
mask_write 0XF8006004 0x0007FFFF 0x00001081
|
|
||||||
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
|
||||||
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
|
||||||
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
|
||||||
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
|
||||||
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
|
||||||
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
|
||||||
mask_write 0XF8006020 0x7FDFFFFC 0x270872D0
|
|
||||||
mask_write 0XF8006024 0x0FFFFFC3 0x00000000
|
|
||||||
mask_write 0XF8006028 0x00003FFF 0x00002007
|
|
||||||
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
|
||||||
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
|
||||||
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
|
||||||
mask_write 0XF8006038 0x00000003 0x00000000
|
|
||||||
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
|
||||||
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
|
||||||
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
|
||||||
mask_write 0XF8006048 0x0003F03F 0x0003C008
|
|
||||||
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
|
||||||
mask_write 0XF8006058 0x00010000 0x00000000
|
|
||||||
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
|
||||||
mask_write 0XF8006060 0x000017FF 0x0000003E
|
|
||||||
mask_write 0XF8006064 0x00021FE0 0x00020000
|
|
||||||
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
|
||||||
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
|
||||||
mask_write 0XF8006078 0x03FFFFFF 0x00466111
|
|
||||||
mask_write 0XF800607C 0x000FFFFF 0x00032222
|
|
||||||
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
|
||||||
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
|
||||||
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
|
||||||
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
|
||||||
mask_write 0XF80060B4 0x00000200 0x00000200
|
|
||||||
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
|
||||||
mask_write 0XF80060C4 0x00000003 0x00000000
|
|
||||||
mask_write 0XF80060C8 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF80060DC 0x00000001 0x00000000
|
|
||||||
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
|
||||||
mask_write 0XF80060F4 0x0000000F 0x00000008
|
|
||||||
mask_write 0XF8006114 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF8006118 0x7FFFFFCF 0x40000001
|
|
||||||
mask_write 0XF800611C 0x7FFFFFCF 0x40000001
|
|
||||||
mask_write 0XF8006120 0x7FFFFFCF 0x40000001
|
|
||||||
mask_write 0XF8006124 0x7FFFFFCF 0x40000001
|
|
||||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
|
||||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
|
||||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
|
||||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
|
||||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
|
||||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
|
||||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
|
||||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
|
||||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006190 0x6FFFFEFE 0x00040080
|
|
||||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
|
||||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF8006208 0x000703FF 0x000003FF
|
|
||||||
mask_write 0XF800620C 0x000703FF 0x000003FF
|
|
||||||
mask_write 0XF8006210 0x000703FF 0x000003FF
|
|
||||||
mask_write 0XF8006214 0x000703FF 0x000003FF
|
|
||||||
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF80062A8 0x00000FF5 0x00000000
|
|
||||||
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
|
||||||
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
|
||||||
mask_poll 0XF8000B74 0x00002000
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
|
||||||
mask_poll 0XF8006054 0x00000007
|
|
||||||
}
|
|
||||||
proc ps7_mio_init_data_3_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
|
||||||
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B6C 0x00007FFF 0x00000209
|
|
||||||
mask_write 0XF8000B70 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000B70 0x00000021 0x00000020
|
|
||||||
mask_write 0XF8000B70 0x07FEFFFF 0x00000823
|
|
||||||
mask_write 0XF8000700 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000704 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000708 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800070C 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000710 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000714 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000718 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800071C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000720 0x00003FFF 0x00000700
|
|
||||||
mask_write 0XF8000724 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000728 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800072C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000730 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000734 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000738 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800073C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000740 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000744 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000748 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF800074C 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000750 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000754 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000758 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800075C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000760 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000764 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000768 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800076C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000770 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000774 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000778 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800077C 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000780 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000784 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000788 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800078C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000790 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000794 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000798 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800079C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B8 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007BC 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
|
||||||
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
|
||||||
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF8000830 0x003F003F 0x002F002E
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_peripherals_init_data_3_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B48 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B4C 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B50 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B54 0x00000180 0x00000180
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
mask_write 0XE0001034 0x000000FF 0x00000006
|
|
||||||
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
|
||||||
mask_write 0XE0001000 0x000001FF 0x00000017
|
|
||||||
mask_write 0XE0001004 0x000003FF 0x00000020
|
|
||||||
mask_write 0XE000D000 0x00080000 0x00080000
|
|
||||||
mask_write 0XF8007000 0x20000000 0x00000000
|
|
||||||
}
|
|
||||||
proc ps7_post_config_3_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000900 0x0000000F 0x0000000F
|
|
||||||
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_debug_3_0 {} {
|
|
||||||
mwr -force 0XF8898FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8899FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8809FB0 0xC5ACCE55
|
|
||||||
}
|
|
||||||
proc ps7_pll_init_data_2_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
|
||||||
mask_write 0XF8000100 0x0007F000 0x00028000
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
|
||||||
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
|
||||||
mask_write 0XF8000104 0x0007F000 0x00020000
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000002
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
|
||||||
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
|
||||||
mask_write 0XF8000108 0x0007F000 0x0001E000
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000004
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_clock_init_data_2_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
|
||||||
mask_write 0XF8000138 0x00000011 0x00000001
|
|
||||||
mask_write 0XF8000140 0x03F03F71 0x00100801
|
|
||||||
mask_write 0XF800014C 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000150 0x00003F33 0x00001401
|
|
||||||
mask_write 0XF8000154 0x00003F33 0x00001402
|
|
||||||
mask_write 0XF8000168 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000170 0x03F03F30 0x00200500
|
|
||||||
mask_write 0XF80001C4 0x00000001 0x00000001
|
|
||||||
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_ddr_init_data_2_0 {} {
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
|
||||||
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
|
|
||||||
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
|
||||||
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
|
||||||
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
|
||||||
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
|
||||||
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
|
||||||
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
|
||||||
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
|
|
||||||
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
|
|
||||||
mask_write 0XF8006028 0x00003FFF 0x00002007
|
|
||||||
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
|
||||||
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
|
||||||
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
|
||||||
mask_write 0XF8006038 0x00001FC3 0x00000000
|
|
||||||
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
|
||||||
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
|
||||||
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
|
||||||
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
|
|
||||||
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
|
||||||
mask_write 0XF8006058 0x0001FFFF 0x00000101
|
|
||||||
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
|
||||||
mask_write 0XF8006060 0x000017FF 0x0000003E
|
|
||||||
mask_write 0XF8006064 0x00021FE0 0x00020000
|
|
||||||
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
|
||||||
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
|
||||||
mask_write 0XF8006078 0x03FFFFFF 0x00466111
|
|
||||||
mask_write 0XF800607C 0x000FFFFF 0x00032222
|
|
||||||
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
|
|
||||||
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
|
||||||
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
|
||||||
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
|
||||||
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
|
||||||
mask_write 0XF80060B4 0x000007FF 0x00000200
|
|
||||||
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
|
||||||
mask_write 0XF80060C4 0x00000003 0x00000000
|
|
||||||
mask_write 0XF80060C8 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF80060DC 0x00000001 0x00000000
|
|
||||||
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
|
||||||
mask_write 0XF80060F4 0x0000000F 0x00000008
|
|
||||||
mask_write 0XF8006114 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
|
||||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
|
||||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
|
||||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
|
||||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
|
||||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
|
||||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
|
||||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
|
||||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
|
||||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
|
||||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF8006208 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF800620C 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006210 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006214 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF80062A8 0x00000FF7 0x00000000
|
|
||||||
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
|
||||||
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
|
||||||
mask_poll 0XF8000B74 0x00002000
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
|
||||||
mask_poll 0XF8006054 0x00000007
|
|
||||||
}
|
|
||||||
proc ps7_mio_init_data_2_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
|
||||||
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B6C 0x00007FFF 0x00000209
|
|
||||||
mask_write 0XF8000B70 0x00000021 0x00000021
|
|
||||||
mask_write 0XF8000B70 0x00000021 0x00000020
|
|
||||||
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
|
|
||||||
mask_write 0XF8000700 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000704 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000708 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800070C 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000710 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000714 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000718 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800071C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000720 0x00003FFF 0x00000700
|
|
||||||
mask_write 0XF8000724 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000728 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800072C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000730 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000734 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000738 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800073C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000740 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000744 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000748 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF800074C 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000750 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000754 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000758 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800075C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000760 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000764 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000768 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800076C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000770 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000774 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000778 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800077C 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000780 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000784 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000788 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800078C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000790 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000794 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000798 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800079C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B8 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007BC 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
|
||||||
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
|
||||||
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF8000830 0x003F003F 0x002F002E
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_peripherals_init_data_2_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B48 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B4C 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B50 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B54 0x00000180 0x00000180
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
mask_write 0XE0001034 0x000000FF 0x00000006
|
|
||||||
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
|
||||||
mask_write 0XE0001000 0x000001FF 0x00000017
|
|
||||||
mask_write 0XE0001004 0x00000FFF 0x00000020
|
|
||||||
mask_write 0XE000D000 0x00080000 0x00080000
|
|
||||||
mask_write 0XF8007000 0x20000000 0x00000000
|
|
||||||
}
|
|
||||||
proc ps7_post_config_2_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000900 0x0000000F 0x0000000F
|
|
||||||
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_debug_2_0 {} {
|
|
||||||
mwr -force 0XF8898FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8899FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8809FB0 0xC5ACCE55
|
|
||||||
}
|
|
||||||
proc ps7_pll_init_data_1_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000110 0x003FFFF0 0x000FA220
|
|
||||||
mask_write 0XF8000100 0x0007F000 0x00028000
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000001
|
|
||||||
mask_write 0XF8000100 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000120 0x1F003F30 0x1F000200
|
|
||||||
mask_write 0XF8000114 0x003FFFF0 0x0012C220
|
|
||||||
mask_write 0XF8000104 0x0007F000 0x00020000
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000104 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000002
|
|
||||||
mask_write 0XF8000104 0x00000010 0x00000000
|
|
||||||
mask_write 0XF8000124 0xFFF00003 0x0C200003
|
|
||||||
mask_write 0XF8000118 0x003FFFF0 0x001452C0
|
|
||||||
mask_write 0XF8000108 0x0007F000 0x0001E000
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000010
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000001
|
|
||||||
mask_write 0XF8000108 0x00000001 0x00000000
|
|
||||||
mask_poll 0XF800010C 0x00000004
|
|
||||||
mask_write 0XF8000108 0x00000010 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_clock_init_data_1_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000128 0x03F03F01 0x00700F01
|
|
||||||
mask_write 0XF8000138 0x00000011 0x00000001
|
|
||||||
mask_write 0XF8000140 0x03F03F71 0x00100801
|
|
||||||
mask_write 0XF800014C 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000150 0x00003F33 0x00001401
|
|
||||||
mask_write 0XF8000154 0x00003F33 0x00001402
|
|
||||||
mask_write 0XF8000168 0x00003F31 0x00000501
|
|
||||||
mask_write 0XF8000170 0x03F03F30 0x00200400
|
|
||||||
mask_write 0XF80001C4 0x00000001 0x00000001
|
|
||||||
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_ddr_init_data_1_0 {} {
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000080
|
|
||||||
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
|
|
||||||
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
|
|
||||||
mask_write 0XF800600C 0x03FFFFFF 0x02001001
|
|
||||||
mask_write 0XF8006010 0x03FFFFFF 0x00014001
|
|
||||||
mask_write 0XF8006014 0x001FFFFF 0x0004159B
|
|
||||||
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
|
|
||||||
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
|
|
||||||
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
|
|
||||||
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
|
|
||||||
mask_write 0XF8006028 0x00003FFF 0x00002007
|
|
||||||
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
|
|
||||||
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
|
|
||||||
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
|
|
||||||
mask_write 0XF8006038 0x00001FC3 0x00000000
|
|
||||||
mask_write 0XF800603C 0x000FFFFF 0x00000777
|
|
||||||
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
|
|
||||||
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
|
|
||||||
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
|
|
||||||
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
|
|
||||||
mask_write 0XF8006058 0x0001FFFF 0x00000101
|
|
||||||
mask_write 0XF800605C 0x0000FFFF 0x00005003
|
|
||||||
mask_write 0XF8006060 0x000017FF 0x0000003E
|
|
||||||
mask_write 0XF8006064 0x00021FE0 0x00020000
|
|
||||||
mask_write 0XF8006068 0x03FFFFFF 0x00284141
|
|
||||||
mask_write 0XF800606C 0x0000FFFF 0x00001610
|
|
||||||
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
|
|
||||||
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
|
|
||||||
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
|
|
||||||
mask_write 0XF80060AC 0x000001FF 0x000001FE
|
|
||||||
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
|
|
||||||
mask_write 0XF80060B4 0x000007FF 0x00000200
|
|
||||||
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
|
|
||||||
mask_write 0XF80060C4 0x00000003 0x00000000
|
|
||||||
mask_write 0XF80060C8 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF80060DC 0x00000001 0x00000000
|
|
||||||
mask_write 0XF80060F0 0x0000FFFF 0x00000000
|
|
||||||
mask_write 0XF80060F4 0x0000000F 0x00000008
|
|
||||||
mask_write 0XF8006114 0x000000FF 0x00000000
|
|
||||||
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
|
|
||||||
mask_write 0XF800612C 0x000FFFFF 0x00033C03
|
|
||||||
mask_write 0XF8006130 0x000FFFFF 0x00034003
|
|
||||||
mask_write 0XF8006134 0x000FFFFF 0x0002F400
|
|
||||||
mask_write 0XF8006138 0x000FFFFF 0x00030400
|
|
||||||
mask_write 0XF8006140 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006144 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006148 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF800614C 0x000FFFFF 0x00000035
|
|
||||||
mask_write 0XF8006154 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF8006158 0x000FFFFF 0x00000083
|
|
||||||
mask_write 0XF800615C 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006160 0x000FFFFF 0x00000080
|
|
||||||
mask_write 0XF8006168 0x001FFFFF 0x00000124
|
|
||||||
mask_write 0XF800616C 0x001FFFFF 0x00000125
|
|
||||||
mask_write 0XF8006170 0x001FFFFF 0x00000112
|
|
||||||
mask_write 0XF8006174 0x001FFFFF 0x00000116
|
|
||||||
mask_write 0XF800617C 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006180 0x000FFFFF 0x000000C3
|
|
||||||
mask_write 0XF8006184 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006188 0x000FFFFF 0x000000C0
|
|
||||||
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
|
|
||||||
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
|
|
||||||
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF8006208 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF800620C 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006210 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006214 0x000F03FF 0x000803FF
|
|
||||||
mask_write 0XF8006218 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF800621C 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006220 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF8006224 0x000F03FF 0x000003FF
|
|
||||||
mask_write 0XF80062A8 0x00000FF7 0x00000000
|
|
||||||
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0XF80062B0 0x003FFFFF 0x00005125
|
|
||||||
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
|
|
||||||
mask_poll 0XF8000B74 0x00002000
|
|
||||||
mask_write 0XF8006000 0x0001FFFF 0x00000081
|
|
||||||
mask_poll 0XF8006054 0x00000007
|
|
||||||
}
|
|
||||||
proc ps7_mio_init_data_1_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B40 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B44 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B48 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B4C 0x00000FFF 0x00000672
|
|
||||||
mask_write 0XF8000B50 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B54 0x00000FFF 0x00000674
|
|
||||||
mask_write 0XF8000B58 0x00000FFF 0x00000600
|
|
||||||
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
|
|
||||||
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
|
|
||||||
mask_write 0XF8000B6C 0x000073FF 0x00000209
|
|
||||||
mask_write 0XF8000B70 0x00000021 0x00000021
|
|
||||||
mask_write 0XF8000B70 0x00000021 0x00000020
|
|
||||||
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
|
|
||||||
mask_write 0XF8000700 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000704 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000708 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800070C 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000710 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000714 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF8000718 0x00003FFF 0x00000702
|
|
||||||
mask_write 0XF800071C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000720 0x00003FFF 0x00000700
|
|
||||||
mask_write 0XF8000724 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000728 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800072C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000730 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000734 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000738 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF800073C 0x00003FFF 0x00000600
|
|
||||||
mask_write 0XF8000740 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000744 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000748 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF800074C 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000750 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000754 0x00003FFF 0x00000302
|
|
||||||
mask_write 0XF8000758 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800075C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000760 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000764 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000768 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF800076C 0x00003FFF 0x00000303
|
|
||||||
mask_write 0XF8000770 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000774 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000778 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800077C 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000780 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000784 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000788 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800078C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000790 0x00003FFF 0x00000305
|
|
||||||
mask_write 0XF8000794 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF8000798 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF800079C 0x00003FFF 0x00000304
|
|
||||||
mask_write 0XF80007A0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007A8 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007AC 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B0 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B4 0x00003FFF 0x00000380
|
|
||||||
mask_write 0XF80007B8 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007BC 0x00003F01 0x00000201
|
|
||||||
mask_write 0XF80007C0 0x00003FFF 0x000002E0
|
|
||||||
mask_write 0XF80007C4 0x00003FFF 0x000002E1
|
|
||||||
mask_write 0XF80007C8 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007CC 0x00003FFF 0x00000200
|
|
||||||
mask_write 0XF80007D0 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF80007D4 0x00003FFF 0x00000280
|
|
||||||
mask_write 0XF8000830 0x003F003F 0x002F002E
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_peripherals_init_data_1_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000B48 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B4C 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B50 0x00000180 0x00000180
|
|
||||||
mask_write 0XF8000B54 0x00000180 0x00000180
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
mask_write 0XE0001034 0x000000FF 0x00000006
|
|
||||||
mask_write 0XE0001018 0x0000FFFF 0x0000003E
|
|
||||||
mask_write 0XE0001000 0x000001FF 0x00000017
|
|
||||||
mask_write 0XE0001004 0x00000FFF 0x00000020
|
|
||||||
mask_write 0XE000D000 0x00080000 0x00080000
|
|
||||||
mask_write 0XF8007000 0x20000000 0x00000000
|
|
||||||
}
|
|
||||||
proc ps7_post_config_1_0 {} {
|
|
||||||
mwr -force 0XF8000008 0x0000DF0D
|
|
||||||
mask_write 0XF8000900 0x0000000F 0x0000000F
|
|
||||||
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
|
|
||||||
mwr -force 0XF8000004 0x0000767B
|
|
||||||
}
|
|
||||||
proc ps7_debug_1_0 {} {
|
|
||||||
mwr -force 0XF8898FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8899FB0 0xC5ACCE55
|
|
||||||
mwr -force 0XF8809FB0 0xC5ACCE55
|
|
||||||
}
|
|
||||||
set PCW_SILICON_VER_1_0 "0x0"
|
|
||||||
set PCW_SILICON_VER_2_0 "0x1"
|
|
||||||
set PCW_SILICON_VER_3_0 "0x2"
|
|
||||||
set APU_FREQ 666666667
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc mask_poll { addr mask } {
|
|
||||||
set count 1
|
|
||||||
set curval "0x[string range [mrd $addr] end-8 end]"
|
|
||||||
set maskedval [expr {$curval & $mask}]
|
|
||||||
while { $maskedval == 0 } {
|
|
||||||
set curval "0x[string range [mrd $addr] end-8 end]"
|
|
||||||
set maskedval [expr {$curval & $mask}]
|
|
||||||
set count [ expr { $count + 1 } ]
|
|
||||||
if { $count == 100000000 } {
|
|
||||||
puts "Timeout Reached. Mask poll failed at ADDRESS: $addr MASK: $mask"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc mask_delay { addr val } {
|
|
||||||
set delay [ get_number_of_cycles_for_delay $val ]
|
|
||||||
perf_reset_and_start_timer
|
|
||||||
set curval "0x[string range [mrd $addr] end-8 end]"
|
|
||||||
set maskedval [expr {$curval < $delay}]
|
|
||||||
while { $maskedval == 1 } {
|
|
||||||
set curval "0x[string range [mrd $addr] end-8 end]"
|
|
||||||
set maskedval [expr {$curval < $delay}]
|
|
||||||
}
|
|
||||||
perf_reset_clock
|
|
||||||
}
|
|
||||||
|
|
||||||
proc ps_version { } {
|
|
||||||
set si_ver "0x[string range [mrd 0xF8007080] end-8 end]"
|
|
||||||
set mask_sil_ver "0x[expr {$si_ver >> 28}]"
|
|
||||||
return $mask_sil_ver;
|
|
||||||
}
|
|
||||||
|
|
||||||
proc ps7_post_config {} {
|
|
||||||
|
|
||||||
ps7_post_config_1_0
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
proc ps7_debug {} {
|
|
||||||
ps7_debug_1_0
|
|
||||||
|
|
||||||
}
|
|
||||||
proc ps7_init {} {
|
|
||||||
|
|
||||||
ps7_mio_init_data_1_0
|
|
||||||
ps7_pll_init_data_1_0
|
|
||||||
ps7_clock_init_data_1_0
|
|
||||||
ps7_ddr_init_data_1_0
|
|
||||||
ps7_peripherals_init_data_1_0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# For delay calculation using global timer
|
|
||||||
|
|
||||||
# start timer
|
|
||||||
proc perf_start_clock { } {
|
|
||||||
|
|
||||||
#writing SCU_GLOBAL_TIMER_CONTROL register
|
|
||||||
|
|
||||||
mask_write 0xF8F00208 0x00000109 0x00000009
|
|
||||||
}
|
|
||||||
|
|
||||||
# stop timer and reset timer count regs
|
|
||||||
proc perf_reset_clock { } {
|
|
||||||
perf_disable_clock
|
|
||||||
mask_write 0xF8F00200 0xFFFFFFFF 0x00000000
|
|
||||||
mask_write 0xF8F00204 0xFFFFFFFF 0x00000000
|
|
||||||
}
|
|
||||||
|
|
||||||
# Compute mask for given delay in miliseconds
|
|
||||||
proc get_number_of_cycles_for_delay { delay } {
|
|
||||||
|
|
||||||
# GTC is always clocked at 1/2 of the CPU frequency (CPU_3x2x)
|
|
||||||
variable APU_FREQ
|
|
||||||
return [ expr ($delay * $APU_FREQ /(2 * 1000))]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# stop timer
|
|
||||||
proc perf_disable_clock {} {
|
|
||||||
mask_write 0xF8F00208 0xFFFFFFFF 0x00000000
|
|
||||||
}
|
|
||||||
|
|
||||||
proc perf_reset_and_start_timer {} {
|
|
||||||
perf_reset_clock
|
|
||||||
perf_start_clock
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
19
openocd/redpitaya.cfg
Normal file
19
openocd/redpitaya.cfg
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
source ./digilent-hs2.cfg
|
||||||
|
adapter speed 1000
|
||||||
|
|
||||||
|
set PL_TAPID 0x13722093
|
||||||
|
set SMP 1
|
||||||
|
|
||||||
|
source ./zynq-7000.cfg
|
||||||
|
|
||||||
|
reset_config none
|
||||||
|
|
||||||
|
source ./common.cfg
|
||||||
|
|
||||||
|
halt
|
||||||
|
|
||||||
|
# Disable MMU
|
||||||
|
targets $_TARGETNAME_1
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
|
targets $_TARGETNAME_0
|
||||||
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
@ -1,61 +0,0 @@
|
|||||||
#
|
|
||||||
# TCL to allow the Xilinx PS7 Init TCL code to run in OpenOCD.
|
|
||||||
#
|
|
||||||
|
|
||||||
proc mrd { args } {
|
|
||||||
if {[llength $args] == 0} {
|
|
||||||
echo "mrd address \[count \[w|h|b\]\]"
|
|
||||||
echo " Read <count> memory locations starting at <address>. Defaults to one word."
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set addr [lindex $args 0]
|
|
||||||
set count 1
|
|
||||||
set bits 32
|
|
||||||
if {[llength $args] > 1} {
|
|
||||||
set count [lindex $args 1]
|
|
||||||
if {[llength $args] > 2} {
|
|
||||||
switch [lindex $args 2] {
|
|
||||||
w { set bits 32 }
|
|
||||||
h { set bits 16 }
|
|
||||||
b { set bits 8 }
|
|
||||||
default { set bits 32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mem2array x $bits $addr $count
|
|
||||||
set nibbles [expr {$bits / 4}]
|
|
||||||
set bytes [expr {$bits / 8}]
|
|
||||||
set result {}
|
|
||||||
foreach {idx elmt} $x {
|
|
||||||
append result [format "%08x: %0*x\n" [expr {$addr + $idx * $bytes}] $nibbles $elmt]
|
|
||||||
}
|
|
||||||
return $result
|
|
||||||
}
|
|
||||||
|
|
||||||
proc mwr { args } {
|
|
||||||
set addr [lindex $args 1]
|
|
||||||
set data [lindex $args 2]
|
|
||||||
mww $addr $data
|
|
||||||
}
|
|
||||||
|
|
||||||
proc mask_write { addr mask value } {
|
|
||||||
set curval "0x[string range [mrd $addr] end-8 end]"
|
|
||||||
set maskedval [expr {$curval & ~$mask}]
|
|
||||||
#echo "curval = [format 0x%08x $curval] maskedval = [format 0x%08x $maskedval]"
|
|
||||||
set writeval(0) [expr {$maskedval | $value}]
|
|
||||||
#echo " $addr <= [format 0x%08x $writeval(0)] ([format 0x%08x $curval]: [format 0x%08x $mask]/[format 0x%08x $value])"
|
|
||||||
array2mem writeval 32 $addr 1
|
|
||||||
}
|
|
||||||
|
|
||||||
proc xilinx_ps7_init { } {
|
|
||||||
poll off
|
|
||||||
reset init
|
|
||||||
reset halt
|
|
||||||
targets zynq.cpu.0
|
|
||||||
sleep 100
|
|
||||||
halt
|
|
||||||
ps7_debug
|
|
||||||
ps7_init
|
|
||||||
ps7_post_config
|
|
||||||
poll on
|
|
||||||
}
|
|
@ -1,43 +1,21 @@
|
|||||||
source [find interface/ftdi/olimex-arm-usb-tiny-h.cfg]
|
source [find interface/ftdi/olimex-arm-usb-tiny-h.cfg]
|
||||||
source [find xilinx-tcl.cfg]
|
adapter speed 1000
|
||||||
adapter_khz 1000
|
|
||||||
|
|
||||||
set PL_TAPID 0x23731093
|
set PL_TAPID 0x23731093
|
||||||
set SMP 1
|
set SMP 1
|
||||||
|
|
||||||
source ./zynq-7000.cfg
|
source ./zynq-7000.cfg
|
||||||
source ./xilinx-tcl.cfg
|
|
||||||
source ./ps7_init.tcl
|
|
||||||
|
|
||||||
reset_config srst_only srst_open_drain
|
reset_config srst_only srst_open_drain
|
||||||
adapter_nsrst_assert_width 250
|
adapter srst pulse_width 250
|
||||||
adapter_nsrst_delay 400
|
adapter srst delay 400
|
||||||
|
|
||||||
set XC7_JSHUTDOWN 0x0d
|
source ./common.cfg
|
||||||
set XC7_JPROGRAM 0x0b
|
|
||||||
set XC7_JSTART 0x0c
|
|
||||||
set XC7_BYPASS 0x3f
|
|
||||||
|
|
||||||
proc xc7_program {tap} {
|
reset halt
|
||||||
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
|
|
||||||
irscan $tap $XC7_JSHUTDOWN
|
|
||||||
irscan $tap $XC7_JPROGRAM
|
|
||||||
runtest 60000
|
|
||||||
#JSTART prevents this from working...
|
|
||||||
#irscan $tap $XC7_JSTART
|
|
||||||
runtest 2000
|
|
||||||
irscan $tap $XC7_BYPASS
|
|
||||||
runtest 2000
|
|
||||||
}
|
|
||||||
|
|
||||||
pld device virtex2 zynq.tap 1
|
|
||||||
init
|
|
||||||
xc7_program zynq.tap
|
|
||||||
|
|
||||||
xilinx_ps7_init
|
|
||||||
|
|
||||||
# Disable MMU
|
# Disable MMU
|
||||||
targets $_TARGETNAME_1
|
targets $_TARGETNAME_1
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
targets $_TARGETNAME_0
|
targets $_TARGETNAME_0
|
||||||
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
|
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
|
||||||
|
@ -81,131 +81,16 @@ jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x03 \
|
|||||||
set _TARGETNAME_0 $_CHIPNAME.cpu.0
|
set _TARGETNAME_0 $_CHIPNAME.cpu.0
|
||||||
set _TARGETNAME_1 $_CHIPNAME.cpu.1
|
set _TARGETNAME_1 $_CHIPNAME.cpu.1
|
||||||
|
|
||||||
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap
|
||||||
target create $_TARGETNAME_0 cortex_a -coreid 0 \
|
target create $_TARGETNAME_0 cortex_a -coreid 0 \
|
||||||
-endian $_ENDIAN \
|
-endian $_ENDIAN \
|
||||||
-chain-position $_CHIPNAME.dap \
|
-dap $_CHIPNAME.dap \
|
||||||
-dbgbase 0x80090000
|
-dbgbase 0x80090000
|
||||||
if { $_SMP } {
|
if { $_SMP } {
|
||||||
echo "Zynq CPU1."
|
echo "Zynq CPU1."
|
||||||
target create $_TARGETNAME_1 cortex_a -coreid 1 \
|
target create $_TARGETNAME_1 cortex_a -coreid 1 \
|
||||||
-endian $_ENDIAN \
|
-endian $_ENDIAN \
|
||||||
-chain-position $_CHIPNAME.dap \
|
-dap $_CHIPNAME.dap \
|
||||||
-dbgbase 0x80092000
|
-dbgbase 0x80092000
|
||||||
target smp $_TARGETNAME_0 $_TARGETNAME_1
|
target smp $_TARGETNAME_0 $_TARGETNAME_1
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
|
||||||
# Hack to get the registers into a stable state when first booting a zynq in
|
|
||||||
# JTAG mode. If r11 is pointing to an invalid address and you use gdb to set a
|
|
||||||
# register the write will fail because gdb attempts to scan or unwind the
|
|
||||||
# current frame and the bad address seems to lock the bus up. This code puts
|
|
||||||
# the registers into the OCM and hopefull safe.
|
|
||||||
#
|
|
||||||
proc zynq_clear_registers { target } {
|
|
||||||
echo "Zynq-7000 Series setup: $target"
|
|
||||||
set _OCM_END 0x0003FFF0
|
|
||||||
mww phys 0xF8007000 0x4E00E07F
|
|
||||||
reg r0 0
|
|
||||||
reg r1 0
|
|
||||||
reg r2 0
|
|
||||||
reg r3 0
|
|
||||||
reg r4 0
|
|
||||||
reg r5 0
|
|
||||||
reg r6 0
|
|
||||||
reg r7 0
|
|
||||||
reg r8 0
|
|
||||||
reg r9 0
|
|
||||||
reg r10 0
|
|
||||||
reg r11 $_OCM_END
|
|
||||||
reg sp_svc $_OCM_END
|
|
||||||
reg lr_svc $_OCM_END
|
|
||||||
reg sp_abt $_OCM_END
|
|
||||||
reg lr_abt $_OCM_END
|
|
||||||
reg sp_und $_OCM_END
|
|
||||||
reg lr_und $_OCM_END
|
|
||||||
}
|
|
||||||
|
|
||||||
proc zynq_disable_mmu_and_caches { target } {
|
|
||||||
# arm mcr pX op1 CRn CRm op2 value
|
|
||||||
echo "Disable MMU and caches"
|
|
||||||
# Invalidate caches
|
|
||||||
catch {
|
|
||||||
$target arm mcr 15 0 7 5 0 0
|
|
||||||
$target arm mcr 15 0 7 7 0 0
|
|
||||||
# Invalidate all TLBs
|
|
||||||
$target arm mcr 15 0 8 5 0 0
|
|
||||||
$target arm mcr 15 0 8 6 0 0
|
|
||||||
$target arm mcr 15 0 8 7 0 0
|
|
||||||
$target arm mcr 15 4 8 3 0 0
|
|
||||||
$target arm mcr 15 4 8 7 0 0
|
|
||||||
set cp [$target arm mrc 15 0 1 0 0]
|
|
||||||
echo "SCTRL => [format 0x%x $cp]"
|
|
||||||
set mask [expr 1 << 29 | 1 << 12 | 1 << 11 | 1 << 2 | 1 << 1 | 1 << 0]
|
|
||||||
set cp [expr ($cp & ~$mask)]
|
|
||||||
$target arm mcr 15 0 1 0 0 $cp
|
|
||||||
echo "SCTRL <= [format 0x%x $cp]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proc zynq_boot_ocm_setup { } {
|
|
||||||
#
|
|
||||||
# Enable the OCM
|
|
||||||
#
|
|
||||||
echo "Zynq Boot OCM setup"
|
|
||||||
catch {
|
|
||||||
mww phys 0xF8000008 0xDF0D
|
|
||||||
mww phys 0xF8000238 0
|
|
||||||
mww phys 0xF8000910 0xC
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proc zynq_rtems_setup { } {
|
|
||||||
cache_config l2x 0xF8F02000 8
|
|
||||||
cortex_a maskisr on
|
|
||||||
}
|
|
||||||
|
|
||||||
proc zynq_restart { wait } {
|
|
||||||
global _SMP
|
|
||||||
global _TARGETNAME_0
|
|
||||||
global _TARGETNAME_1
|
|
||||||
set target0 $_TARGETNAME_0
|
|
||||||
set target1 $_TARGETNAME_1
|
|
||||||
echo "Zynq reset, resetting the board ... "
|
|
||||||
poll off
|
|
||||||
#
|
|
||||||
# Issue the reset via the SLCR
|
|
||||||
#
|
|
||||||
catch {
|
|
||||||
mww phys 0xF8000008 0xDF0D
|
|
||||||
mww phys 0xF8000200 1
|
|
||||||
}
|
|
||||||
echo "Zynq reset waiting for $wait msecs ... "
|
|
||||||
sleep $wait
|
|
||||||
#
|
|
||||||
# Reconnect the DAP etc due to the reset.
|
|
||||||
#
|
|
||||||
$target0 cortex_a dbginit
|
|
||||||
$target0 arm core_state arm
|
|
||||||
if { $_SMP } {
|
|
||||||
$target1 arm core_state arm
|
|
||||||
$target1 cortex_a dbginit
|
|
||||||
cortex_a smp_off
|
|
||||||
}
|
|
||||||
poll on
|
|
||||||
#
|
|
||||||
# We can now halt the core.
|
|
||||||
#
|
|
||||||
if { $_SMP } {
|
|
||||||
targets $target1
|
|
||||||
halt
|
|
||||||
}
|
|
||||||
targets $target0
|
|
||||||
halt
|
|
||||||
zynq_rtems_setup
|
|
||||||
}
|
|
||||||
|
|
||||||
proc zynq_gdb_attach { target } {
|
|
||||||
catch {
|
|
||||||
halt
|
|
||||||
}
|
|
||||||
}
|
|
6
qemu.gdb
6
qemu.gdb
@ -1,6 +0,0 @@
|
|||||||
target remote :1234
|
|
||||||
|
|
||||||
# print demangled symbols by default
|
|
||||||
set print asm-demangle on
|
|
||||||
|
|
||||||
load
|
|
@ -4,7 +4,7 @@ set -e
|
|||||||
|
|
||||||
target_host="rpi-4.m-labs.hk"
|
target_host="rpi-4.m-labs.hk"
|
||||||
|
|
||||||
while getopts "h:i" opt; do
|
while getopts "h:" opt; do
|
||||||
case "$opt" in
|
case "$opt" in
|
||||||
\?) exit 0
|
\?) exit 0
|
||||||
;;
|
;;
|
||||||
|
11
runner.sh
11
runner.sh
@ -1,11 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e -m
|
|
||||||
|
|
||||||
ELF=$1
|
|
||||||
IMAGE=$ELF.bin
|
|
||||||
arm-none-eabihf-objcopy -O binary $ELF $IMAGE
|
|
||||||
qemu-system-arm -M xilinx-zynq-a9 -s -kernel $IMAGE -chardev file,id=uart0,path=/tmp/qemu.serial &
|
|
||||||
sleep 1
|
|
||||||
gdb -x qemu.gdb $ELF
|
|
||||||
kill -KILL %1
|
|
24
shell.nix
24
shell.nix
@ -1,24 +0,0 @@
|
|||||||
let
|
|
||||||
mozillaOverlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
|
|
||||||
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; };
|
|
||||||
in
|
|
||||||
with pkgs;
|
|
||||||
let
|
|
||||||
project = callPackage ./default.nix {};
|
|
||||||
in
|
|
||||||
with project;
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
name = "zynq-env";
|
|
||||||
buildInputs = (with rustPlatform.rust; [
|
|
||||||
rustc cargo
|
|
||||||
cargo-xbuild rustcSrc
|
|
||||||
]) ++ (with pkgs; [ openocd gdb ]);
|
|
||||||
|
|
||||||
# Set Environment Variables
|
|
||||||
RUST_BACKTRACE = 1;
|
|
||||||
XARGO_RUST_SRC = "${rustcSrc}/src";
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
echo "Run 'cargo xbuild --release -p experiments' to build."
|
|
||||||
'';
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user