forked from auracaster/openocd
Compare commits
956 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5d07f7ea5 | ||
|
|
ef1c4a2b1f | ||
|
|
fcca2e82ec | ||
|
|
90142e3edb | ||
|
|
3822a07ed7 | ||
|
|
39cff815d2 | ||
|
|
7178940114 | ||
|
|
be46b9821e | ||
|
|
d9ba56c295 | ||
|
|
b7d2cdc0d4 | ||
|
|
564a5eb537 | ||
|
|
67607fb64c | ||
|
|
392fe70927 | ||
|
|
ece2892701 | ||
|
|
37299b2b58 | ||
|
|
da2e40bcd3 | ||
|
|
992059b898 | ||
|
|
e12989a84b | ||
|
|
4a590e0b56 | ||
|
|
0e6c42eb42 | ||
|
|
4bfa4858d1 | ||
|
|
ad1c9cdbcb | ||
|
|
906d6aaa19 | ||
|
|
ff1108ad38 | ||
|
|
d7646942f2 | ||
|
|
79d6d3cda9 | ||
|
|
9695564e63 | ||
|
|
d5e564625f | ||
|
|
37c28903a1 | ||
|
|
109f37c161 | ||
|
|
1936646fc2 | ||
|
|
28cf4e463b | ||
|
|
2cb486213e | ||
|
|
3f0e9c8ad2 | ||
|
|
b2189fa936 | ||
|
|
0a33b7b2aa | ||
|
|
46bcaec696 | ||
|
|
305832c49d | ||
|
|
3ad44cc1f5 | ||
|
|
460eb952d8 | ||
|
|
665ac60ef0 | ||
|
|
441914978d | ||
|
|
50c9315212 | ||
|
|
74db7f9681 | ||
|
|
37a6e40250 | ||
|
|
2dde122b66 | ||
|
|
1d040adb0d | ||
|
|
c185a5b724 | ||
|
|
70fb53f90b | ||
|
|
704fc7eb3d | ||
|
|
2a8a89edcb | ||
|
|
0875e64ddb | ||
|
|
900f2998c8 | ||
|
|
fe97fab6a0 | ||
|
|
8fa4d71d5c | ||
|
|
b7e0cd48f0 | ||
|
|
1da9e595ec | ||
|
|
0fd0b8ee7c | ||
|
|
9c450c704c | ||
|
|
a7e3418258 | ||
|
|
4315142ea0 | ||
|
|
13288a44be | ||
|
|
4e47519f6c | ||
|
|
927e53f8d5 | ||
|
|
700e7605fe | ||
|
|
30fde70c03 | ||
|
|
fac9057f02 | ||
|
|
02192f6b8c | ||
|
|
9b6de72c2b | ||
|
|
5914310f88 | ||
|
|
80b80ef9b4 | ||
|
|
dd9145b52e | ||
|
|
680230c63c | ||
|
|
101c602b5e | ||
|
|
8a4835bd26 | ||
|
|
3533ce0106 | ||
|
|
aa3f7887ea | ||
|
|
7074321ade | ||
|
|
2467da4b4a | ||
|
|
a84d237acf | ||
|
|
07dcd5648d | ||
|
|
7aaf4f75b3 | ||
|
|
e65db159e0 | ||
|
|
1fd8ac0ee6 | ||
|
|
468a4b65ea | ||
|
|
f14cf545eb | ||
|
|
1d1f1b95a7 | ||
|
|
0581ab7855 | ||
|
|
dcfa3ac7c7 | ||
|
|
ef83a9ee93 | ||
|
|
0f1d00bda6 | ||
|
|
5d80b36552 | ||
|
|
c4e0109644 | ||
|
|
57aa19f846 | ||
|
|
3d62c3df6d | ||
|
|
80f78acf73 | ||
|
|
b00b9f2d7d | ||
|
|
17b57f8865 | ||
|
|
15d6602e8a | ||
|
|
bfe1a6c892 | ||
|
|
bd5df8520b | ||
|
|
87668aebf1 | ||
|
|
feddedb6db | ||
|
|
f4f87cb472 | ||
|
|
98709ab461 | ||
|
|
e6b27756da | ||
|
|
85ed6ea59f | ||
|
|
fc2abe63fd | ||
|
|
bf3f35092e | ||
|
|
4a5c9a4965 | ||
|
|
08fc741733 | ||
|
|
b5c616b90e | ||
|
|
f54a639b28 | ||
|
|
f807d6ab3d | ||
|
|
3eb7d77601 | ||
|
|
d631b2e5ac | ||
|
|
6efcd943b2 | ||
|
|
aef50bc563 | ||
|
|
9cdb6b438d | ||
|
|
86cc37183a | ||
|
|
061f828a50 | ||
|
|
b2be4934d7 | ||
|
|
3ad078cb60 | ||
|
|
df7a6b08a6 | ||
|
|
7ae9154846 | ||
|
|
76afadeb7b | ||
|
|
48e01a4969 | ||
|
|
6bd9e3b94f | ||
|
|
bf2b0a0361 | ||
|
|
9060ae7de5 | ||
|
|
aebe7596f6 | ||
|
|
b9dbf569b4 | ||
|
|
cf1418e9a8 | ||
|
|
9b045f62f4 | ||
|
|
80649fc3d5 | ||
|
|
84043a95e1 | ||
|
|
54a8640df0 | ||
|
|
f82798c814 | ||
|
|
977db554c4 | ||
|
|
928289773c | ||
|
|
e0d4d46dbe | ||
|
|
95025349fa | ||
|
|
0466ee7e4a | ||
|
|
c3e537a340 | ||
|
|
69359b1c52 | ||
|
|
67801c061f | ||
|
|
adb8ec32dc | ||
|
|
c7a6f065d2 | ||
|
|
561984c8f6 | ||
|
|
bd1502eb0f | ||
|
|
6c467da586 | ||
|
|
549d9bc72c | ||
|
|
1bba393e3c | ||
|
|
a047d87196 | ||
|
|
b7ea4a6162 | ||
|
|
26902bb317 | ||
|
|
db42a373b7 | ||
|
|
1e07f7bb6a | ||
|
|
71d43007c6 | ||
|
|
2d75ff3151 | ||
|
|
67a848424b | ||
|
|
c91dbd41ba | ||
|
|
539a9cf208 | ||
|
|
6d76fc1328 | ||
|
|
6565988064 | ||
|
|
27ad96e0d9 | ||
|
|
1a8223f28b | ||
|
|
3e81c4b6df | ||
|
|
7155349bd0 | ||
|
|
9785f51f19 | ||
|
|
78807eb6ec | ||
|
|
5bb5620c48 | ||
|
|
18077654af | ||
|
|
f3e01106d9 | ||
|
|
83f3f2c4c7 | ||
|
|
c09cd75d9b | ||
|
|
6644018337 | ||
|
|
9aad563d15 | ||
|
|
47d5f44fe0 | ||
|
|
115b7be426 | ||
|
|
0355d98793 | ||
|
|
08ddb19fd3 | ||
|
|
aa8e480ec4 | ||
|
|
5c2c269336 | ||
|
|
a72a42230b | ||
|
|
68956e028a | ||
|
|
79fa75e199 | ||
|
|
ed3632d9c7 | ||
|
|
051ec13abc | ||
|
|
d8d1c62cc3 | ||
|
|
e22a6d2e06 | ||
|
|
c4ab127b40 | ||
|
|
e89cae8dbc | ||
|
|
8104b58dbc | ||
|
|
fc302a0252 | ||
|
|
6663a788a5 | ||
|
|
452248af1d | ||
|
|
d2f61e1a45 | ||
|
|
9064fa9081 | ||
|
|
6d8a865eef | ||
|
|
d2e8ce1478 | ||
|
|
538a86c339 | ||
|
|
6f65045b37 | ||
|
|
077d77140c | ||
|
|
442a684303 | ||
|
|
3a6ac23716 | ||
|
|
a4dc39beb4 | ||
|
|
4a5dc0988a | ||
|
|
27f0497efa | ||
|
|
7165e05cf6 | ||
|
|
98a41bca6e | ||
|
|
443197aff0 | ||
|
|
15615dcff2 | ||
|
|
19b351d8c8 | ||
|
|
14e12c3969 | ||
|
|
d8e4a7370f | ||
|
|
2bda1ee49d | ||
|
|
9ff4071568 | ||
|
|
a136b08fc3 | ||
|
|
006a108494 | ||
|
|
3f8ca97daf | ||
|
|
9e001244da | ||
|
|
8415353f2b | ||
|
|
4da4e1cfb7 | ||
|
|
9fe0457c51 | ||
|
|
cbfc443c7b | ||
|
|
43902905bb | ||
|
|
44e6d7720b | ||
|
|
16cd4e6fce | ||
|
|
5952843fc5 | ||
|
|
bd5f5c6a66 | ||
|
|
c9d9573c29 | ||
|
|
8d4ad82da7 | ||
|
|
28749c15bb | ||
|
|
7cf1a1f04f | ||
|
|
8cbcd56c0e | ||
|
|
f8388cd4bb | ||
|
|
3eb80331ce | ||
|
|
a3c09f9624 | ||
|
|
eaed9db414 | ||
|
|
f232512a21 | ||
|
|
8a271d9dd1 | ||
|
|
ebece4a981 | ||
|
|
a046475f03 | ||
|
|
c06af3af91 | ||
|
|
46c1114c1e | ||
|
|
2076ba093d | ||
|
|
0b98ca3610 | ||
|
|
5ed9eb6160 | ||
|
|
baf1797406 | ||
|
|
a5768e9722 | ||
|
|
e4df550ad9 | ||
|
|
abccd76ea4 | ||
|
|
1ab99c3fe5 | ||
|
|
0b118583f7 | ||
|
|
4dd8f8aa40 | ||
|
|
516719b6b8 | ||
|
|
15e19011ea | ||
|
|
fe52282c37 | ||
|
|
a4830e7a6a | ||
|
|
370d02b857 | ||
|
|
552e027f68 | ||
|
|
e26ddb627b | ||
|
|
8a197f0bbc | ||
|
|
37f8f0bf9a | ||
|
|
39f3501afb | ||
|
|
9fbfb6103a | ||
|
|
6d9803ef1d | ||
|
|
4288886c83 | ||
|
|
210ff60284 | ||
|
|
9a8aa4ec63 | ||
|
|
897817b331 | ||
|
|
6055d952c3 | ||
|
|
d9a02fda07 | ||
|
|
d7f5a00cdc | ||
|
|
0288ea0920 | ||
|
|
9a9f745eba | ||
|
|
38e547b9c7 | ||
|
|
07158a7f8a | ||
|
|
73d87c6210 | ||
|
|
4c3972c1df | ||
|
|
09f9596ae0 | ||
|
|
a25e61ecd3 | ||
|
|
2ce4e31bbc | ||
|
|
4be685c616 | ||
|
|
0989cd4d5d | ||
|
|
47728f9215 | ||
|
|
63a23e6fc8 | ||
|
|
349b459e98 | ||
|
|
f97a159411 | ||
|
|
78f4f95648 | ||
|
|
640141eea3 | ||
|
|
2d57e80801 | ||
|
|
60a932b368 | ||
|
|
fb525cdd76 | ||
|
|
0e4dee1164 | ||
|
|
939f923927 | ||
|
|
c58c24c42f | ||
|
|
aec561c7c6 | ||
|
|
66b9bff3b3 | ||
|
|
8b344453ed | ||
|
|
3cbabd9fff | ||
|
|
a7f320e919 | ||
|
|
7d11ee207b | ||
|
|
0527d336a5 | ||
|
|
168fcf58c5 | ||
|
|
f1e9cef410 | ||
|
|
63687807cc | ||
|
|
9c9c06b8ae | ||
|
|
ee8df96b2b | ||
|
|
8fe2bed92c | ||
|
|
c89eb70a20 | ||
|
|
b8862229d0 | ||
|
|
2b6a75538a | ||
|
|
b56bad824b | ||
|
|
7b67ec988c | ||
|
|
40801d21ff | ||
|
|
246f8492da | ||
|
|
5e1f5f4731 | ||
|
|
09cd5661e6 | ||
|
|
9a8edbfa8b | ||
|
|
38e44d1361 | ||
|
|
055abd0b9c | ||
|
|
531fbf0ef2 | ||
|
|
fe583e78c2 | ||
|
|
ba00ef3c40 | ||
|
|
52125f1d13 | ||
|
|
951d185049 | ||
|
|
0900d5a3cd | ||
|
|
8cf671ea7b | ||
|
|
10fd274cfe | ||
|
|
5e4ee571cc | ||
|
|
af9918deec | ||
|
|
aaf5991d79 | ||
|
|
f5e97b5e1b | ||
|
|
b598efb613 | ||
|
|
2aab7d3ce2 | ||
|
|
24c0f9470a | ||
|
|
1df6e59178 | ||
|
|
07251ab8d8 | ||
|
|
5b170456f7 | ||
|
|
2c14497d0a | ||
|
|
e8641695c6 | ||
|
|
9ce207a52a | ||
|
|
30aacc0564 | ||
|
|
6d639b09f0 | ||
|
|
edf0c3376d | ||
|
|
321948b41f | ||
|
|
24a1e7b0fc | ||
|
|
5b0a131594 | ||
|
|
aeb3c4f37e | ||
|
|
4b6af97978 | ||
|
|
17ea1b31a1 | ||
|
|
b79f9ad172 | ||
|
|
e571746735 | ||
|
|
d50ce65962 | ||
|
|
7800045671 | ||
|
|
a21affa429 | ||
|
|
1b2cb095ba | ||
|
|
8fb5e8e58f | ||
|
|
9b3224e887 | ||
|
|
445a54a669 | ||
|
|
c3074f377c | ||
|
|
3d2dd4a3a3 | ||
|
|
423bfc49f9 | ||
|
|
d6334188ec | ||
|
|
f901445524 | ||
|
|
ffabd98d4a | ||
|
|
6b6e28ff02 | ||
|
|
b908538998 | ||
|
|
5cc004180b | ||
|
|
1dd462a6d6 | ||
|
|
25b855d2d2 | ||
|
|
bb3793c9a4 | ||
|
|
482660031a | ||
|
|
e1c40cb1c1 | ||
|
|
8f842ea40a | ||
|
|
7bfcc10839 | ||
|
|
a34b38d621 | ||
|
|
87a9ee3625 | ||
|
|
f019c4f7d6 | ||
|
|
7572059832 | ||
|
|
323aeaf90b | ||
|
|
8cb0dae823 | ||
|
|
47a276cfae | ||
|
|
064475459b | ||
|
|
9ca1592cb9 | ||
|
|
0eaa8e7db0 | ||
|
|
ec5e4bae25 | ||
|
|
f9ea791e9b | ||
|
|
e858451505 | ||
|
|
cad5991135 | ||
|
|
c102e448c3 | ||
|
|
61672009c4 | ||
|
|
18df479f0a | ||
|
|
57260831dd | ||
|
|
caeb057205 | ||
|
|
a09bb27e23 | ||
|
|
d469c686d9 | ||
|
|
6637cf9229 | ||
|
|
9d31589d19 | ||
|
|
e95f8d93f2 | ||
|
|
ca53849045 | ||
|
|
d2d4f776d8 | ||
|
|
e1e1d4742c | ||
|
|
1b0c22dd56 | ||
|
|
4257cb728c | ||
|
|
47cf0aabc8 | ||
|
|
7fca524606 | ||
|
|
85c0375337 | ||
|
|
dcb222e072 | ||
|
|
f7a37efc3f | ||
|
|
388d041e0f | ||
|
|
908ee4dc96 | ||
|
|
85735925c7 | ||
|
|
ee38fff78b | ||
|
|
8002ed268d | ||
|
|
ff6c3dd13c | ||
|
|
cc4a934d37 | ||
|
|
2d8c7c510b | ||
|
|
5d1cabb142 | ||
|
|
9cc733ae31 | ||
|
|
0ce2e9a259 | ||
|
|
6f3a9bdf67 | ||
|
|
8117ad8ce9 | ||
|
|
fdbf70601d | ||
|
|
d1cd97777b | ||
|
|
f28a5d9217 | ||
|
|
63e5386fa6 | ||
|
|
f908bae6bf | ||
|
|
6ba7331501 | ||
|
|
941fb511cf | ||
|
|
0a581ccdb1 | ||
|
|
b9ecc64c80 | ||
|
|
fa39842d28 | ||
|
|
26f1354eda | ||
|
|
28e43783e5 | ||
|
|
c9e59b30ab | ||
|
|
e6e8bf46e4 | ||
|
|
818cc61775 | ||
|
|
008336becc | ||
|
|
b4eba5819f | ||
|
|
c2207e852e | ||
|
|
6a1236a7ac | ||
|
|
43d4ae4763 | ||
|
|
28c0f2befc | ||
|
|
7e2fb7ce9a | ||
|
|
b6068f5a48 | ||
|
|
3c270bb0a9 | ||
|
|
d90eb2b93d | ||
|
|
57dce9560a | ||
|
|
108a458ab8 | ||
|
|
e3b3273433 | ||
|
|
f1e59308d1 | ||
|
|
fad7240689 | ||
|
|
7743e0fb43 | ||
|
|
a2935397b4 | ||
|
|
e2535e7901 | ||
|
|
18e6e02cdc | ||
|
|
a6cf60c9c2 | ||
|
|
2c25ab4588 | ||
|
|
8e5ea23201 | ||
|
|
1748aab2c9 | ||
|
|
d40cb56d49 | ||
|
|
d1a6dfbb87 | ||
|
|
738e259d59 | ||
|
|
90ea965fca | ||
|
|
861df4574d | ||
|
|
8cb4fc1420 | ||
|
|
067ac78b61 | ||
|
|
e9976aa3a8 | ||
|
|
4e31b87943 | ||
|
|
90d33c5c87 | ||
|
|
d26098b664 | ||
|
|
222afb3d0e | ||
|
|
c68a267ee1 | ||
|
|
8fc35a696f | ||
|
|
4aa63d59bd | ||
|
|
1274df07f1 | ||
|
|
f1c0133321 | ||
|
|
b0cab3d809 | ||
|
|
0ba480d924 | ||
|
|
e26d076190 | ||
|
|
fe11baeebb | ||
|
|
7151398cff | ||
|
|
4a29a4a86d | ||
|
|
5d02d2de43 | ||
|
|
dbb8de15e3 | ||
|
|
e2073cc18a | ||
|
|
6f5b9e9304 | ||
|
|
cfdfe5119d | ||
|
|
8e198e9471 | ||
|
|
35e7377160 | ||
|
|
39650e2273 | ||
|
|
34d1f82c75 | ||
|
|
736e8bb773 | ||
|
|
ea39d4b281 | ||
|
|
7d1f9bafc7 | ||
|
|
ed12a6521f | ||
|
|
0999bdb830 | ||
|
|
27b3d9c434 | ||
|
|
5c5af2467b | ||
|
|
dfe8f3a441 | ||
|
|
0ab3f83667 | ||
|
|
4b4ce4f27e | ||
|
|
9e137265de | ||
|
|
00937cd049 | ||
|
|
428d1559ee | ||
|
|
c59a4419fc | ||
|
|
3ddb3b3c3d | ||
|
|
592be6504c | ||
|
|
cea4842207 | ||
|
|
14f51c0a32 | ||
|
|
38dc253001 | ||
|
|
6dfd56a743 | ||
|
|
30a4271b41 | ||
|
|
21a0f9b48b | ||
|
|
3a7ca6a621 | ||
|
|
5793056d96 | ||
|
|
d431af34fe | ||
|
|
94db77a0e6 | ||
|
|
90cee35696 | ||
|
|
bee7184ce4 | ||
|
|
dec6b91380 | ||
|
|
e6580a3cff | ||
|
|
2eb564b756 | ||
|
|
813f4a5411 | ||
|
|
f0ef9960b6 | ||
|
|
f6b50b8ea2 | ||
|
|
897981c318 | ||
|
|
2f944a3410 | ||
|
|
631b80fd08 | ||
|
|
445770c081 | ||
|
|
d8b912755d | ||
|
|
0a98914700 | ||
|
|
fd39a5e8ad | ||
|
|
ddb2bb28fa | ||
|
|
737a52d7b2 | ||
|
|
b0ef9cf117 | ||
|
|
7c4f3b1ff5 | ||
|
|
ec73356159 | ||
|
|
338f5a1d48 | ||
|
|
de545ee93a | ||
|
|
87bf0db125 | ||
|
|
5d43ffd5bc | ||
|
|
7d48be5bd3 | ||
|
|
5bcb78f181 | ||
|
|
60c2ea144b | ||
|
|
19edcec872 | ||
|
|
d608dcaa62 | ||
|
|
4db24acb93 | ||
|
|
394dcc8e34 | ||
|
|
f86986a9ef | ||
|
|
dbbe2a5388 | ||
|
|
4291873994 | ||
|
|
7719e2188e | ||
|
|
374127301e | ||
|
|
de0130a0aa | ||
|
|
2af5b97ba3 | ||
|
|
38f8e5eefa | ||
|
|
3da783f628 | ||
|
|
9f0cba528a | ||
|
|
fab0dcd7e6 | ||
|
|
1e9f8836a1 | ||
|
|
7b032df3aa | ||
|
|
8b00e56e64 | ||
|
|
9ad57e96b3 | ||
|
|
2f6f7c442d | ||
|
|
b48d1f6637 | ||
|
|
91e054a9ea | ||
|
|
f7772ccb49 | ||
|
|
e3b114e285 | ||
|
|
c4f2a018a5 | ||
|
|
250dc58056 | ||
|
|
dd4247dba5 | ||
|
|
bce7009e31 | ||
|
|
81b4ef6ee5 | ||
|
|
61f3d4b7e4 | ||
|
|
fce4ac5714 | ||
|
|
571db43791 | ||
|
|
6bbb1479b3 | ||
|
|
f2ee4eff73 | ||
|
|
1340f952a7 | ||
|
|
15f546e92f | ||
|
|
9663ee3243 | ||
|
|
f50ca7c184 | ||
|
|
3c63eff2d9 | ||
|
|
536ca77e38 | ||
|
|
a559f8a791 | ||
|
|
769064de4b | ||
|
|
8959fccc19 | ||
|
|
7f1ab30b88 | ||
|
|
c527882121 | ||
|
|
3a550e5b5f | ||
|
|
9db465810a | ||
|
|
23ece85f33 | ||
|
|
28b1fbd5ee | ||
|
|
3528457ba8 | ||
|
|
0c2f8b6eb8 | ||
|
|
eae6353ca4 | ||
|
|
c25ffd013e | ||
|
|
0a4b27ec4b | ||
|
|
433ca26f1a | ||
|
|
885341a2db | ||
|
|
2bc51d1abc | ||
|
|
ebac7c963a | ||
|
|
ff3028ce1b | ||
|
|
1db60b9c43 | ||
|
|
ca173ff4d4 | ||
|
|
fa5b0833d5 | ||
|
|
c46cbe3aa7 | ||
|
|
c2ab3b4d5e | ||
|
|
37b575367b | ||
|
|
c2c4f440af | ||
|
|
aa29f083a7 | ||
|
|
0cccdde3c7 | ||
|
|
04fe2ca554 | ||
|
|
2a34cc8eb6 | ||
|
|
0aefdbd446 | ||
|
|
ad0847ca38 | ||
|
|
afe95871c5 | ||
|
|
5f83378a9c | ||
|
|
32d3063cf5 | ||
|
|
06d1580ff7 | ||
|
|
cd22bedf6f | ||
|
|
80df024c80 | ||
|
|
e024bcc3d9 | ||
|
|
a77ba6a8b4 | ||
|
|
63c4af0104 | ||
|
|
327fafc6a2 | ||
|
|
51f06253ad | ||
|
|
c3beb69c47 | ||
|
|
3cbed17e18 | ||
|
|
e8b094b846 | ||
|
|
16b6b5e7a8 | ||
|
|
42cb62cf3b | ||
|
|
ae7ab8b09d | ||
|
|
4668bd264c | ||
|
|
54d6330b78 | ||
|
|
59cd1c892d | ||
|
|
c479f9b50f | ||
|
|
725e7e6aa7 | ||
|
|
033d1053ae | ||
|
|
1d75eb25e0 | ||
|
|
1d873623a0 | ||
|
|
54f820e8d8 | ||
|
|
9f89822335 | ||
|
|
4c11906241 | ||
|
|
7e2257663d | ||
|
|
27bcd224b2 | ||
|
|
c402c1166b | ||
|
|
8901fca027 | ||
|
|
a57d547dd7 | ||
|
|
583c9b31ab | ||
|
|
684e9674a6 | ||
|
|
c6f44bde73 | ||
|
|
77accb2f3d | ||
|
|
7e3780de15 | ||
|
|
e1478abc2c | ||
|
|
115f5380ff | ||
|
|
a30a4f0fc7 | ||
|
|
cb90d32e38 | ||
|
|
991ed5a2b6 | ||
|
|
c132304ee9 | ||
|
|
73e3ea47aa | ||
|
|
55fd943c15 | ||
|
|
7da1f2bbbc | ||
|
|
46cc1df722 | ||
|
|
c10a315f91 | ||
|
|
886ea0b914 | ||
|
|
667d510dab | ||
|
|
09571d62bc | ||
|
|
164450a015 | ||
|
|
06e731185f | ||
|
|
230f0e9dc6 | ||
|
|
e8d1da15c2 | ||
|
|
ac4340e391 | ||
|
|
3d0e2547fe | ||
|
|
b7ce3b5d15 | ||
|
|
122509a0dc | ||
|
|
330b0d68c2 | ||
|
|
3ed7e793c8 | ||
|
|
3500109fc7 | ||
|
|
5165afc005 | ||
|
|
d6a1ff8399 | ||
|
|
1794e5ee54 | ||
|
|
3dde0f47b2 | ||
|
|
4f4acc3669 | ||
|
|
ea54ea5364 | ||
|
|
ce3760c7e8 | ||
|
|
57cb28b484 | ||
|
|
f80ef64858 | ||
|
|
83be6cfc16 | ||
|
|
c725167ba8 | ||
|
|
e0c0810a8e | ||
|
|
e2fdb1c864 | ||
|
|
6461f7669a | ||
|
|
c460697b62 | ||
|
|
ea16bc578f | ||
|
|
e6c3ab9df3 | ||
|
|
b9346fbd64 | ||
|
|
b462316699 | ||
|
|
17322b729c | ||
|
|
3291edf1e7 | ||
|
|
c8f4d82b45 | ||
|
|
56e64812b8 | ||
|
|
40d9b24195 | ||
|
|
841ee77350 | ||
|
|
03fc47a79e | ||
|
|
c44293b0f8 | ||
|
|
218a4b4e20 | ||
|
|
0f41634d4f | ||
|
|
dbf25984cd | ||
|
|
e224b64d70 | ||
|
|
b302344779 | ||
|
|
88ca3aabfb | ||
|
|
de1fb8c6ac | ||
|
|
e1500a9c9d | ||
|
|
280e1b334a | ||
|
|
e5e2408680 | ||
|
|
950f240519 | ||
|
|
6eb18b307a | ||
|
|
2475e7b14c | ||
|
|
f2af5a7b48 | ||
|
|
78677c6b42 | ||
|
|
a1f6b6612b | ||
|
|
7af4ec859d | ||
|
|
ed13d3d3be | ||
|
|
aef1fe6024 | ||
|
|
287ba1888b | ||
|
|
9450da873c | ||
|
|
d31803d3d9 | ||
|
|
a17907d106 | ||
|
|
ffe969898f | ||
|
|
67c3ad8c40 | ||
|
|
a943ec1ca9 | ||
|
|
9e1a16690e | ||
|
|
eac1bc55d2 | ||
|
|
fb5422261f | ||
|
|
87552bc1d3 | ||
|
|
36cc893086 | ||
|
|
4c3a87c28f | ||
|
|
86e3cd20dd | ||
|
|
b472c2f245 | ||
|
|
7d9d056eae | ||
|
|
86d8ee7fe2 | ||
|
|
234f51429e | ||
|
|
74558296d1 | ||
|
|
e74a081a1a | ||
|
|
3558721df7 | ||
|
|
ac813a666a | ||
|
|
6fa4c5a456 | ||
|
|
3bab899063 | ||
|
|
0552c05ee8 | ||
|
|
d931bb5a05 | ||
|
|
00c8648351 | ||
|
|
4bea65f1b2 | ||
|
|
ca45e700b1 | ||
|
|
17b546a900 | ||
|
|
6be4646d17 | ||
|
|
b01e136045 | ||
|
|
61699628c8 | ||
|
|
e875e321f1 | ||
|
|
45570860d0 | ||
|
|
482e8a2b55 | ||
|
|
ed028542ed | ||
|
|
5bdd2111d0 | ||
|
|
2b20e4afac | ||
|
|
cb38df20dc | ||
|
|
d031b5def8 | ||
|
|
61957bee47 | ||
|
|
ce3905a29f | ||
|
|
efbafd9dc8 | ||
|
|
bab6db1fd9 | ||
|
|
252758b6a1 | ||
|
|
07be858d2a | ||
|
|
444f202360 | ||
|
|
955316a727 | ||
|
|
2c906384c3 | ||
|
|
5f00c007cb | ||
|
|
566faa17de | ||
|
|
2ea7a42e22 | ||
|
|
06216744ed | ||
|
|
889a306fc8 | ||
|
|
3f8f583964 | ||
|
|
01f461b20a | ||
|
|
9b9092b7fa | ||
|
|
9933fa334d | ||
|
|
08815946f6 | ||
|
|
fc553327c0 | ||
|
|
c0e1bfa8b4 | ||
|
|
abfd4b19a6 | ||
|
|
fe2fd812fa | ||
|
|
af51c69fbc | ||
|
|
97806831e2 | ||
|
|
7e817839f3 | ||
|
|
d265fa78c3 | ||
|
|
e6d979eefc | ||
|
|
2036c2aaae | ||
|
|
be17f6b08e | ||
|
|
5cca45d5f9 | ||
|
|
8f76ca05d9 | ||
|
|
f80ec2aa37 | ||
|
|
8c6b95ed16 | ||
|
|
ea10093422 | ||
|
|
e5fd6131fe | ||
|
|
8e8ff02b74 | ||
|
|
09fbc0ab86 | ||
|
|
40c425e400 | ||
|
|
7b94f4c99d | ||
|
|
3432049276 | ||
|
|
9bb3a05f0e | ||
|
|
dad3850264 | ||
|
|
d5b5f9f4fd | ||
|
|
2c31adb31d | ||
|
|
c5c4ed82ab | ||
|
|
c9f51acdc3 | ||
|
|
4e079d18bf | ||
|
|
0577ba8331 | ||
|
|
811f7d3f7e | ||
|
|
8d5e34635c | ||
|
|
5179738062 | ||
|
|
a093f82bb7 | ||
|
|
7fe05ff330 | ||
|
|
6b209e7489 | ||
|
|
3d2305f2e6 | ||
|
|
1c1771ef6c | ||
|
|
9ddb94c1f3 | ||
|
|
36e3009ff9 | ||
|
|
4f2655c28b | ||
|
|
4eca579a6e | ||
|
|
0dac042a10 | ||
|
|
af37d5f196 | ||
|
|
59beb93752 | ||
|
|
70143a96c5 | ||
|
|
2f6bdac60a | ||
|
|
80c20a186b | ||
|
|
ea295bd694 | ||
|
|
2d4bdb9fe0 | ||
|
|
3828b5827d | ||
|
|
8c3c5e53e3 | ||
|
|
498662e2e5 | ||
|
|
d4599b8b3f | ||
|
|
8cd3832e2b | ||
|
|
5a7cff26a5 | ||
|
|
2c6d312ec9 | ||
|
|
4e80a9128e | ||
|
|
24f82100f8 | ||
|
|
ca0cc39f5f | ||
|
|
3ab7855d1a | ||
|
|
cf692abe83 | ||
|
|
43689d3371 | ||
|
|
92b14f8ca9 | ||
|
|
a147563ac1 | ||
|
|
1163435e19 | ||
|
|
9d4c466c21 | ||
|
|
3f6ef7a40b | ||
|
|
e56e5a3929 | ||
|
|
830e76fecd | ||
|
|
028d9aa9ed | ||
|
|
b1c74747b6 | ||
|
|
e4590dad08 | ||
|
|
07bf5f443a | ||
|
|
8b61ed2e95 | ||
|
|
3977c5169b | ||
|
|
e42363c0f6 | ||
|
|
da8ce5f2e1 | ||
|
|
a17adf0601 | ||
|
|
ac49e24149 | ||
|
|
00ded4eb01 | ||
|
|
ef885d3b2a | ||
|
|
05b12e6c5e | ||
|
|
daa41473ab | ||
|
|
508bc7ca36 | ||
|
|
bfe634aa91 | ||
|
|
8d40b03ba3 | ||
|
|
5c91551ea7 | ||
|
|
4017af8492 | ||
|
|
c50ed69e79 | ||
|
|
1411ad11c1 | ||
|
|
48e8d2d21c | ||
|
|
70d9d808e5 | ||
|
|
ea7c87e5e7 | ||
|
|
355f183adb | ||
|
|
c4a1728a2d | ||
|
|
fb164bca55 | ||
|
|
fbbce95140 | ||
|
|
353362651f | ||
|
|
1d135dddf2 | ||
|
|
c331c9382f | ||
|
|
6446dbaacb | ||
|
|
c881fb8532 | ||
|
|
d1bd5569b3 | ||
|
|
118a9a9ca0 | ||
|
|
b6e4d26695 | ||
|
|
d01cbd7143 | ||
|
|
b6f8b2ab66 | ||
|
|
3633e8d7b8 | ||
|
|
7e20eda944 | ||
|
|
42300c98ab | ||
|
|
be568d37c0 | ||
|
|
573cbeac1e | ||
|
|
eb0734de19 | ||
|
|
1d4f294c3c | ||
|
|
e1a2d7255e | ||
|
|
2aa14db677 | ||
|
|
67bb8a6cb2 | ||
|
|
c8926d1457 | ||
|
|
e175f02715 | ||
|
|
4bcf37e2c0 | ||
|
|
62eec47ff1 | ||
|
|
8d7ddde5f1 | ||
|
|
32862ed9f8 | ||
|
|
85219514cf | ||
|
|
dd318f8243 | ||
|
|
b2ff00fb86 | ||
|
|
8292b1b5cd | ||
|
|
0d5a38d829 | ||
|
|
40ac04ca7a | ||
|
|
358df39b43 | ||
|
|
54fc164d3a | ||
|
|
42b85f76f7 | ||
|
|
b72af9dbfc | ||
|
|
f9a379d02c | ||
|
|
8ff6097e23 | ||
|
|
9779a2bf1a | ||
|
|
45b5c838a6 | ||
|
|
85f1963d52 | ||
|
|
28f088dc66 | ||
|
|
85cf298667 | ||
|
|
738b91ddb4 | ||
|
|
7bcc7c31d2 | ||
|
|
a62d8f2271 | ||
|
|
7675db7e92 | ||
|
|
67f1f0c7b5 | ||
|
|
f25ffaf2b2 | ||
|
|
0b64be2019 | ||
|
|
d23d61a932 | ||
|
|
5f698273c2 | ||
|
|
5812ef2b73 | ||
|
|
6f1641a5cc | ||
|
|
068c9f266e | ||
|
|
827057f560 | ||
|
|
c18e02387b | ||
|
|
1be7163408 | ||
|
|
800bc9308d | ||
|
|
e1466df54d | ||
|
|
194e3c5bc5 | ||
|
|
d1a16ce9d6 | ||
|
|
6e5c37be29 | ||
|
|
7d2bf8805d | ||
|
|
c2c19c5018 | ||
|
|
e8543de820 | ||
|
|
ba68ae8bd5 | ||
|
|
db87a2f375 | ||
|
|
5920b15ff5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -79,6 +79,7 @@ NOTES
|
|||||||
|
|
||||||
# coexist with quilt
|
# coexist with quilt
|
||||||
patches
|
patches
|
||||||
|
*.patch
|
||||||
|
|
||||||
# Eclipse stuff
|
# Eclipse stuff
|
||||||
.project
|
.project
|
||||||
@@ -88,5 +89,8 @@ patches
|
|||||||
# Emacs temp files
|
# Emacs temp files
|
||||||
*~
|
*~
|
||||||
|
|
||||||
|
# Emacs TAGS file
|
||||||
|
TAGS
|
||||||
|
|
||||||
# CScope database files
|
# CScope database files
|
||||||
*cscope.out
|
*cscope.out
|
||||||
|
|||||||
4
BUGS
4
BUGS
@@ -4,7 +4,7 @@
|
|||||||
Please report bugs by subscribing to the OpenOCD mailing list and
|
Please report bugs by subscribing to the OpenOCD mailing list and
|
||||||
posting a message with your report:
|
posting a message with your report:
|
||||||
|
|
||||||
openocd-development@lists.berlios.de
|
openocd-devel@lists.sourceforge.net
|
||||||
|
|
||||||
Also, please check the Trac bug database to see if a ticket for
|
Also, please check the Trac bug database to see if a ticket for
|
||||||
the bug has already been opened. You might be asked to open
|
the bug has already been opened. You might be asked to open
|
||||||
@@ -32,7 +32,7 @@ that may be important.
|
|||||||
http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html
|
http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html
|
||||||
|
|
||||||
If possible, please develop and attach a patch that helps to expose or
|
If possible, please develop and attach a patch that helps to expose or
|
||||||
solve the reported problem. See the PATCHES.txt file for information
|
solve the reported problem. See the HACKING file for information
|
||||||
about that process.
|
about that process.
|
||||||
|
|
||||||
Attach all files directly to your posting. The mailing list knows to
|
Attach all files directly to your posting. The mailing list knows to
|
||||||
|
|||||||
2
COPYING
2
COPYING
@@ -2,7 +2,7 @@
|
|||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|||||||
@@ -307,13 +307,13 @@ EXTRACT_PRIVATE = NO
|
|||||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||||
# will be included in the documentation.
|
# will be included in the documentation.
|
||||||
|
|
||||||
EXTRACT_STATIC = NO
|
EXTRACT_STATIC = YES
|
||||||
|
|
||||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||||
# defined locally in source files will be included in the documentation.
|
# defined locally in source files will be included in the documentation.
|
||||||
# If set to NO only classes defined in header files are included.
|
# If set to NO only classes defined in header files are included.
|
||||||
|
|
||||||
EXTRACT_LOCAL_CLASSES = NO
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
|
||||||
# This flag is only useful for Objective-C code. When set to YES local
|
# This flag is only useful for Objective-C code. When set to YES local
|
||||||
# methods, which are defined in the implementation section but not in
|
# methods, which are defined in the implementation section but not in
|
||||||
@@ -567,7 +567,7 @@ WARN_LOGFILE =
|
|||||||
INPUT = @srcdir@/doc/manual \
|
INPUT = @srcdir@/doc/manual \
|
||||||
@srcdir@/TODO \
|
@srcdir@/TODO \
|
||||||
@srcdir@/BUGS \
|
@srcdir@/BUGS \
|
||||||
@srcdir@/PATCHES.txt \
|
@srcdir@/HACKING \
|
||||||
@srcdir@/src \
|
@srcdir@/src \
|
||||||
@builddir@/config.h
|
@builddir@/config.h
|
||||||
|
|
||||||
|
|||||||
190
HACKING
190
HACKING
@@ -1,56 +1,178 @@
|
|||||||
Submitting patches to the OpenOCD mailing list:
|
// This file is part of the Doxygen Developer Manual
|
||||||
|
/** @page patchguide Patch Guidelines
|
||||||
|
|
||||||
By the time you have read this, one supposes that
|
\attention If you're behind a corporate wall with http only access to the
|
||||||
you have figured out how to clone the OpenOCD git
|
world, you can still use these instructions!
|
||||||
repository.
|
|
||||||
|
|
||||||
Below is a basic workflow and specific instructions
|
\attention You can't send patches to the mailing list anymore at all. Nowadays
|
||||||
to get you going with git and patches.
|
you are expected to send patches to the OpenOCD Gerrit GIT server for a
|
||||||
|
review.
|
||||||
|
|
||||||
0. Clone the git repository, rather than just
|
@section gerrit Submitting patches to the OpenOCD Gerrit server
|
||||||
download the source.
|
|
||||||
|
|
||||||
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
OpenOCD is to some extent a "self service" open source project, so to
|
||||||
|
contribute, you must follow the standard procedures to have the best
|
||||||
|
possible chance to get your changes accepted.
|
||||||
|
|
||||||
|
The procedure to create a patch is essentially:
|
||||||
|
|
||||||
|
- make the changes
|
||||||
|
- create a commit
|
||||||
|
- send the changes to the Gerrit server for review
|
||||||
|
- correct the patch and re-send it according to review feedback
|
||||||
|
|
||||||
|
Your patch (or commit) should be a "good patch": focus it on a single
|
||||||
|
issue, and make it be easily reviewable. Don't make
|
||||||
|
it so large that it's hard to review; split large
|
||||||
|
patches into smaller ones. (That can also help
|
||||||
|
track down bugs later on.) All patches should
|
||||||
|
be "clean", which includes preserving the existing
|
||||||
|
coding style and updating documentation as needed.
|
||||||
|
|
||||||
|
Say in the commit message if it's a bugfix (describe the bug) or a new
|
||||||
|
feature. Don't expect patches to merge immediately
|
||||||
|
for the next release. Be ready to rework patches
|
||||||
|
in response to feedback.
|
||||||
|
|
||||||
|
Add yourself to the GPL copyright for non-trivial changes.
|
||||||
|
|
||||||
|
@section stepbystep Step by step procedure
|
||||||
|
|
||||||
|
-# Create a Gerrit account at: http://openocd.zylin.com
|
||||||
|
- On subsequent sign ins, use the full URL prefaced with 'http://'
|
||||||
|
For example: http://user_identifier.open_id_provider.com
|
||||||
|
-# Add a username to your profile.
|
||||||
|
After creating the Gerrit account and signing in, you will need to
|
||||||
|
add a username to your profile. To do this, go to 'Settings', and
|
||||||
|
add a username of your choice.
|
||||||
|
Your username will be required in step 3 and substituted wherever
|
||||||
|
the string 'USERNAME' is found.
|
||||||
|
-# Create an SSH public key following the directions on github:
|
||||||
|
https://help.github.com/articles/generating-ssh-keys . You can skip step 3
|
||||||
|
(adding key to Github account) and 4 (testing) - these are useful only if
|
||||||
|
you actually use Github or want to test whether the new key works fine.
|
||||||
|
-# Add this new SSH key to your Gerrit account:
|
||||||
|
go to 'Settings' > 'SSH Public Keys', paste the contents of
|
||||||
|
~/.ssh/id_rsa.pub into the text field (if it's not visible click on
|
||||||
|
'Add Key ...' button) and confirm by clicking 'Add' button.
|
||||||
|
-# Clone the git repository, rather than just download the source:
|
||||||
|
@code
|
||||||
|
git clone git://git.code.sf.net/p/openocd/code openocd
|
||||||
|
@endcode
|
||||||
or if you have problems with the "git:" protocol, use
|
or if you have problems with the "git:" protocol, use
|
||||||
the slower http protocol:
|
the slower http protocol:
|
||||||
|
@code
|
||||||
git clone http://repo.or.cz/r/openocd.git
|
git clone http://git.code.sf.net/p/openocd/code openocd
|
||||||
|
@endcode
|
||||||
1. Set up git with your name and email:
|
-# Set up Gerrit with your local repository. All this does it
|
||||||
|
to instruct git locally how to send off the changes.
|
||||||
|
-# Add a new remote to git using Gerrit username:
|
||||||
|
@code
|
||||||
|
git remote add review ssh://USERNAME@openocd.zylin.com:29418/openocd.git
|
||||||
|
git config remote.review.push HEAD:refs/publish/master
|
||||||
|
@endcode
|
||||||
|
Or with http only:
|
||||||
|
@code
|
||||||
|
git remote add review http://USERNAME@openocd.zylin.com/p/openocd.git
|
||||||
|
git config remote.review.push HEAD:refs/publish/master
|
||||||
|
@endcode
|
||||||
|
The http password is configured from your gerrit settings - http://openocd.zylin.com/#/settings/http-password.
|
||||||
|
\note If you want to simplify http access you can also add your http password to the url as follows:
|
||||||
|
@code
|
||||||
|
git remote add review http://USERNAME:PASSWORD@openocd.zylin.com/p/openocd.git
|
||||||
|
@endcode
|
||||||
|
-# You will need to install this hook, we will look into a better solution:
|
||||||
|
@code
|
||||||
|
scp -p -P 29418 USERNAME@openocd.zylin.com:hooks/commit-msg .git/hooks/
|
||||||
|
@endcode
|
||||||
|
Or with http only:
|
||||||
|
@code
|
||||||
|
wget http://openocd.zylin.com/tools/hooks/commit-msg
|
||||||
|
mv commit-msg .git/hooks
|
||||||
|
chmod +x .git/hooks/commit-msg
|
||||||
|
@endcode
|
||||||
|
\note A script exists to simplify the two items above. execute:
|
||||||
|
@code
|
||||||
|
tools/initial.sh <username>
|
||||||
|
@endcode
|
||||||
|
With @<username@> being your Gerrit username.
|
||||||
|
-# Set up git with your name and email:
|
||||||
|
@code
|
||||||
git config --global user.name "John Smith"
|
git config --global user.name "John Smith"
|
||||||
git config --global user.email "john@smith.org"
|
git config --global user.email "john@smith.org"
|
||||||
|
@endcode
|
||||||
2. Work on your patches. Split the work into
|
-# Work on your patches. Split the work into
|
||||||
multiple small patches that can be reviewed and
|
multiple small patches that can be reviewed and
|
||||||
applied seperately and safely to the OpenOCD
|
applied seperately and safely to the OpenOCD
|
||||||
repository.
|
repository.
|
||||||
|
@code
|
||||||
while(!done) {
|
while(!done) {
|
||||||
work - edit files using your favorite editor.
|
work - edit files using your favorite editor.
|
||||||
run "git commit -a" to commit all changes.
|
run "git commit -s -a" to commit all changes.
|
||||||
|
run tools/checkpatch.sh to verify your patch style is ok.
|
||||||
}
|
}
|
||||||
|
@endcode
|
||||||
|
\note use "git add ." before commit to add new files.
|
||||||
|
|
||||||
TIP! use "git add ." before commit to add new files.
|
Comment template, notice the short first line w/topic. The topic field
|
||||||
|
should identify the main part or subsystem the patch touches. Check
|
||||||
--- example comment, notice the short first line w/topic ---
|
git log for examples.
|
||||||
topic: short comment
|
@code
|
||||||
|
topic: Short comment
|
||||||
<blank line>
|
<blank line>
|
||||||
longer comments over several
|
Longer comments over several lines, explaining (where applicable) the
|
||||||
lines...
|
reason for the patch and the general idea the solution is based on,
|
||||||
-----
|
any major design decisions, etc...
|
||||||
|
<blank line>
|
||||||
3. Next you need to make sure that your patches
|
Signed-off-by: ...
|
||||||
|
@endcode
|
||||||
|
-# Next you need to make sure that your patches
|
||||||
are on top of the latest stuff on the server and
|
are on top of the latest stuff on the server and
|
||||||
that there are no conflicts.
|
that there are no conflicts:
|
||||||
|
@code
|
||||||
|
git pull --rebase origin master
|
||||||
|
@endcode
|
||||||
|
-# Send the patches to the Gerrit server for review:
|
||||||
|
@code
|
||||||
|
git push review
|
||||||
|
@endcode
|
||||||
|
-# Forgot something, want to add more? Just make the changes and do:
|
||||||
|
@code
|
||||||
|
git commit --amend
|
||||||
|
git push review
|
||||||
|
@endcode
|
||||||
|
|
||||||
git pull --rebase
|
Further reading: http://www.coreboot.org/Git
|
||||||
|
|
||||||
4. Generate the patch files. This will generate
|
@section timeline When can I expect my contribution to be committed?
|
||||||
patches for all commits that are on top of
|
|
||||||
the latest stuff on the server:
|
|
||||||
|
|
||||||
git format-patch origin/master
|
The code review is intended to take as long as a week or two to allow
|
||||||
|
maintainers and contributors who work on OpenOCD only in their spare
|
||||||
|
time oportunity to perform a review and raise objections.
|
||||||
|
|
||||||
5. Email the patches to openocd-development@lists.berlios.de
|
With Gerrit much of the urgency of getting things committed has been
|
||||||
|
removed as the work in progress is safely stored in Gerrit and
|
||||||
|
available if someone needs to build on your work before it is
|
||||||
|
submitted to the official repository.
|
||||||
|
|
||||||
|
Another factor that contributes to the desire for longer cool-off
|
||||||
|
times (the time a patch lies around without any further changes or
|
||||||
|
comments), it means that the chances of quality regression on the
|
||||||
|
master branch will be much reduced.
|
||||||
|
|
||||||
|
If a contributor pushes a patch, it is considered good form if another
|
||||||
|
contributor actually approves and submits that patch.
|
||||||
|
|
||||||
|
It should be noted that a negative review in Gerrit ("-1" or "-2") may (but does
|
||||||
|
not have to) be disregarded if all conditions listed below are met:
|
||||||
|
|
||||||
|
- the concerns raised in the review have been addressed (or explained),
|
||||||
|
- reviewer does not re-examine the change in a month,
|
||||||
|
- reviewer does not answer e-mails for another month.
|
||||||
|
|
||||||
|
@section browsing Browsing Patches
|
||||||
|
All OpenOCD patches can be reviewed <a href="http://openocd.zylin.com/">here</a>.
|
||||||
|
*/
|
||||||
|
/** @file
|
||||||
|
This file contains the @ref patchguide page.
|
||||||
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
AUTOMAKE_OPTIONS = gnu 1.6
|
AUTOMAKE_OPTIONS = gnu 1.6
|
||||||
|
|
||||||
# make sure we pass the correct jimtcl flags to distcheck
|
# make sure we pass the correct jimtcl flags to distcheck
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --with-jim-ext=nvp --disable-lineedit --disable-install-jim
|
DISTCHECK_CONFIGURE_FLAGS = --disable-install-jim
|
||||||
|
|
||||||
nobase_dist_pkgdata_DATA = \
|
nobase_dist_pkgdata_DATA = \
|
||||||
contrib/libdcc/dcc_stdio.c \
|
contrib/libdcc/dcc_stdio.c \
|
||||||
@@ -24,7 +24,6 @@ EXTRA_DIST = \
|
|||||||
BUGS \
|
BUGS \
|
||||||
HACKING \
|
HACKING \
|
||||||
NEWTAPS \
|
NEWTAPS \
|
||||||
PATCHES.txt \
|
|
||||||
README.Win32 \
|
README.Win32 \
|
||||||
Doxyfile.in \
|
Doxyfile.in \
|
||||||
tools/logger.pl \
|
tools/logger.pl \
|
||||||
@@ -64,7 +63,7 @@ $(THE_MANUAL): %.pdf: %.tex
|
|||||||
|
|
||||||
TCL_PATH = tcl
|
TCL_PATH = tcl
|
||||||
# command to find paths of script files, relative to TCL_PATH
|
# command to find paths of script files, relative to TCL_PATH
|
||||||
TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' | \
|
TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' -o -name '*.txt' | \
|
||||||
sed -e 's,^$(srcdir)/$(TCL_PATH),,'
|
sed -e 's,^$(srcdir)/$(TCL_PATH),,'
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
|
|||||||
65
NEWS
65
NEWS
@@ -1,63 +1,33 @@
|
|||||||
This file includes highlights of the changes made in the
|
This file includes highlights of the changes made in the
|
||||||
OpenOCD 0.5.0 source archive release. See the repository
|
OpenOCD source archive release. See the
|
||||||
history for details about what changed, including bugfixes
|
repository history for details about what changed, including
|
||||||
and other issues not mentioned here.
|
bugfixes and other issues not mentioned here.
|
||||||
|
|
||||||
JTAG Layer:
|
JTAG Layer:
|
||||||
New driver for "Bus Pirate"
|
New TI ICDI adapter support.
|
||||||
Rename various commands so they're not JTAG-specific
|
Support Latest OSBDM firmware.
|
||||||
There are migration procedures for most of these, but you should
|
Improved MIPS EJTAG Support.
|
||||||
convert your scripts to the new names, since those procedures
|
|
||||||
will not be around forever.
|
|
||||||
jtag jinterface ... is now adapter_name
|
|
||||||
jtag_khz ... is now adapter_khz
|
|
||||||
jtag_nsrst_delay ... is now adapter_nsrst_delay
|
|
||||||
jtag_nsrst_assert_width ... is now adapter_nsrst_assert_width
|
|
||||||
Support Voipac VPACLink JTAG Adapter.
|
|
||||||
|
|
||||||
Boundary Scan:
|
Boundary Scan:
|
||||||
|
|
||||||
Transport framework core ... supporting future work for SWD, SPI, and other
|
|
||||||
non-JTAG ways to debug targets or program flash.
|
|
||||||
|
|
||||||
Target Layer:
|
Target Layer:
|
||||||
ARM:
|
New ARMv7R and Cortex-R4 support.
|
||||||
- basic semihosting support for ARMv7M.
|
Added ChibiOS/RT support.
|
||||||
- renamed "armv7m" command prefix as "arm"
|
|
||||||
MIPS:
|
|
||||||
- "ejtag_srst" variant removed. The same functionality is
|
|
||||||
obtained by using "reset_config none".
|
|
||||||
- added PIC32MX software reset support, this means srst is not
|
|
||||||
required to be connected anymore.
|
|
||||||
OTHER:
|
|
||||||
- preliminary AVR32 AP7000 support.
|
|
||||||
|
|
||||||
Flash Layer:
|
Flash Layer:
|
||||||
New "stellaris recover" command, implements the procedure
|
New NXP LPC1850 support.
|
||||||
to recover locked devices (restoring non-volatile
|
New NXP LPC4300 support.
|
||||||
state to the factory defaults, including erasing
|
New NXP SPIFI support.
|
||||||
the flash and its protection bits, and possibly
|
New Energy Micro EFM32 support.
|
||||||
re-enabling hardware debugging).
|
New ST STM32W support.
|
||||||
PIC32MX now uses algorithm for flash programming, this
|
New ST STM32f2 write protection and lock/unlock support.
|
||||||
has increased the performance by approx 96%.
|
Ability to override STM32 flash bank size.
|
||||||
New 'pic32mx unlock' cmd to remove readout protection.
|
|
||||||
New STM32 Value Line Support.
|
|
||||||
New 'virtual' flash driver, used to associate other addresses
|
|
||||||
with a flash bank. See pic32mx.cfg for usage.
|
|
||||||
New iMX27 NAND flash controller driver.
|
|
||||||
|
|
||||||
Board, Target, and Interface Configuration Scripts:
|
Board, Target, and Interface Configuration Scripts:
|
||||||
Support IAR LPC1768 kickstart board (by Olimex)
|
Support Freescale i.MX6 series targets.
|
||||||
Support Voipac PXA270/PXA270M module.
|
|
||||||
New $PARPORTADDR tcl variable used to change default
|
|
||||||
parallel port address used.
|
|
||||||
Remove lm3s811.cfg; use "stellaris.cfg" instead
|
|
||||||
|
|
||||||
Core Jim/TCL Scripting:
|
|
||||||
New "add_script_search_dir" command, behaviour is the same
|
|
||||||
as the "-s" cmd line option.
|
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
|
New MIPS debugging info.
|
||||||
|
|
||||||
Build and Release:
|
Build and Release:
|
||||||
|
|
||||||
@@ -71,4 +41,3 @@ For older NEWS, see the NEWS files associated with each release
|
|||||||
For more information about contributing test reports, bug fixes, or new
|
For more information about contributing test reports, bug fixes, or new
|
||||||
features and device support, please read the new Developer Manual (or
|
features and device support, please read the new Developer Manual (or
|
||||||
the BUGS and PATCHES.txt files in the source archive).
|
the BUGS and PATCHES.txt files in the source archive).
|
||||||
|
|
||||||
|
|||||||
74
NEWS-0.5.0
Normal file
74
NEWS-0.5.0
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
This file includes highlights of the changes made in the
|
||||||
|
OpenOCD 0.5.0 source archive release. See the repository
|
||||||
|
history for details about what changed, including bugfixes
|
||||||
|
and other issues not mentioned here.
|
||||||
|
|
||||||
|
JTAG Layer:
|
||||||
|
New driver for "Bus Pirate"
|
||||||
|
Rename various commands so they're not JTAG-specific
|
||||||
|
There are migration procedures for most of these, but you should
|
||||||
|
convert your scripts to the new names, since those procedures
|
||||||
|
will not be around forever.
|
||||||
|
jtag jinterface ... is now adapter_name
|
||||||
|
jtag_khz ... is now adapter_khz
|
||||||
|
jtag_nsrst_delay ... is now adapter_nsrst_delay
|
||||||
|
jtag_nsrst_assert_width ... is now adapter_nsrst_assert_width
|
||||||
|
Support Voipac VPACLink JTAG Adapter.
|
||||||
|
|
||||||
|
Boundary Scan:
|
||||||
|
|
||||||
|
Transport framework core ... supporting future work for SWD, SPI, and other
|
||||||
|
non-JTAG ways to debug targets or program flash.
|
||||||
|
|
||||||
|
Target Layer:
|
||||||
|
ARM:
|
||||||
|
- basic semihosting support for ARMv7M.
|
||||||
|
- renamed "armv7m" command prefix as "arm"
|
||||||
|
MIPS:
|
||||||
|
- "ejtag_srst" variant removed. The same functionality is
|
||||||
|
obtained by using "reset_config none".
|
||||||
|
- added PIC32MX software reset support, this means srst is not
|
||||||
|
required to be connected anymore.
|
||||||
|
OTHER:
|
||||||
|
- preliminary AVR32 AP7000 support.
|
||||||
|
|
||||||
|
Flash Layer:
|
||||||
|
New "stellaris recover" command, implements the procedure
|
||||||
|
to recover locked devices (restoring non-volatile
|
||||||
|
state to the factory defaults, including erasing
|
||||||
|
the flash and its protection bits, and possibly
|
||||||
|
re-enabling hardware debugging).
|
||||||
|
PIC32MX now uses algorithm for flash programming, this
|
||||||
|
has increased the performance by approx 96%.
|
||||||
|
New 'pic32mx unlock' cmd to remove readout protection.
|
||||||
|
New STM32 Value Line Support.
|
||||||
|
New 'virtual' flash driver, used to associate other addresses
|
||||||
|
with a flash bank. See pic32mx.cfg for usage.
|
||||||
|
New iMX27 NAND flash controller driver.
|
||||||
|
|
||||||
|
Board, Target, and Interface Configuration Scripts:
|
||||||
|
Support IAR LPC1768 kickstart board (by Olimex)
|
||||||
|
Support Voipac PXA270/PXA270M module.
|
||||||
|
New $PARPORTADDR tcl variable used to change default
|
||||||
|
parallel port address used.
|
||||||
|
Remove lm3s811.cfg; use "stellaris.cfg" instead
|
||||||
|
|
||||||
|
Core Jim/TCL Scripting:
|
||||||
|
New "add_script_search_dir" command, behaviour is the same
|
||||||
|
as the "-s" cmd line option.
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
Build and Release:
|
||||||
|
|
||||||
|
For more details about what has changed since the last release,
|
||||||
|
see the git repository history. With gitweb, you can browse that
|
||||||
|
in various levels of detail.
|
||||||
|
|
||||||
|
For older NEWS, see the NEWS files associated with each release
|
||||||
|
(i.e. NEWS-<version>).
|
||||||
|
|
||||||
|
For more information about contributing test reports, bug fixes, or new
|
||||||
|
features and device support, please read the new Developer Manual (or
|
||||||
|
the BUGS and PATCHES.txt files in the source archive).
|
||||||
|
|
||||||
54
NEWS-0.6.0
Normal file
54
NEWS-0.6.0
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
This file includes highlights of the changes made in the
|
||||||
|
OpenOCD source archive release. See the
|
||||||
|
repository history for details about what changed, including
|
||||||
|
bugfixes and other issues not mentioned here.
|
||||||
|
|
||||||
|
JTAG Layer:
|
||||||
|
New STLINK V1/V2 JTAG/SWD adapter support.
|
||||||
|
New OSJTAG adapter support.
|
||||||
|
New Tincantools Flyswatter2 support.
|
||||||
|
Improved ULINK driver.
|
||||||
|
Improved RLINK driver.
|
||||||
|
Support for adapters based on FT232H chips.
|
||||||
|
New experimental driver for FTDI based adapters, using libusb-1.0 in asynchronous mode.
|
||||||
|
|
||||||
|
Boundary Scan:
|
||||||
|
|
||||||
|
Target Layer:
|
||||||
|
New Cortex-M0 support.
|
||||||
|
New Cortex-M4 support.
|
||||||
|
Improved Working area algorithm.
|
||||||
|
New RTOS support. Currently linux, FreeRTOS, ThreadX and eCos.
|
||||||
|
Connecting under reset to Cortex-Mx and MIPS chips.
|
||||||
|
|
||||||
|
Flash Layer:
|
||||||
|
New SST39WF1601 support.
|
||||||
|
New EN29LV800BB support.
|
||||||
|
New async algorithm support for selected targets, stm32, stellaris and pic32.
|
||||||
|
New Atmel SAM3S, SAM3N support.
|
||||||
|
New ST STM32L support.
|
||||||
|
New Microchip PIC32MX1xx/2xx support.
|
||||||
|
New Freescale Kinetis K40 support.
|
||||||
|
|
||||||
|
Board, Target, and Interface Configuration Scripts:
|
||||||
|
Support Dangerous Prototypes Bus Blaster.
|
||||||
|
Support ST SPEAr Family.
|
||||||
|
Support Gumstix Verdex boards.
|
||||||
|
Support TI Beaglebone.
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
Improved HACKING info for submitting patches.
|
||||||
|
Fixed numerous broken links.
|
||||||
|
|
||||||
|
Build and Release:
|
||||||
|
|
||||||
|
For more details about what has changed since the last release,
|
||||||
|
see the git repository history. With gitweb, you can browse that
|
||||||
|
in various levels of detail.
|
||||||
|
|
||||||
|
For older NEWS, see the NEWS files associated with each release
|
||||||
|
(i.e. NEWS-<version>).
|
||||||
|
|
||||||
|
For more information about contributing test reports, bug fixes, or new
|
||||||
|
features and device support, please read the new Developer Manual (or
|
||||||
|
the BUGS and PATCHES.txt files in the source archive).
|
||||||
2
NEWTAPS
2
NEWTAPS
@@ -4,7 +4,7 @@ Reporting Unknown JTAG TAP IDS
|
|||||||
If OpenOCD reports an UNKNOWN or Unexpected Tap ID please report it to
|
If OpenOCD reports an UNKNOWN or Unexpected Tap ID please report it to
|
||||||
the development mailing list - However - keep reading.
|
the development mailing list - However - keep reading.
|
||||||
|
|
||||||
openocd-development@lists.berlios.de.
|
openocd-devel@lists.sourceforge.net.
|
||||||
|
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
|
|||||||
47
PATCHES.txt
47
PATCHES.txt
@@ -1,47 +0,0 @@
|
|||||||
// This file is part of the Doxygen Developer Manual
|
|
||||||
/** @page patchguide Patch Guidelines
|
|
||||||
|
|
||||||
Please mail patches to: @par
|
|
||||||
openocd-development@lists.berlios.de
|
|
||||||
|
|
||||||
Note that you can't send patches to that list unless
|
|
||||||
you're a member, despite what the list info page says.
|
|
||||||
|
|
||||||
@section Patch Guidelines in a Nutshell
|
|
||||||
|
|
||||||
Your patches should be against git mainline. Submit output
|
|
||||||
of "git diff"; equivalently, quilt patches are OK.
|
|
||||||
|
|
||||||
It should be a "good patch": focus it on a single
|
|
||||||
issue, and make it be easily reviewable. Don't make
|
|
||||||
it so large that it's hard to review; split large
|
|
||||||
patches into smaller ones. (That can also help
|
|
||||||
track down bugs later on.) All patches should
|
|
||||||
be "clean", which includes preserving the existing
|
|
||||||
coding style and updating documentation as needed.j
|
|
||||||
|
|
||||||
Attach the patch to the email as a .txt file and
|
|
||||||
also write a short change log entry that maintainers
|
|
||||||
can copy and paste into the commit message
|
|
||||||
|
|
||||||
Say if it's a bugfix (describe the bug) or a new
|
|
||||||
feature. Don't expect patches to merge immediately
|
|
||||||
for the next release. Be ready to rework patches
|
|
||||||
in response to feedback.
|
|
||||||
|
|
||||||
Add yourself to the GPL copyright for non-trivial changes.
|
|
||||||
|
|
||||||
To create a patch from the command line:
|
|
||||||
@code
|
|
||||||
git diff >mypatch.txt
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@section More Information on Patching
|
|
||||||
|
|
||||||
The @ref primerpatches provides a more complete guide to creating,
|
|
||||||
managing, and contributing patches to the OpenOCD project.
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** @file
|
|
||||||
This file contains the @ref patchguide page.
|
|
||||||
*/
|
|
||||||
84
README
84
README
@@ -23,10 +23,10 @@ In addition to in-tree documentation, the latest documentation may be
|
|||||||
viewed on-line at the following URLs:
|
viewed on-line at the following URLs:
|
||||||
|
|
||||||
OpenOCD User's Guide:
|
OpenOCD User's Guide:
|
||||||
http://openocd.berlios.de/doc/html/index.html
|
http://openocd.sourceforge.net/doc/html/index.html
|
||||||
|
|
||||||
OpenOCD Developer's Manual:
|
OpenOCD Developer's Manual:
|
||||||
http://openocd.berlios.de/doc/doxygen/index.html
|
http://openocd.sourceforge.net/doc/doxygen/html/index.html
|
||||||
|
|
||||||
These reflect the latest development versions, so the following section
|
These reflect the latest development versions, so the following section
|
||||||
introduces how to build the complete documentation from the package.
|
introduces how to build the complete documentation from the package.
|
||||||
@@ -35,7 +35,7 @@ introduces how to build the complete documentation from the package.
|
|||||||
For more information, refer to these documents or contact the developers
|
For more information, refer to these documents or contact the developers
|
||||||
by subscribing to the OpenOCD developer mailing list:
|
by subscribing to the OpenOCD developer mailing list:
|
||||||
|
|
||||||
openocd-development@lists.berlios.de
|
openocd-devel@lists.sourceforge.net
|
||||||
|
|
||||||
Building the OpenOCD Documentation
|
Building the OpenOCD Documentation
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@@ -210,53 +210,90 @@ options may be available there:
|
|||||||
|
|
||||||
--enable-dummy Enable building the dummy JTAG port driver
|
--enable-dummy Enable building the dummy JTAG port driver
|
||||||
|
|
||||||
|
--enable-parport Enable building the pc parallel port driver
|
||||||
|
--disable-parport-ppdev Disable use of ppdev (/dev/parportN) for parport
|
||||||
|
(for x86 only)
|
||||||
|
--enable-parport-giveio Enable use of giveio for parport (for CygWin only)
|
||||||
|
|
||||||
|
--enable-ftdi Enable building support for the MPSSE mode of FTDI
|
||||||
|
based devices, using libusb-1.0 in asynchronous mode
|
||||||
|
|
||||||
--enable-ft2232_libftdi Enable building support for FT2232 based devices
|
--enable-ft2232_libftdi Enable building support for FT2232 based devices
|
||||||
using the libftdi driver, opensource alternate of
|
using the libftdi driver, opensource alternate of
|
||||||
FTD2XX
|
FTD2XX
|
||||||
--enable-ft2232_ftd2xx Enable building support for FT2232 based devices
|
--enable-ft2232_ftd2xx Enable building support for FT2232 based devices
|
||||||
using the FTD2XX driver from ftdichip.com
|
using the FTD2XX driver from ftdichip.com
|
||||||
|
|
||||||
|
--enable-usb_blaster_libftdi
|
||||||
|
Enable building support for the Altera USB-Blaster
|
||||||
|
using the libftdi driver, opensource alternate of
|
||||||
|
FTD2XX
|
||||||
|
--enable-usb_blaster_ftd2xx
|
||||||
|
Enable building support for the Altera USB-Blaster
|
||||||
|
using the FTD2XX driver from ftdichip.com
|
||||||
|
|
||||||
|
--enable-amtjtagaccel Enable building the Amontec JTAG-Accelerator driver
|
||||||
|
|
||||||
|
--enable-zy1000-master Use ZY1000 JTAG master registers
|
||||||
|
--enable-zy1000 Enable ZY1000 interface
|
||||||
|
|
||||||
|
--enable-ioutil Enable ioutil functions - useful for standalone
|
||||||
|
OpenOCD implementations
|
||||||
|
|
||||||
|
--enable-ep93xx Enable building support for EP93xx based SBCs
|
||||||
|
|
||||||
|
--enable-at91rm9200 Enable building support for AT91RM9200 based SBCs
|
||||||
|
|
||||||
--enable-gw16012 Enable building support for the Gateworks GW16012
|
--enable-gw16012 Enable building support for the Gateworks GW16012
|
||||||
JTAG Programmer
|
JTAG Programmer
|
||||||
|
|
||||||
--enable-parport Enable building the pc parallel port driver
|
|
||||||
--disable-parport-ppdev Disable use of ppdev (/dev/parportN) for parport
|
|
||||||
(for x86 only)
|
|
||||||
--enable-parport-giveio Enable use of giveio for parport (for CygWin only)
|
|
||||||
|
|
||||||
--enable-presto_libftdi Enable building support for ASIX Presto Programmer
|
--enable-presto_libftdi Enable building support for ASIX Presto Programmer
|
||||||
using the libftdi driver
|
using the libftdi driver
|
||||||
--enable-presto_ftd2xx Enable building support for ASIX Presto Programmer
|
--enable-presto_ftd2xx Enable building support for ASIX Presto Programmer
|
||||||
using the FTD2XX driver
|
using the FTD2XX driver
|
||||||
|
|
||||||
--enable-amtjtagaccel Enable building the Amontec JTAG-Accelerator driver
|
--enable-usbprog Enable building support for the usbprog JTAG
|
||||||
--enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW
|
|
||||||
Programmer
|
Programmer
|
||||||
|
|
||||||
|
--enable-oocd_trace Enable building support for some prototype
|
||||||
|
OpenOCD+trace ETM capture hardware
|
||||||
|
|
||||||
--enable-jlink Enable building support for the Segger J-Link JTAG
|
--enable-jlink Enable building support for the Segger J-Link JTAG
|
||||||
Programmer
|
Programmer
|
||||||
|
|
||||||
|
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
||||||
|
Programmer
|
||||||
|
|
||||||
--enable-rlink Enable building support for the Raisonance RLink
|
--enable-rlink Enable building support for the Raisonance RLink
|
||||||
JTAG Programmer
|
JTAG Programmer
|
||||||
--enable-ulink Enable building support for the Keil ULINK JTAG
|
--enable-ulink Enable building support for the Keil ULINK JTAG
|
||||||
Programmer
|
Programmer
|
||||||
--enable-usbprog Enable building support for the usbprog JTAG
|
--enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW
|
||||||
Programmer
|
|
||||||
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
|
||||||
Programmer
|
Programmer
|
||||||
|
|
||||||
--enable-oocd_trace Enable building support for the OpenOCD+trace ETM
|
--enable-buspirate Enable building support for the Buspirate
|
||||||
capture device
|
|
||||||
|
|
||||||
--enable-ep93xx Enable building support for EP93xx based SBCs
|
--enable-stlink Enable building support for the ST-Link JTAG
|
||||||
--enable-at91rm9200 Enable building support for AT91RM9200 based SBCs
|
Programmer
|
||||||
|
--enable-ti-icdi Enable building support for the TI/Stellaris ICDI
|
||||||
|
JTAG Programmer
|
||||||
|
|
||||||
--enable-ecosboard Enable building support for eCos based JTAG debugger
|
--enable-osbdm Enable building support for the OSBDM (JTAG only)
|
||||||
--enable-zy1000 Enable ZY1000 interface
|
Programmer
|
||||||
|
|
||||||
|
--enable-opendous Enable building support for the estick/opendous JTAG
|
||||||
|
Programmer
|
||||||
|
--enable-sysfsgpio Enable building support for programming driven via
|
||||||
|
sysfs gpios.
|
||||||
|
|
||||||
--enable-minidriver-dummy
|
--enable-minidriver-dummy
|
||||||
Enable the dummy minidriver.
|
Enable the dummy minidriver.
|
||||||
|
|
||||||
--enable-ioutil Enable ioutil functions - useful for standalone
|
--disable-internal-jimtcl
|
||||||
OpenOCD implementations
|
Disable building internal jimtcl
|
||||||
|
--enable-libusb0 Use libusb-0.1 library for USB JTAG devices
|
||||||
|
--enable-remote-bitbang Enable building support for the Remote Bitbang jtag
|
||||||
|
driver
|
||||||
|
|
||||||
--disable-doxygen-html Disable building Doxygen manual as HTML.
|
--disable-doxygen-html Disable building Doxygen manual as HTML.
|
||||||
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
|
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
|
||||||
@@ -386,7 +423,7 @@ Obtaining OpenOCD From GIT
|
|||||||
You can download the current GIT version with a GIT client of your
|
You can download the current GIT version with a GIT client of your
|
||||||
choice from the main repository:
|
choice from the main repository:
|
||||||
|
|
||||||
git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
git://git.code.sf.net/p/openocd/code
|
||||||
|
|
||||||
You may prefer to use a mirror:
|
You may prefer to use a mirror:
|
||||||
|
|
||||||
@@ -397,7 +434,7 @@ Using the GIT command line client, you might use the following command
|
|||||||
to set up a local copy of the current repository (make sure there is no
|
to set up a local copy of the current repository (make sure there is no
|
||||||
directory called "openocd" in the current directory):
|
directory called "openocd" in the current directory):
|
||||||
|
|
||||||
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
git clone git://git.code.sf.net/p/openocd/code openocd
|
||||||
|
|
||||||
Then you can update that at your convenience using
|
Then you can update that at your convenience using
|
||||||
|
|
||||||
@@ -406,7 +443,6 @@ Then you can update that at your convenience using
|
|||||||
There is also a gitweb interface, which you can use either to browse
|
There is also a gitweb interface, which you can use either to browse
|
||||||
the repository or to download arbitrary snapshots using HTTP:
|
the repository or to download arbitrary snapshots using HTTP:
|
||||||
|
|
||||||
http://openocd.git.sourceforge.net/git/gitweb.cgi?p=openocd/openocd
|
|
||||||
http://repo.or.cz/w/openocd.git
|
http://repo.or.cz/w/openocd.git
|
||||||
|
|
||||||
Snapshots are compressed tarballs of the source tree, about 1.3 MBytes
|
Snapshots are compressed tarballs of the source tree, about 1.3 MBytes
|
||||||
|
|||||||
1
TODO
1
TODO
@@ -214,7 +214,6 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
|
|||||||
|
|
||||||
- finish documentation for the following flash drivers:
|
- finish documentation for the following flash drivers:
|
||||||
- avr
|
- avr
|
||||||
- ecosflash
|
|
||||||
- pic32mx
|
- pic32mx
|
||||||
- ocl
|
- ocl
|
||||||
- str9xpec
|
- str9xpec
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# common flags used in openocd build
|
# common flags used in openocd build
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src \
|
AM_CPPFLAGS = -I$(top_srcdir)/src \
|
||||||
-I$(top_builddir)/src \
|
-I$(top_builddir)/src \
|
||||||
|
-I$(top_srcdir)/src/helper \
|
||||||
-DPKGDATADIR=\"$(pkgdatadir)\" \
|
-DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||||
-DPKGLIBDIR=\"$(pkglibdir)\"
|
-DPKGLIBDIR=\"$(pkglibdir)\"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,13 +7,13 @@ $comment = "// Autogenerated by contrib/gen-stellaris-part-header.pl
|
|||||||
// From Stellaris Firmware Development Package revision";
|
// From Stellaris Firmware Development Package revision";
|
||||||
|
|
||||||
$struct_header = "static struct {
|
$struct_header = "static struct {
|
||||||
uint32_t partno;
|
uint8_t class;
|
||||||
|
uint8_t partno;
|
||||||
const char *partname;
|
const char *partname;
|
||||||
} StellarisParts[] =
|
} StellarisParts[] = {
|
||||||
{
|
|
||||||
";
|
";
|
||||||
|
|
||||||
$struct_footer = "\t{0,\"Unknown part\"}\n};\n";
|
$struct_footer = "\t{0xFF, 0x00, \"Unknown Part\"}\n};\n";
|
||||||
|
|
||||||
$#ARGV == 1 || die "Usage: $0 <inc directory> <output file>\n";
|
$#ARGV == 1 || die "Usage: $0 <inc directory> <output file>\n";
|
||||||
-d $ARGV[0] || die $ARGV[0]." is not a directory\n";
|
-d $ARGV[0] || die $ARGV[0]." is not a directory\n";
|
||||||
@@ -26,13 +26,11 @@ opendir(DIR, $dir) || die "can't open $dir: $!";
|
|||||||
@files = readdir(DIR);
|
@files = readdir(DIR);
|
||||||
closedir(DIR);
|
closedir(DIR);
|
||||||
|
|
||||||
@short_files = sort(grep(/lm3s...\.h/, @files));
|
@header_files = sort(grep(/lm.+\.h/, @files));
|
||||||
@long_files = sort(grep(/lm3s....\.h/, @files));
|
|
||||||
|
|
||||||
$ver = 0;
|
$ver = 0;
|
||||||
$new_struct = $struct_header;
|
$new_struct = $struct_header;
|
||||||
process_file(@short_files);
|
process_file(@header_files);
|
||||||
process_file(@long_files);
|
|
||||||
$new_struct .= $struct_footer;
|
$new_struct .= $struct_footer;
|
||||||
|
|
||||||
$dump = "$comment $ver\n$new_struct";
|
$dump = "$comment $ver\n$new_struct";
|
||||||
@@ -51,7 +49,7 @@ close(OUTPUT);
|
|||||||
|
|
||||||
sub process_file {
|
sub process_file {
|
||||||
foreach $h_file (@_) {
|
foreach $h_file (@_) {
|
||||||
($base) = ($h_file =~ m/lm3s(.{3,4})\.h/ig);
|
($base) = ($h_file =~ m/lm..(.{3,7})\.h/ig);
|
||||||
$base = uc($base);
|
$base = uc($base);
|
||||||
local($/, *FILE);
|
local($/, *FILE);
|
||||||
open(FILE, "$dir/$h_file");
|
open(FILE, "$dir/$h_file");
|
||||||
@@ -66,22 +64,39 @@ sub process_file {
|
|||||||
$ver = $1;
|
$ver = $1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($content =~ /SYSCTL_DID1_VER_[^M]\s+0x(\S+)/) {
|
|
||||||
$did1_ver = hex($1);
|
if ($content =~ /SYSCTL_DID0_CLASS_[^M].+?0x(\S+)/s) {
|
||||||
|
$class = hex($1) >> 16;
|
||||||
} else {
|
} else {
|
||||||
print STDERR "$h_file is missing SYSCTL_DID1_VER\n";
|
# attempt another way to get class
|
||||||
$did1_ver = 255;
|
if ($content =~ /\s(\S+)-class/) {
|
||||||
|
$class = getclass($1);
|
||||||
|
if ($class eq 0xFF) {
|
||||||
|
print STDERR "$h_file unknown class\n";
|
||||||
$invalid = 1;
|
$invalid = 1;
|
||||||
}
|
}
|
||||||
if ($content =~ /SYSCTL_DID1_PRTNO_$base\s+0x(\S+)/) {
|
} else {
|
||||||
|
print STDERR "$h_file is missing SYSCTL_DID0_CLASS_\n";
|
||||||
|
$class = 0;
|
||||||
|
$invalid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($content =~ /SYSCTL_DID1_PRTNO_$base.+0x(\S+)/) {
|
||||||
$prtno = hex($1);
|
$prtno = hex($1);
|
||||||
|
$base = "LM3S" . $base;
|
||||||
|
} else {
|
||||||
|
# LM4F have a changed header
|
||||||
|
if ($content =~ /SYSCTL_DID1_PRTNO_LM4F$base.+?0x(\S+)/s) {
|
||||||
|
$prtno = hex($1);
|
||||||
|
$base = "LM4F" . $base;
|
||||||
} else {
|
} else {
|
||||||
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
|
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
|
||||||
$prtno = 0;
|
$prtno = 0;
|
||||||
$invalid = 1;
|
$invalid = 1;
|
||||||
}
|
}
|
||||||
$id = ($did1_ver | $prtno) >> 16;
|
}
|
||||||
$new_member = sprintf "{0x%04X,\"LM3S%s\"},", $id, $base;
|
$new_member = sprintf "{0x%02X, 0x%02X, \"%s\"},", $class, $prtno >> 16, $base;
|
||||||
if ($invalid == 1) {
|
if ($invalid == 1) {
|
||||||
#$new_struct .= "\t//$new_member\t// Invalid\n";
|
#$new_struct .= "\t//$new_member\t// Invalid\n";
|
||||||
} else {
|
} else {
|
||||||
@@ -89,3 +104,21 @@ sub process_file {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub getclass {
|
||||||
|
$class = $_[0];
|
||||||
|
if ($class =~ /Sandstorm/i) {
|
||||||
|
return 0;
|
||||||
|
} elsif ($class =~ /Fury/i) {
|
||||||
|
return 1;
|
||||||
|
} elsif ($class =~ /DustDevil/i) {
|
||||||
|
return 3;
|
||||||
|
} elsif ($class =~ /Tempest/i) {
|
||||||
|
return 4;
|
||||||
|
} elsif ($class =~ /Blizzard/i) {
|
||||||
|
return 5;
|
||||||
|
} elsif ($class =~ /Firestorm/i) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
#define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8))
|
#define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8))
|
||||||
#define TARGET_REQ_DEBUGCHAR 0x02
|
#define TARGET_REQ_DEBUGCHAR 0x02
|
||||||
|
|
||||||
#if defined(__ARM_ARCH_7M__)
|
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_6SM__)
|
||||||
|
|
||||||
/* we use the cortex_m3 DCRDR reg to simulate a arm7_9 dcc channel
|
/* we use the System Control Block DCRDR reg to simulate a arm7_9 dcc channel
|
||||||
* DCRDR[7:0] is used by target for status
|
* DCRDR[7:0] is used by target for status
|
||||||
* DCRDR[15:8] is used by target for write buffer
|
* DCRDR[15:8] is used by target for write buffer
|
||||||
* DCRDR[23:16] is used for by host for status
|
* DCRDR[23:16] is used for by host for status
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
.text
|
.text
|
||||||
.syntax unified
|
.syntax unified
|
||||||
.arch armv7-m
|
.cpu cortex-m0
|
||||||
.thumb
|
.thumb
|
||||||
.thumb_func
|
.thumb_func
|
||||||
|
|
||||||
@@ -35,32 +35,37 @@
|
|||||||
_start:
|
_start:
|
||||||
main:
|
main:
|
||||||
mov r2, r0
|
mov r2, r0
|
||||||
mov r0, #0xffffffff /* crc */
|
movs r0, #0
|
||||||
|
mvns r0, r0
|
||||||
|
ldr r6, CRC32XOR
|
||||||
mov r3, r1
|
mov r3, r1
|
||||||
mov r4, #0
|
movs r4, #0
|
||||||
b ncomp
|
b ncomp
|
||||||
nbyte:
|
nbyte:
|
||||||
ldrb r1, [r2, r4]
|
ldrb r1, [r2, r4]
|
||||||
|
lsls r1, r1, #24
|
||||||
ldr r7, CRC32XOR
|
eors r0, r0, r1
|
||||||
eor r0, r0, r1, asl #24
|
movs r5, #0
|
||||||
mov r5, #0
|
|
||||||
loop:
|
loop:
|
||||||
cmp r0, #0
|
cmp r0, #0
|
||||||
mov r6, r0, asl #1
|
bge notset
|
||||||
add r5, r5, #1
|
lsls r0, r0, #1
|
||||||
mov r0, r6
|
eors r0, r0, r6
|
||||||
it lt
|
b cont
|
||||||
eorlt r0, r6, r7
|
notset:
|
||||||
|
lsls r0, r0, #1
|
||||||
|
cont:
|
||||||
|
adds r5, r5, #1
|
||||||
cmp r5, #8
|
cmp r5, #8
|
||||||
bne loop
|
bne loop
|
||||||
|
adds r4, r4, #1
|
||||||
add r4, r4, #1
|
|
||||||
ncomp:
|
ncomp:
|
||||||
cmp r4, r3
|
cmp r4, r3
|
||||||
bne nbyte
|
bne nbyte
|
||||||
bkpt #0
|
bkpt #0
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
|
||||||
CRC32XOR: .word 0x04c11db7
|
CRC32XOR: .word 0x04c11db7
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
|||||||
41
contrib/loaders/erase_check/armv4_5_erase_check.s
Normal file
41
contrib/loaders/erase_check/armv4_5_erase_check.s
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
parameters:
|
||||||
|
r0 - address in
|
||||||
|
r1 - byte count
|
||||||
|
r2 - mask - result out
|
||||||
|
*/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldrb r3, [r0], #1
|
||||||
|
and r2, r2, r3
|
||||||
|
subs r1, r1, #1
|
||||||
|
bne loop
|
||||||
|
end:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
CRC32XOR: .word 0x04c11db7
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -18,41 +18,28 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
.text
|
|
||||||
.syntax unified
|
|
||||||
.cpu cortex-m3
|
|
||||||
.thumb
|
|
||||||
.thumb_func
|
|
||||||
.global write
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
r0 - source address
|
parameters:
|
||||||
r1 - target address
|
r0 - address in
|
||||||
r2 - count (halfword-16bit)
|
r1 - byte count
|
||||||
r3 - sector offet in : result out
|
r2 - mask - result out
|
||||||
r4 - flash base
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
.text
|
||||||
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
.syntax unified
|
||||||
|
.cpu cortex-m0
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
write:
|
.align 2
|
||||||
ldr r4, STM32_FLASH_BASE
|
|
||||||
add r4, r3 /* add offset 0x00 for sector 0 : 0x40 for sector 1 */
|
|
||||||
write_half_word:
|
|
||||||
movs r3, #0x01
|
|
||||||
str r3, [r4, #STM32_FLASH_CR_OFFSET] /* PG (bit0) == 1 => flash programming enabled */
|
|
||||||
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
|
|
||||||
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
|
|
||||||
busy:
|
|
||||||
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
|
|
||||||
tst r3, #0x01 /* BSY (bit0) == 1 => operation in progress */
|
|
||||||
beq busy /* wait more... */
|
|
||||||
tst r3, #0x14 /* PGERR (bit2) == 1 or WRPRTERR (bit4) == 1 => error */
|
|
||||||
bne exit /* fail... */
|
|
||||||
subs r2, r2, #0x01 /* decrement counter */
|
|
||||||
bne write_half_word /* write next half-word if anything left */
|
|
||||||
exit:
|
|
||||||
bkpt #0x00
|
|
||||||
|
|
||||||
STM32_FLASH_BASE: .word 0x40022000 /* base address of FLASH struct */
|
loop:
|
||||||
|
ldrb r3, [r0]
|
||||||
|
adds r0, #1
|
||||||
|
ands r2, r2, r3
|
||||||
|
subs r1, r1, #1
|
||||||
|
bne loop
|
||||||
|
end:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.end
|
||||||
60
contrib/loaders/flash/armv7m_io.s
Normal file
60
contrib/loaders/flash/armv7m_io.s
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2013 by Henrik Nilsson *
|
||||||
|
* henrik.nilsson@bytequest.se *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-m
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
/* Inputs:
|
||||||
|
* r0 buffer address
|
||||||
|
* r1 NAND data address (byte wide)
|
||||||
|
* r2 buffer length
|
||||||
|
*/
|
||||||
|
read:
|
||||||
|
ldrb r3, [r1]
|
||||||
|
strb r3, [r0], #1
|
||||||
|
subs r2, r2, #1
|
||||||
|
bne read
|
||||||
|
|
||||||
|
done_read:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
/* Inputs:
|
||||||
|
* r0 NAND data address (byte wide)
|
||||||
|
* r1 buffer address
|
||||||
|
* r2 buffer length
|
||||||
|
*/
|
||||||
|
write:
|
||||||
|
ldrb r3, [r1], #1
|
||||||
|
strb r3, [r0]
|
||||||
|
subs r2, r2, #1
|
||||||
|
bne write
|
||||||
|
|
||||||
|
done_write:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.end
|
||||||
|
|
||||||
114
contrib/loaders/flash/efm32.S
Normal file
114
contrib/loaders/flash/efm32.S
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Andreas Fritiofson *
|
||||||
|
* andreas.fritiofson@gmail.com *
|
||||||
|
* Copyright (C) 2013 by Roman Dmitrienko *
|
||||||
|
* me@iamroman.org *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m0
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
/* Params:
|
||||||
|
* r0 - flash base (in), status (out)
|
||||||
|
* r1 - count (word-32bit)
|
||||||
|
* r2 - workarea start
|
||||||
|
* r3 - workarea end
|
||||||
|
* r4 - target address
|
||||||
|
* Clobbered:
|
||||||
|
* r5 - rp
|
||||||
|
* r6 - wp, tmp
|
||||||
|
* r7 - tmp
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* offsets of registers from flash reg base */
|
||||||
|
#define EFM32_MSC_WRITECTRL_OFFSET 0x008
|
||||||
|
#define EFM32_MSC_WRITECMD_OFFSET 0x00c
|
||||||
|
#define EFM32_MSC_ADDRB_OFFSET 0x010
|
||||||
|
#define EFM32_MSC_WDATA_OFFSET 0x018
|
||||||
|
#define EFM32_MSC_STATUS_OFFSET 0x01c
|
||||||
|
#define EFM32_MSC_LOCK_OFFSET 0x03c
|
||||||
|
|
||||||
|
/* unlock MSC */
|
||||||
|
ldr r6, =#0x1b71
|
||||||
|
str r6, [r0, #EFM32_MSC_LOCK_OFFSET]
|
||||||
|
/* set WREN to 1 */
|
||||||
|
movs r6, #1
|
||||||
|
str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET]
|
||||||
|
|
||||||
|
wait_fifo:
|
||||||
|
ldr r6, [r2, #0] /* read wp */
|
||||||
|
cmp r6, #0 /* abort if wp == 0 */
|
||||||
|
beq exit
|
||||||
|
ldr r5, [r2, #4] /* read rp */
|
||||||
|
cmp r5, r6 /* wait until rp != wp */
|
||||||
|
beq wait_fifo
|
||||||
|
|
||||||
|
/* store address in MSC_ADDRB */
|
||||||
|
str r4, [r0, #EFM32_MSC_ADDRB_OFFSET]
|
||||||
|
/* set LADDRIM bit */
|
||||||
|
movs r6, #1
|
||||||
|
str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
|
||||||
|
/* check status for INVADDR and/or LOCKED */
|
||||||
|
ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
|
||||||
|
movs r7, #6
|
||||||
|
tst r6, r7
|
||||||
|
bne error
|
||||||
|
|
||||||
|
/* wait for WDATAREADY */
|
||||||
|
wait_wdataready:
|
||||||
|
ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
|
||||||
|
movs r7, #8
|
||||||
|
tst r6, r7
|
||||||
|
beq wait_wdataready
|
||||||
|
|
||||||
|
/* load data to WDATA */
|
||||||
|
ldr r6, [r5]
|
||||||
|
str r6, [r0, #EFM32_MSC_WDATA_OFFSET]
|
||||||
|
/* set WRITEONCE bit */
|
||||||
|
movs r6, #8
|
||||||
|
str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
|
||||||
|
|
||||||
|
adds r5, #4 /* rp++ */
|
||||||
|
adds r4, #4 /* target_address++ */
|
||||||
|
|
||||||
|
/* wait until BUSY flag is reset */
|
||||||
|
busy:
|
||||||
|
ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
|
||||||
|
movs r7, #1
|
||||||
|
tst r6, r7
|
||||||
|
bne busy
|
||||||
|
|
||||||
|
cmp r5, r3 /* wrap rp at end of buffer */
|
||||||
|
bcc no_wrap
|
||||||
|
mov r5, r2
|
||||||
|
adds r5, #8
|
||||||
|
no_wrap:
|
||||||
|
str r5, [r2, #4] /* store rp */
|
||||||
|
subs r1, r1, #1 /* decrement word count */
|
||||||
|
cmp r1, #0
|
||||||
|
beq exit /* loop if not done */
|
||||||
|
b wait_fifo
|
||||||
|
error:
|
||||||
|
movs r0, #0
|
||||||
|
str r0, [r2, #4] /* set rp = 0 on error */
|
||||||
|
exit:
|
||||||
|
mov r0, r6 /* return status in r0 */
|
||||||
|
bkpt #0
|
||||||
176
contrib/loaders/flash/lpcspifi_erase.S
Normal file
176
contrib/loaders/flash/lpcspifi_erase.S
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2012 by George Harris *
|
||||||
|
* george@luminairecoffee.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m3
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Params :
|
||||||
|
* r0 = start address, status (out)
|
||||||
|
* r1 = count
|
||||||
|
* r2 = erase command
|
||||||
|
* r3 = block size
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SSP_BASE_HIGH 0x4008
|
||||||
|
#define SSP_BASE_LOW 0x3000
|
||||||
|
#define SSP_CR0_OFFSET 0x00
|
||||||
|
#define SSP_CR1_OFFSET 0x04
|
||||||
|
#define SSP_DATA_OFFSET 0x08
|
||||||
|
#define SSP_CPSR_OFFSET 0x10
|
||||||
|
#define SSP_SR_OFFSET 0x0c
|
||||||
|
|
||||||
|
#define SSP_CLOCK_BASE_HIGH 0x4005
|
||||||
|
#define SSP_CLOCK_BASE_LOW 0x0000
|
||||||
|
#define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005
|
||||||
|
#define SSP_BRANCH_CLOCK_BASE_LOW 0x2000
|
||||||
|
#define SSP_BASE_CLOCK_OFFSET 0x94
|
||||||
|
#define SSP_BRANCH_CLOCK_OFFSET 0x700
|
||||||
|
|
||||||
|
#define IOCONFIG_BASE_HIGH 0x4008
|
||||||
|
#define IOCONFIG_BASE_LOW 0x6000
|
||||||
|
#define IOCONFIG_SCK_OFFSET 0x18c
|
||||||
|
#define IOCONFIG_HOLD_OFFSET 0x190
|
||||||
|
#define IOCONFIG_WP_OFFSET 0x194
|
||||||
|
#define IOCONFIG_MISO_OFFSET 0x198
|
||||||
|
#define IOCONFIG_MOSI_OFFSET 0x19c
|
||||||
|
#define IOCONFIG_CS_OFFSET 0x1a0
|
||||||
|
|
||||||
|
#define IO_BASE_HIGH 0x400f
|
||||||
|
#define IO_BASE_LOW 0x4000
|
||||||
|
#define IO_CS_OFFSET 0xab
|
||||||
|
#define IODIR_BASE_HIGH 0x400f
|
||||||
|
#define IODIR_BASE_LOW 0x6000
|
||||||
|
#define IO_CS_DIR_OFFSET 0x14
|
||||||
|
|
||||||
|
|
||||||
|
setup: /* Initialize SSP pins and module */
|
||||||
|
mov.w r10, #IOCONFIG_BASE_LOW
|
||||||
|
movt r10, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r8, #0xea
|
||||||
|
str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */
|
||||||
|
mov.w r8, #0x40
|
||||||
|
str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */
|
||||||
|
mov.w r8, #0x40
|
||||||
|
str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */
|
||||||
|
mov.w r8, #0xed
|
||||||
|
str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */
|
||||||
|
mov.w r8, #0xed
|
||||||
|
str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */
|
||||||
|
mov.w r8, #0x44
|
||||||
|
str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */
|
||||||
|
|
||||||
|
mov.w r10, #IODIR_BASE_LOW
|
||||||
|
movt r10, #IODIR_BASE_HIGH
|
||||||
|
mov.w r8, #0x800
|
||||||
|
str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */
|
||||||
|
mov.w r10, #IO_BASE_LOW
|
||||||
|
movt r10, #IO_BASE_HIGH
|
||||||
|
mov.w r8, #0xff
|
||||||
|
str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_CLOCK_BASE_LOW
|
||||||
|
movt r10, #SSP_CLOCK_BASE_HIGH
|
||||||
|
mov.w r8, #0x0000
|
||||||
|
movt r8, #0x0100
|
||||||
|
str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW
|
||||||
|
movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH
|
||||||
|
mov.w r8, #0x01
|
||||||
|
str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_BASE_LOW
|
||||||
|
movt r10, #SSP_BASE_HIGH
|
||||||
|
mov.w r8, #0x07
|
||||||
|
str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */
|
||||||
|
mov.w r8, #0x02
|
||||||
|
str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */
|
||||||
|
str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */
|
||||||
|
write_enable:
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x06 /* Send the write enable command */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x05 /* Get status register */
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, #0x00 /* Dummy data to clock in status */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
|
||||||
|
tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */
|
||||||
|
beq error
|
||||||
|
erase:
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, r2 /* Send the erase command */
|
||||||
|
bl write_data
|
||||||
|
write_address:
|
||||||
|
lsr r9, r0, #16 /* Send the current 24-bit write address, MSB first */
|
||||||
|
bl write_data
|
||||||
|
lsr r9, r0, #8
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, r0
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
wait_flash_busy: /* Wait for the flash to finish the previous erase */
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x05 /* Get status register */
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, #0x00 /* Dummy data to clock in status */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
tst r9, #0x01 /* If it isn't done, keep waiting */
|
||||||
|
bne wait_flash_busy
|
||||||
|
|
||||||
|
subs r1, r1, #1 /* decrement count */
|
||||||
|
cbz r1, exit /* Exit if we have written everything */
|
||||||
|
add r0, r3 /* Move the address up by the block size */
|
||||||
|
b write_enable /* Start a new block erase */
|
||||||
|
write_data: /* Send/receive 1 byte of data over SSP */
|
||||||
|
mov.w r10, #SSP_BASE_LOW
|
||||||
|
movt r10, #SSP_BASE_HIGH
|
||||||
|
str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */
|
||||||
|
wait_transmit:
|
||||||
|
ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */
|
||||||
|
tst r9, #0x0010 /* Check if BSY bit is set */
|
||||||
|
bne wait_transmit /* If still transmitting, keep waiting */
|
||||||
|
ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */
|
||||||
|
bx lr /* Exit subroutine */
|
||||||
|
cs_up:
|
||||||
|
mov.w r8, #0xff
|
||||||
|
b cs_write
|
||||||
|
cs_down:
|
||||||
|
mov.w r8, #0x0000
|
||||||
|
cs_write:
|
||||||
|
mov.w r10, #IO_BASE_LOW
|
||||||
|
movt r10, #IO_BASE_HIGH
|
||||||
|
str.w r8, [r10, #IO_CS_OFFSET]
|
||||||
|
bx lr
|
||||||
|
error:
|
||||||
|
movs r0, #0
|
||||||
|
exit:
|
||||||
|
bkpt #0x00
|
||||||
|
|
||||||
|
.end
|
||||||
102
contrib/loaders/flash/lpcspifi_init.S
Normal file
102
contrib/loaders/flash/lpcspifi_init.S
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2012 by George Harris *
|
||||||
|
* george@luminairecoffee.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* This is an algorithm for the LPC43xx family (and probably the LPC18xx *
|
||||||
|
* family as well, though they have not been tested) that will initialize *
|
||||||
|
* memory-mapped SPI flash accesses. Unfortunately NXP has published *
|
||||||
|
* neither the ROM source code that performs this initialization nor the *
|
||||||
|
* register descriptions necessary to do so, so this code is necessary to *
|
||||||
|
* call into the ROM SPIFI API. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-m
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Params :
|
||||||
|
* r0 = spifi clock speed
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define IOCONFIG_BASE_HIGH 0x4008
|
||||||
|
#define IOCONFIG_BASE_LOW 0x6000
|
||||||
|
#define IOCONFIG_SCK_OFFSET 0x18c
|
||||||
|
#define IOCONFIG_HOLD_OFFSET 0x190
|
||||||
|
#define IOCONFIG_WP_OFFSET 0x194
|
||||||
|
#define IOCONFIG_MISO_OFFSET 0x198
|
||||||
|
#define IOCONFIG_MOSI_OFFSET 0x19c
|
||||||
|
#define IOCONFIG_CS_OFFSET 0x1a0
|
||||||
|
|
||||||
|
#define SPIFI_ROM_TABLE_BASE_HIGH 0x1040
|
||||||
|
#define SPIFI_ROM_TABLE_BASE_LOW 0x0118
|
||||||
|
|
||||||
|
code:
|
||||||
|
mov.w r8, r0
|
||||||
|
sub sp, #0x84
|
||||||
|
add r7, sp, #0x0
|
||||||
|
/* Initialize SPIFI pins */
|
||||||
|
mov.w r3, #IOCONFIG_BASE_LOW
|
||||||
|
movt r3, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r2, #0xf3
|
||||||
|
str.w r2, [r3, #IOCONFIG_SCK_OFFSET]
|
||||||
|
mov.w r3, #IOCONFIG_BASE_LOW
|
||||||
|
movt r3, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r2, #IOCONFIG_BASE_LOW
|
||||||
|
movt r2, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r1, #IOCONFIG_BASE_LOW
|
||||||
|
movt r1, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r0, #IOCONFIG_BASE_LOW
|
||||||
|
movt r0, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r4, #0xd3
|
||||||
|
str.w r4, [r0, #IOCONFIG_MOSI_OFFSET]
|
||||||
|
mov r0, r4
|
||||||
|
str.w r0, [r1, #IOCONFIG_MISO_OFFSET]
|
||||||
|
mov r1, r0
|
||||||
|
str.w r1, [r2, #IOCONFIG_WP_OFFSET]
|
||||||
|
str.w r1, [r3, #IOCONFIG_HOLD_OFFSET]
|
||||||
|
mov.w r3, #IOCONFIG_BASE_LOW
|
||||||
|
movt r3, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r2, #0x13
|
||||||
|
str.w r2, [r3, #IOCONFIG_CS_OFFSET]
|
||||||
|
|
||||||
|
/* Perform SPIFI init. See spifi_rom_api.h (in NXP lpc43xx driver package) for details */
|
||||||
|
/* on initialization arguments. */
|
||||||
|
movw r3, #SPIFI_ROM_TABLE_BASE_LOW /* The ROM API table is located @ 0x10400118, and */
|
||||||
|
movt r3, #SPIFI_ROM_TABLE_BASE_HIGH /* the first pointer in the struct is to the init function. */
|
||||||
|
ldr r3, [r3, #0x0]
|
||||||
|
ldr r4, [r3, #0x0] /* Grab the init function pointer from the table */
|
||||||
|
/* Set up function arguments */
|
||||||
|
movw r0, #0x3b4
|
||||||
|
movt r0, #0x1000 /* Pointer to a SPIFI data struct that we don't care about */
|
||||||
|
mov.w r1, #0x3 /* "csHigh". Not 100% sure what this does. */
|
||||||
|
mov.w r2, #0xc0 /* The configuration word: S_RCVCLOCK | S_FULLCLK */
|
||||||
|
mov.w r3, r8 /* SPIFI clock speed (12MHz) */
|
||||||
|
blx r4 /* Call the init function */
|
||||||
|
b done
|
||||||
|
|
||||||
|
done:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.end
|
||||||
210
contrib/loaders/flash/lpcspifi_write.S
Normal file
210
contrib/loaders/flash/lpcspifi_write.S
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2012 by George Harris *
|
||||||
|
* george@luminairecoffee.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m3
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Params :
|
||||||
|
* r0 = workarea start, status (out)
|
||||||
|
* r1 = workarea end
|
||||||
|
* r2 = target address (offset from flash base)
|
||||||
|
* r3 = count (bytes)
|
||||||
|
* r4 = page size
|
||||||
|
* Clobbered:
|
||||||
|
* r7 - rp
|
||||||
|
* r8 - wp, tmp
|
||||||
|
* r9 - send/receive data
|
||||||
|
* r10 - temp
|
||||||
|
* r11 - current page end address
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SSP_BASE_HIGH 0x4008
|
||||||
|
#define SSP_BASE_LOW 0x3000
|
||||||
|
#define SSP_CR0_OFFSET 0x00
|
||||||
|
#define SSP_CR1_OFFSET 0x04
|
||||||
|
#define SSP_DATA_OFFSET 0x08
|
||||||
|
#define SSP_CPSR_OFFSET 0x10
|
||||||
|
#define SSP_SR_OFFSET 0x0c
|
||||||
|
|
||||||
|
#define SSP_CLOCK_BASE_HIGH 0x4005
|
||||||
|
#define SSP_CLOCK_BASE_LOW 0x0000
|
||||||
|
#define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005
|
||||||
|
#define SSP_BRANCH_CLOCK_BASE_LOW 0x2000
|
||||||
|
#define SSP_BASE_CLOCK_OFFSET 0x94
|
||||||
|
#define SSP_BRANCH_CLOCK_OFFSET 0x700
|
||||||
|
|
||||||
|
#define IOCONFIG_BASE_HIGH 0x4008
|
||||||
|
#define IOCONFIG_BASE_LOW 0x6000
|
||||||
|
#define IOCONFIG_SCK_OFFSET 0x18c
|
||||||
|
#define IOCONFIG_HOLD_OFFSET 0x190
|
||||||
|
#define IOCONFIG_WP_OFFSET 0x194
|
||||||
|
#define IOCONFIG_MISO_OFFSET 0x198
|
||||||
|
#define IOCONFIG_MOSI_OFFSET 0x19c
|
||||||
|
#define IOCONFIG_CS_OFFSET 0x1a0
|
||||||
|
|
||||||
|
#define IO_BASE_HIGH 0x400f
|
||||||
|
#define IO_BASE_LOW 0x4000
|
||||||
|
#define IO_CS_OFFSET 0xab
|
||||||
|
#define IODIR_BASE_HIGH 0x400f
|
||||||
|
#define IODIR_BASE_LOW 0x6000
|
||||||
|
#define IO_CS_DIR_OFFSET 0x14
|
||||||
|
|
||||||
|
|
||||||
|
setup: /* Initialize SSP pins and module */
|
||||||
|
mov.w r10, #IOCONFIG_BASE_LOW
|
||||||
|
movt r10, #IOCONFIG_BASE_HIGH
|
||||||
|
mov.w r8, #0xea
|
||||||
|
str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */
|
||||||
|
mov.w r8, #0x40
|
||||||
|
str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */
|
||||||
|
mov.w r8, #0x40
|
||||||
|
str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */
|
||||||
|
mov.w r8, #0xed
|
||||||
|
str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */
|
||||||
|
mov.w r8, #0xed
|
||||||
|
str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */
|
||||||
|
mov.w r8, #0x44
|
||||||
|
str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */
|
||||||
|
|
||||||
|
mov.w r10, #IODIR_BASE_LOW
|
||||||
|
movt r10, #IODIR_BASE_HIGH
|
||||||
|
mov.w r8, #0x800
|
||||||
|
str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */
|
||||||
|
mov.w r10, #IO_BASE_LOW
|
||||||
|
movt r10, #IO_BASE_HIGH
|
||||||
|
mov.w r8, #0xff
|
||||||
|
str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_CLOCK_BASE_LOW
|
||||||
|
movt r10, #SSP_CLOCK_BASE_HIGH
|
||||||
|
mov.w r8, #0x0000
|
||||||
|
movt r8, #0x0100
|
||||||
|
str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW
|
||||||
|
movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH
|
||||||
|
mov.w r8, #0x01
|
||||||
|
str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
|
||||||
|
|
||||||
|
mov.w r10, #SSP_BASE_LOW
|
||||||
|
movt r10, #SSP_BASE_HIGH
|
||||||
|
mov.w r8, #0x07
|
||||||
|
str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */
|
||||||
|
mov.w r8, #0x02
|
||||||
|
str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */
|
||||||
|
str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */
|
||||||
|
|
||||||
|
mov.w r11, #0x00
|
||||||
|
find_next_page_boundary:
|
||||||
|
add r11, r4 /* Increment to the next page */
|
||||||
|
cmp r11, r2
|
||||||
|
/* If we have not reached the next page boundary after the target address, keep going */
|
||||||
|
bls find_next_page_boundary
|
||||||
|
write_enable:
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x06 /* Send the write enable command */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x05 /* Get status register */
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, #0x00 /* Dummy data to clock in status */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
|
||||||
|
tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */
|
||||||
|
beq error
|
||||||
|
page_program:
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x02 /* Send the page program command */
|
||||||
|
bl write_data
|
||||||
|
write_address:
|
||||||
|
lsr r9, r2, #16 /* Send the current 24-bit write address, MSB first */
|
||||||
|
bl write_data
|
||||||
|
lsr r9, r2, #8
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, r2
|
||||||
|
bl write_data
|
||||||
|
wait_fifo:
|
||||||
|
ldr r8, [r0] /* read the write pointer */
|
||||||
|
cmp r8, #0 /* if it's zero, we're gonzo */
|
||||||
|
beq exit
|
||||||
|
ldr r7, [r0, #4] /* read the read pointer */
|
||||||
|
cmp r7, r8 /* wait until they are not equal */
|
||||||
|
beq wait_fifo
|
||||||
|
write:
|
||||||
|
ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
|
||||||
|
bl write_data /* send the byte to the flash chip */
|
||||||
|
|
||||||
|
cmp r7, r1 /* wrap the read pointer if it is at the end */
|
||||||
|
it cs
|
||||||
|
addcs r7, r0, #8 /* skip loader args */
|
||||||
|
str r7, [r0, #4] /* store the new read pointer */
|
||||||
|
subs r3, r3, #1 /* decrement count */
|
||||||
|
cbz r3, exit /* Exit if we have written everything */
|
||||||
|
|
||||||
|
add r2, #1 /* Increment flash address by 1 */
|
||||||
|
cmp r11, r2 /* See if we have reached the end of a page */
|
||||||
|
bne wait_fifo /* If not, keep writing bytes */
|
||||||
|
bl cs_up /* Otherwise, end the command and keep going w/ the next page */
|
||||||
|
add r11, r4 /* Move up the end-of-page address by the page size*/
|
||||||
|
wait_flash_busy: /* Wait for the flash to finish the previous page write */
|
||||||
|
bl cs_down
|
||||||
|
mov.w r9, #0x05 /* Get status register */
|
||||||
|
bl write_data
|
||||||
|
mov.w r9, #0x00 /* Dummy data to clock in status */
|
||||||
|
bl write_data
|
||||||
|
bl cs_up
|
||||||
|
tst r9, #0x01 /* If it isn't done, keep waiting */
|
||||||
|
bne wait_flash_busy
|
||||||
|
b write_enable /* If it is done, start a new page write */
|
||||||
|
write_data: /* Send/receive 1 byte of data over SSP */
|
||||||
|
mov.w r10, #SSP_BASE_LOW
|
||||||
|
movt r10, #SSP_BASE_HIGH
|
||||||
|
str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */
|
||||||
|
wait_transmit:
|
||||||
|
ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */
|
||||||
|
tst r9, #0x0010 /* Check if BSY bit is set */
|
||||||
|
bne wait_transmit /* If still transmitting, keep waiting */
|
||||||
|
ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */
|
||||||
|
bx lr /* Exit subroutine */
|
||||||
|
cs_up:
|
||||||
|
mov.w r8, #0xff
|
||||||
|
b cs_write
|
||||||
|
cs_down:
|
||||||
|
mov.w r8, #0x0000
|
||||||
|
cs_write:
|
||||||
|
mov.w r10, #IO_BASE_LOW
|
||||||
|
movt r10, #IO_BASE_HIGH
|
||||||
|
str.w r8, [r10, #IO_CS_OFFSET]
|
||||||
|
bx lr
|
||||||
|
error:
|
||||||
|
movs r0, #0
|
||||||
|
str r0, [r2, #4] /* set rp = 0 on error */
|
||||||
|
exit:
|
||||||
|
mov r0, r6
|
||||||
|
bkpt #0x00
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -26,40 +26,52 @@
|
|||||||
.cpu cortex-m3
|
.cpu cortex-m3
|
||||||
.thumb
|
.thumb
|
||||||
.thumb_func
|
.thumb_func
|
||||||
.align 2
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Call with :
|
* Params :
|
||||||
r0 = buffer address
|
* r0 = workarea start
|
||||||
r1 = destination address
|
* r1 = workarea end
|
||||||
r2 = bytecount (in) - endaddr (work)
|
* r2 = target address
|
||||||
|
* r3 = count (32bit words)
|
||||||
Used registers:
|
*
|
||||||
r3 = pFLASH_CTRL_BASE
|
* Clobbered:
|
||||||
r4 = FLASHWRITECMD
|
* r4 = pFLASH_CTRL_BASE
|
||||||
r5 = #1
|
* r5 = FLASHWRITECMD
|
||||||
r6 = bytes written
|
* r7 - rp
|
||||||
r7 = temp reg
|
* r8 - wp, tmp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
write:
|
write:
|
||||||
ldr r3,pFLASH_CTRL_BASE
|
ldr r4, pFLASH_CTRL_BASE
|
||||||
ldr r4,FLASHWRITECMD
|
ldr r5, FLASHWRITECMD
|
||||||
movs r5, 1
|
|
||||||
movs r6, #0
|
wait_fifo:
|
||||||
|
ldr r8, [r0, #0] /* read wp */
|
||||||
|
cmp r8, #0 /* abort if wp == 0 */
|
||||||
|
beq exit
|
||||||
|
ldr r7, [r0, #4] /* read rp */
|
||||||
|
cmp r7, r8 /* wait until rp != wp */
|
||||||
|
beq wait_fifo
|
||||||
|
|
||||||
mainloop:
|
mainloop:
|
||||||
str r1, [r3, #0]
|
str r2, [r4, #0] /* FMA - write address */
|
||||||
ldr r7, [r0, r6]
|
add r2, r2, #4 /* increment target address */
|
||||||
str r7, [r3, #4]
|
ldr r8, [r7], #4
|
||||||
str r4, [r3, #8]
|
str r8, [r4, #4] /* FMD - write data */
|
||||||
waitloop:
|
str r5, [r4, #8] /* FMC - enable write */
|
||||||
ldr r7, [r3, #8]
|
busy:
|
||||||
tst r7, r5
|
ldr r8, [r4, #8]
|
||||||
bne waitloop
|
tst r8, #1
|
||||||
adds r1, r1, #4
|
bne busy
|
||||||
adds r6, r6, #4
|
|
||||||
cmp r6, r2
|
cmp r7, r1 /* wrap rp at end of buffer */
|
||||||
bne mainloop
|
it cs
|
||||||
|
addcs r7, r0, #8 /* skip loader args */
|
||||||
|
str r7, [r0, #4] /* store rp */
|
||||||
|
subs r3, r3, #1 /* decrement word count */
|
||||||
|
cbz r3, exit /* loop if not done */
|
||||||
|
b wait_fifo
|
||||||
|
exit:
|
||||||
bkpt #0
|
bkpt #0
|
||||||
|
|
||||||
pFLASH_CTRL_BASE: .word 0x400FD000
|
pFLASH_CTRL_BASE: .word 0x400FD000
|
||||||
|
|||||||
76
contrib/loaders/flash/stm32f1x.S
Normal file
76
contrib/loaders/flash/stm32f1x.S
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Andreas Fritiofson *
|
||||||
|
* andreas.fritiofson@gmail.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m0
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
.global write
|
||||||
|
|
||||||
|
/* Params:
|
||||||
|
* r0 - flash base (in), status (out)
|
||||||
|
* r1 - count (halfword-16bit)
|
||||||
|
* r2 - workarea start
|
||||||
|
* r3 - workarea end
|
||||||
|
* r4 - target address
|
||||||
|
* Clobbered:
|
||||||
|
* r5 - rp
|
||||||
|
* r6 - wp, tmp
|
||||||
|
* r7 - tmp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register from flash reg base */
|
||||||
|
|
||||||
|
wait_fifo:
|
||||||
|
ldr r6, [r2, #0] /* read wp */
|
||||||
|
cmp r6, #0 /* abort if wp == 0 */
|
||||||
|
beq exit
|
||||||
|
ldr r5, [r2, #4] /* read rp */
|
||||||
|
cmp r5, r6 /* wait until rp != wp */
|
||||||
|
beq wait_fifo
|
||||||
|
ldrh r6, [r5] /* "*target_address++ = *rp++" */
|
||||||
|
strh r6, [r4]
|
||||||
|
adds r5, #2
|
||||||
|
adds r4, #2
|
||||||
|
busy:
|
||||||
|
ldr r6, [r0, #STM32_FLASH_SR_OFFSET] /* wait until BSY flag is reset */
|
||||||
|
movs r7, #1
|
||||||
|
tst r6, r7
|
||||||
|
bne busy
|
||||||
|
movs r7, #0x14 /* check the error bits */
|
||||||
|
tst r6, r7
|
||||||
|
bne error
|
||||||
|
cmp r5, r3 /* wrap rp at end of buffer */
|
||||||
|
bcc no_wrap
|
||||||
|
mov r5, r2
|
||||||
|
adds r5, #8
|
||||||
|
no_wrap:
|
||||||
|
str r5, [r2, #4] /* store rp */
|
||||||
|
subs r1, r1, #1 /* decrement halfword count */
|
||||||
|
cmp r1, #0
|
||||||
|
beq exit /* loop if not done */
|
||||||
|
b wait_fifo
|
||||||
|
error:
|
||||||
|
movs r0, #0
|
||||||
|
str r0, [r2, #4] /* set rp = 0 on error */
|
||||||
|
exit:
|
||||||
|
mov r0, r6 /* return status in r0 */
|
||||||
|
bkpt #0
|
||||||
80
contrib/loaders/flash/stm32f2x.S
Normal file
80
contrib/loaders/flash/stm32f2x.S
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2011 Øyvind Harboe *
|
||||||
|
* oyvind.harboe@zylin.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m3
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Params :
|
||||||
|
* r0 = workarea start, status (out)
|
||||||
|
* r1 = workarea end
|
||||||
|
* r2 = target address
|
||||||
|
* r3 = count (16bit words)
|
||||||
|
* r4 = flash base
|
||||||
|
*
|
||||||
|
* Clobbered:
|
||||||
|
* r6 - temp
|
||||||
|
* r7 - rp
|
||||||
|
* r8 - wp, tmp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
||||||
|
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of SR register in FLASH struct */
|
||||||
|
|
||||||
|
wait_fifo:
|
||||||
|
ldr r8, [r0, #0] /* read wp */
|
||||||
|
cmp r8, #0 /* abort if wp == 0 */
|
||||||
|
beq exit
|
||||||
|
ldr r7, [r0, #4] /* read rp */
|
||||||
|
cmp r7, r8 /* wait until rp != wp */
|
||||||
|
beq wait_fifo
|
||||||
|
|
||||||
|
ldr r6, STM32_PROG16
|
||||||
|
str r6, [r4, #STM32_FLASH_CR_OFFSET]
|
||||||
|
ldrh r6, [r7], #0x02 /* read one half-word from src, increment ptr */
|
||||||
|
strh r6, [r2], #0x02 /* write one half-word from src, increment ptr */
|
||||||
|
busy:
|
||||||
|
ldr r6, [r4, #STM32_FLASH_SR_OFFSET]
|
||||||
|
tst r6, #0x10000 /* BSY (bit16) == 1 => operation in progress */
|
||||||
|
bne busy /* wait more... */
|
||||||
|
tst r6, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */
|
||||||
|
bne error /* fail... */
|
||||||
|
|
||||||
|
cmp r7, r1 /* wrap rp at end of buffer */
|
||||||
|
it cs
|
||||||
|
addcs r7, r0, #8 /* skip loader args */
|
||||||
|
str r7, [r0, #4] /* store rp */
|
||||||
|
subs r3, r3, #1 /* decrement halfword count */
|
||||||
|
cbz r3, exit /* loop if not done */
|
||||||
|
b wait_fifo
|
||||||
|
error:
|
||||||
|
movs r1, #0
|
||||||
|
str r1, [r0, #4] /* set rp = 0 on error */
|
||||||
|
exit:
|
||||||
|
mov r0, r6 /* return status in r0 */
|
||||||
|
bkpt #0x00
|
||||||
|
|
||||||
|
STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/
|
||||||
@@ -5,6 +5,9 @@
|
|||||||
* Copyright (C) 2011 Øyvind Harboe *
|
* Copyright (C) 2011 Øyvind Harboe *
|
||||||
* oyvind.harboe@zylin.com *
|
* oyvind.harboe@zylin.com *
|
||||||
* *
|
* *
|
||||||
|
* Copyright (C) 2011 Clement Burin des Roziers *
|
||||||
|
* clement.burin-des-roziers@hikob.com *
|
||||||
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
@@ -22,7 +25,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
// Build : arm-eabi-gcc -c stm32f2xxx.S
|
// Build : arm-eabi-gcc -c stm32lx.S
|
||||||
.text
|
.text
|
||||||
.syntax unified
|
.syntax unified
|
||||||
.cpu cortex-m3
|
.cpu cortex-m3
|
||||||
@@ -31,33 +34,30 @@
|
|||||||
.global write
|
.global write
|
||||||
|
|
||||||
/*
|
/*
|
||||||
r0 - source address
|
r0 - destination address
|
||||||
r1 - target address
|
r1 - source address
|
||||||
r2 - count (halfword-16bit)
|
r2 - count
|
||||||
r3 - result out
|
|
||||||
r4 - flash base
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
// Set 0 to r3
|
||||||
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
movs r3, #0
|
||||||
|
// Go to compare
|
||||||
|
b.n test_done
|
||||||
|
|
||||||
write:
|
write_word:
|
||||||
|
// Load one word from address in r0, increment by 4
|
||||||
|
ldr.w ip, [r1], #4
|
||||||
|
// Store the word to address in r1, increment by 4
|
||||||
|
str.w ip, [r0], #4
|
||||||
|
// Increment r3
|
||||||
|
adds r3, #1
|
||||||
|
|
||||||
write_half_word:
|
test_done:
|
||||||
ldr r3, STM32_PROG16
|
// Compare r3 and r2
|
||||||
str r3, [r4, #STM32_FLASH_CR_OFFSET]
|
cmp r3, r2
|
||||||
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
|
// Loop if not zero
|
||||||
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
|
bcc.n write_word
|
||||||
busy:
|
|
||||||
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
|
// Set breakpoint to exit
|
||||||
tst r3, #0x10000 /* BSY (bit0) == 1 => operation in progress */
|
|
||||||
beq busy /* wait more... */
|
|
||||||
tst r3, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */
|
|
||||||
bne exit /* fail... */
|
|
||||||
subs r2, r2, #0x01 /* decrement counter */
|
|
||||||
bne write_half_word /* write next half-word if anything left */
|
|
||||||
exit:
|
|
||||||
bkpt #0x00
|
bkpt #0x00
|
||||||
|
|
||||||
|
|
||||||
STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/
|
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
ACTION!="add|change", GOTO="openocd_rules_end"
|
ACTION!="add|change", GOTO="openocd_rules_end"
|
||||||
SUBSYSTEM!="usb", GOTO="openocd_rules_end"
|
SUBSYSTEM!="usb|tty", GOTO="openocd_rules_end"
|
||||||
ENV{DEVTYPE}!="usb_device", GOTO="openocd_rules_end"
|
|
||||||
|
|
||||||
# Olimex ARM-USB-OCD
|
# Olimex ARM-USB-OCD
|
||||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# Olimex ARM-USB-OCD-H
|
||||||
|
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# Olimex ARM-USB-OCD-TINY
|
# Olimex ARM-USB-OCD-TINY
|
||||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
@@ -28,9 +30,11 @@ ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="664", GROUP="plugdev"
|
|||||||
# TinCanTools Flyswatter
|
# TinCanTools Flyswatter
|
||||||
# OOCD-Link
|
# OOCD-Link
|
||||||
# Marvell Sheevaplug (early development versions)
|
# Marvell Sheevaplug (early development versions)
|
||||||
|
# DLP Design DLP-USB1232H USB-to-UART/FIFO interface module
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# Calao Systems USB-A9260-C02
|
# Calao Systems USB-A9260-C02
|
||||||
|
# Bus Pirate
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# IAR J-Link USB
|
# IAR J-Link USB
|
||||||
@@ -45,12 +49,15 @@ ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="664", GROUP="plugdev"
|
|||||||
# Hitex STM32-PerformanceStick
|
# Hitex STM32-PerformanceStick
|
||||||
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# TI/Luminary Stellaris Evaluation Board (several)
|
# TI/Luminary Stellaris Evaluation Board FTDI (several)
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
|
# TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
|
||||||
|
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
# Xverve Signalyzer Tool (DT-USB-ST)
|
# Xverve Signalyzer Tool (DT-USB-ST)
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
@@ -67,5 +74,19 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
|||||||
# Hilscher NXHX Boards
|
# Hilscher NXHX Boards
|
||||||
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
LABEL="openocd_rules_end"
|
# Debug Board for Neo1973
|
||||||
|
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# XDS100v2
|
||||||
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# stlink v1
|
||||||
|
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# stlink v2
|
||||||
|
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# opendous and estick
|
||||||
|
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
LABEL="openocd_rules_end"
|
||||||
|
|||||||
53
doc/manual/jtag/drivers/remote_bitbang.txt
Normal file
53
doc/manual/jtag/drivers/remote_bitbang.txt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/** @remote_bitbangpage OpenOCD Developer's Guide
|
||||||
|
|
||||||
|
The remote_bitbang JTAG driver is used to drive JTAG from a remote process. The
|
||||||
|
remote_bitbang driver communicates via TCP or UNIX sockets with some remote
|
||||||
|
process using an ASCII encoding of the bitbang interface. The remote process
|
||||||
|
presumably then drives the JTAG however it pleases. The remote process should
|
||||||
|
act as a server, listening for connections from the openocd remote_bitbang
|
||||||
|
driver.
|
||||||
|
|
||||||
|
The remote bitbang driver is useful for debugging software running on
|
||||||
|
processors which are being simulated.
|
||||||
|
|
||||||
|
The bitbang interface consists of the following functions.
|
||||||
|
|
||||||
|
blink on
|
||||||
|
Blink a light somewhere. The argument on is either 1 or 0.
|
||||||
|
|
||||||
|
read
|
||||||
|
Sample the value of tdo.
|
||||||
|
|
||||||
|
write tck tms tdi
|
||||||
|
Set the value of tck, tms, and tdi.
|
||||||
|
|
||||||
|
reset trst srst
|
||||||
|
Set the value of trst, srst.
|
||||||
|
|
||||||
|
An additional function, quit, is added to the remote_bitbang interface to
|
||||||
|
indicate there will be no more requests and the connection with the remote
|
||||||
|
driver should be closed.
|
||||||
|
|
||||||
|
These five functions are encoded in ascii by assigning a single character to
|
||||||
|
each possible request. The assignments are:
|
||||||
|
|
||||||
|
B - Blink on
|
||||||
|
b - Blink off
|
||||||
|
R - Read request
|
||||||
|
Q - Quit request
|
||||||
|
0 - Write 0 0 0
|
||||||
|
1 - Write 0 0 1
|
||||||
|
2 - Write 0 1 0
|
||||||
|
3 - Write 0 1 1
|
||||||
|
4 - Write 1 0 0
|
||||||
|
5 - Write 1 0 1
|
||||||
|
6 - Write 1 1 0
|
||||||
|
7 - Write 1 1 1
|
||||||
|
r - Reset 0 0
|
||||||
|
s - Reset 0 1
|
||||||
|
t - Reset 1 0
|
||||||
|
u - Reset 1 1
|
||||||
|
|
||||||
|
The read response is encoded in ascii as either digit 0 or 1.
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -36,7 +36,6 @@ This pages lists Technical Primers available for OpenOCD Developers.
|
|||||||
They seek to provide information to pull novices up the learning curves
|
They seek to provide information to pull novices up the learning curves
|
||||||
associated with the fundamental technologies used by OpenOCD.
|
associated with the fundamental technologies used by OpenOCD.
|
||||||
|
|
||||||
- @subpage primerpatches
|
|
||||||
- @subpage primerdocs
|
- @subpage primerdocs
|
||||||
- @subpage primerautotools
|
- @subpage primerautotools
|
||||||
- @subpage primertcl
|
- @subpage primertcl
|
||||||
@@ -83,6 +82,7 @@ modules are stacked in the current implementation (from bottom to top):
|
|||||||
- @subpage targetdocs
|
- @subpage targetdocs
|
||||||
- @ref targetarm
|
- @ref targetarm
|
||||||
- @ref targetnotarm
|
- @ref targetnotarm
|
||||||
|
- @ref targetmips
|
||||||
- @ref targetregister
|
- @ref targetregister
|
||||||
- @ref targetimage
|
- @ref targetimage
|
||||||
- @ref targettrace
|
- @ref targettrace
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
/** @page primerpatches Patch Primer
|
|
||||||
|
|
||||||
This page provides an introduction to patching that may be useful
|
|
||||||
for OpenOCD contributors who are unfamiliar with the process.
|
|
||||||
|
|
||||||
@section primerpatchintro Introduction to Patching
|
|
||||||
|
|
||||||
The standard method for creating patches requires developers to:
|
|
||||||
- checkout the git repository (or bring a copy up-to-date),
|
|
||||||
- make the necessary modifications to a working copy,
|
|
||||||
- check with 'git status' to see which files will be modified/added, and
|
|
||||||
- use 'git diff' to review the changes and produce a patch.
|
|
||||||
|
|
||||||
It is important to minimize the changes to only those lines that contain
|
|
||||||
important differences; do not allow stray whitespace changes into your
|
|
||||||
patches, and keep the focus to a single logical change.
|
|
||||||
|
|
||||||
@section primerpatchcreate Creating Patches
|
|
||||||
|
|
||||||
You can create a patch (from the root of your working copy) with a
|
|
||||||
command like the following example: @par
|
|
||||||
@verbatim
|
|
||||||
git diff > patch-name.patch
|
|
||||||
@endverbatim
|
|
||||||
|
|
||||||
where @a patch-name should be something that is descriptive and unique.
|
|
||||||
|
|
||||||
The above command will create a patch containing all of the changes in
|
|
||||||
the working copy; if you want to obtain a subset, simply provide the
|
|
||||||
list of files to the command: @par
|
|
||||||
@verbatim
|
|
||||||
git diff doc > <patch-name>-doc.patch
|
|
||||||
git diff src > <patch-name>-src.patch
|
|
||||||
@endverbatim
|
|
||||||
|
|
||||||
This will create two patches, each containing only those changes present
|
|
||||||
in the subdirectory specified.
|
|
||||||
|
|
||||||
@subsection primerpatchcreate Naming Patches
|
|
||||||
|
|
||||||
One developer has evolved an informal standard for naming his patches: @par
|
|
||||||
@verbatim
|
|
||||||
<project>-<lod>-<action>-<task>.patch
|
|
||||||
@endverbatim
|
|
||||||
|
|
||||||
where @a project is @c openocd, @a lod (line-of-development) could be a
|
|
||||||
subsystem (e.g. @c jtag, @c jlink, etc.) or other group identifier,
|
|
||||||
@a action is @c add, @c change, @c fix, @c update, etc., and @a task is
|
|
||||||
whatever the patch will accomplish (in 2-4 words).
|
|
||||||
|
|
||||||
This scheme does not need to be followed, but it is helpful for
|
|
||||||
maintainers that receive many patches. You do not want your own
|
|
||||||
@c openocd.patch file to be accidentally overwritten by another
|
|
||||||
submission, sending your patch to the bit bucket on accident.
|
|
||||||
|
|
||||||
@section primerpatchpreflight Developer Review
|
|
||||||
|
|
||||||
Before sending in patches, please make sure you have updated to the
|
|
||||||
latest version of the trunk (using <code>git pull</code>) before creating
|
|
||||||
your patch. This helps to increase the chances that it will apply
|
|
||||||
cleanly to the trunk. However, the content matters most.
|
|
||||||
|
|
||||||
When creating a patch using "<code>git diff</code>", git will
|
|
||||||
produce a patch that contains all of the changes in your working copy.
|
|
||||||
To manage multiple changes at once, you either need one working copy per
|
|
||||||
patch, or you can specified specific files and directories when using
|
|
||||||
<code>git diff</code>. Overlapping patches will be discussed in the
|
|
||||||
next section.
|
|
||||||
|
|
||||||
@todo Does git's treatment of line-endings behave sanely?
|
|
||||||
Basically, the repository should use newlines internally,
|
|
||||||
and convert to/from CRLF on Windows etc.
|
|
||||||
|
|
||||||
@section primerpatchseries Patch Series
|
|
||||||
|
|
||||||
As was mentioned above, each patch should contain one logical @c task,
|
|
||||||
and multiple logical tasks should be split into a series of patches.
|
|
||||||
There are no hard guidelines for how that is to be done; it's an art
|
|
||||||
form. Many simple changes should not have to worry about being split,
|
|
||||||
as they will naturally represent a single task.
|
|
||||||
|
|
||||||
When working on several different non-intersecting lines of development,
|
|
||||||
a combination of multiple working copies and patch series management
|
|
||||||
techniques can become critical to efficiently managing change. This
|
|
||||||
again is an area where developers have favorite methodologies that are
|
|
||||||
simply a matter of taste or familiarity; your mileage may vary.
|
|
||||||
|
|
||||||
Packages such as @c patchutils, @c diffutils, and @c quilt are among
|
|
||||||
those that have proved themselves invaluable for these type of tasks.
|
|
||||||
Others take their patch management a step further, using stkgit or
|
|
||||||
some other framework on top of git.
|
|
||||||
|
|
||||||
@subsection primerpatchseriesinterdiff Using @c interdiff
|
|
||||||
|
|
||||||
The @c patchutils package includes the @c interdiff command, which
|
|
||||||
produces a patch that contains the changes made between two other
|
|
||||||
patches. This command can be used to manage the creation of trivial
|
|
||||||
patch series. For example, the following sequence of commands will
|
|
||||||
produce three patches: @par
|
|
||||||
@verbatim
|
|
||||||
$ cd openocd/
|
|
||||||
$ git pull
|
|
||||||
...
|
|
||||||
$ <<<start changes for patch #1>>>
|
|
||||||
...
|
|
||||||
$ <<<finish changes for patch #1>>>
|
|
||||||
$ git diff > series-1.patch # patch #1 is easy
|
|
||||||
$ <<<start changes for patch #2>>>
|
|
||||||
...
|
|
||||||
$ <<<finish changes for patch #2>>>
|
|
||||||
$ git diff > series-1+2.patch # create patch 1+2
|
|
||||||
$ interdiff series-1{,+2}.patch > series-2.patch # 1 ~ 1+2 => #2
|
|
||||||
$ <<<start changes for patch #3>>>
|
|
||||||
...
|
|
||||||
$ <<<finish changes for patch #3>>>
|
|
||||||
$ git diff > series-1+2+3.patch # create patch 1+2+3
|
|
||||||
$ interdiff series-1+2{,+3}.patch > series-3.patch # 1+2 ~ 1+2+3 => 3
|
|
||||||
@endverbatim
|
|
||||||
|
|
||||||
This technique falls apart when the repository changes, but this may be
|
|
||||||
suitable for small series of patches.
|
|
||||||
|
|
||||||
@subsection primerpatchseriesquilt Using @c quilt
|
|
||||||
|
|
||||||
The @c quilt package provides scripts to manage series of patches more
|
|
||||||
efficiently than can be managed by hand. For out-of-tree work projects
|
|
||||||
that require such patch management, @c quilt provides an indispensable
|
|
||||||
tool for solving the problem.
|
|
||||||
|
|
||||||
@section primerpatchsubmit Submitting Patches
|
|
||||||
|
|
||||||
Write access to the OpenOCD git repository is limited to
|
|
||||||
contributors that have demonstrated the ability to produce clear,
|
|
||||||
consistent, and frequent patches. These individuals are responsible
|
|
||||||
for maintaining the integrity of the repository for the community.
|
|
||||||
|
|
||||||
Thus, commits to the git repository must be handled by one of
|
|
||||||
these maintainers.
|
|
||||||
|
|
||||||
Patches must be sent to the OpenOCD developer mailing list:
|
|
||||||
@par
|
|
||||||
openocd-development@lists.berlios.de
|
|
||||||
|
|
||||||
They will be reviewed and committed if the changes are found to be
|
|
||||||
acceptable. If there are problems, you will receive feedback via the
|
|
||||||
mailing list; in general, the maintainers prefer all communication to go
|
|
||||||
through the list, as the entire community needs to judge contributions
|
|
||||||
for possible merits and mistakes.
|
|
||||||
|
|
||||||
Contributors may be asked to address certain issues and submit a new
|
|
||||||
patch. In the event that it gets overlooked, you may need to resubmit
|
|
||||||
it or prompt for feedback. Please have patience, as many maintainers
|
|
||||||
work on the project voluntarily and without compensation for the time
|
|
||||||
that they spend doing these tasks.
|
|
||||||
|
|
||||||
@section primerpatchguide Guidelines for Submitting Patches
|
|
||||||
|
|
||||||
- Each patch file should contain:
|
|
||||||
- A commit description that describes all of the changes.
|
|
||||||
- A separator line that contains three hyphens: <code>---</code>
|
|
||||||
- A summary of the changes produced by diffstat (optional)
|
|
||||||
- Another separator line (optional)
|
|
||||||
- The actual patch contents, containing a single change.
|
|
||||||
|
|
||||||
- Each patch series should include:
|
|
||||||
- A summary of the patches in the series.
|
|
||||||
- Logically-related patches that contain incremental changes.
|
|
||||||
|
|
||||||
*/
|
|
||||||
/** @file
|
|
||||||
This file contains the @ref primerpatches page.
|
|
||||||
*/
|
|
||||||
@@ -107,14 +107,14 @@ original code base. Each packager release should have a unique
|
|||||||
version.
|
version.
|
||||||
|
|
||||||
For example, the following command will add a 'foo' tag to the
|
For example, the following command will add a 'foo' tag to the
|
||||||
configure.in script of a local copy of the source tree, giving
|
configure.ac script of a local copy of the source tree, giving
|
||||||
a version label like <em>0.3.0-foo</em>:
|
a version label like <em>0.3.0-foo</em>:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
tools/release/version.sh version tag add foo
|
tools/release/version.sh tag add foo
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
This command will modify the configure.in script in your working copy
|
This command will modify the configure.ac script in your working copy
|
||||||
only. After running the @c bootstrap sequence, the tree can be patched
|
only. After running the @c bootstrap sequence, the tree can be patched
|
||||||
and used to produce your own derived versions. You might check that
|
and used to produce your own derived versions. You might check that
|
||||||
change into a private branch of your git tree, along with the other
|
change into a private branch of your git tree, along with the other
|
||||||
@@ -125,7 +125,7 @@ each time a derived package is released, incrementing the tag's
|
|||||||
version to facilitate tracking the changes you have distributed.
|
version to facilitate tracking the changes you have distributed.
|
||||||
|
|
||||||
@code
|
@code
|
||||||
tools/release/version.sh version bump tag foo
|
tools/release/version.sh bump tag foo
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
Of course, any patches in your branches must be provided to
|
Of course, any patches in your branches must be provided to
|
||||||
@@ -296,7 +296,7 @@ The following steps should be followed to produce each release:
|
|||||||
be needed (except to seed the process for the next release, or maybe
|
be needed (except to seed the process for the next release, or maybe
|
||||||
if a significant and longstanding bug is fixed late in the RC phase).
|
if a significant and longstanding bug is fixed late in the RC phase).
|
||||||
-# Bump library version if our API changed (not yet required)
|
-# Bump library version if our API changed (not yet required)
|
||||||
-# Update and commit the final package version in @c configure.in:
|
-# Update and commit the final package version in @c configure.ac:
|
||||||
(The <code>tools/release/version.sh</code> script might help ensure
|
(The <code>tools/release/version.sh</code> script might help ensure
|
||||||
the versions are named properly.):
|
the versions are named properly.):
|
||||||
-# Remove @c -dev tag.
|
-# Remove @c -dev tag.
|
||||||
@@ -306,7 +306,7 @@ The following steps should be followed to produce each release:
|
|||||||
- If producing the next RC in a series, bump the rc number
|
- If producing the next RC in a series, bump the rc number
|
||||||
-# Commit that version change, with a good descriptive comment.
|
-# Commit that version change, with a good descriptive comment.
|
||||||
-# Create a git tag for the final commit, with a tag name matching
|
-# Create a git tag for the final commit, with a tag name matching
|
||||||
the version string in <code>configure.in</code> (including <em>-rcN</em>
|
the version string in <code>configure.ac</code> (including <em>-rcN</em>
|
||||||
where relevant):
|
where relevant):
|
||||||
@verbatim
|
@verbatim
|
||||||
PACKAGE_VERSION="x.y.z"
|
PACKAGE_VERSION="x.y.z"
|
||||||
@@ -322,14 +322,14 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
|||||||
the last ones to be included in the release being made.
|
the last ones to be included in the release being made.
|
||||||
-# Produce the release files, using the local clone of the source
|
-# Produce the release files, using the local clone of the source
|
||||||
tree which holds the release's tag and updated version in
|
tree which holds the release's tag and updated version in
|
||||||
@c configure.in ... this is used only to produce the release, and
|
@c configure.ac ... this is used only to produce the release, and
|
||||||
all files should already be properly checked out.
|
all files should already be properly checked out.
|
||||||
-# Run <code>tools/release.sh package</code> to produce the
|
-# Run <code>tools/release.sh package</code> to produce the
|
||||||
source archives. This automatically bootstraps and
|
source archives. This automatically bootstraps and
|
||||||
configures the process.
|
configures the process.
|
||||||
-# Run <code>tools/release.sh stage</code> to create an @c archives
|
-# Run <code>tools/release.sh stage</code> to create an @c archives
|
||||||
directory with the release data, including MD5 and SHA1
|
directory with the release data, including MD5 and SHA1
|
||||||
checksum files (which are used with Berlios).
|
checksum files.
|
||||||
-# Sanity check at least one of those archives, by extracting and
|
-# Sanity check at least one of those archives, by extracting and
|
||||||
configuring its contents, using them to build a copy of OpenOCD,
|
configuring its contents, using them to build a copy of OpenOCD,
|
||||||
and verifying that the result prints the correct release version
|
and verifying that the result prints the correct release version
|
||||||
@@ -357,13 +357,6 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
|||||||
- .zip: Windows
|
- .zip: Windows
|
||||||
- For openocd.pdf just associate it with the right release notes.
|
- For openocd.pdf just associate it with the right release notes.
|
||||||
-# Create an SF.net project news update.
|
-# Create an SF.net project news update.
|
||||||
- Berlios:
|
|
||||||
-# Provide @c NEWS file, as requested.
|
|
||||||
-# Upload the release files via FTP to ftp://ftp.berlios.de/incoming/
|
|
||||||
-# Edit descriptions for each file (one at a time) Note that Berlios
|
|
||||||
does not automatically checksum files, and it uses a very old
|
|
||||||
version of the SourceForge code with user interface issues.
|
|
||||||
-# Click button to send E-mail Release Notice.
|
|
||||||
-# Depending on how paranoid you're feeling today, verify the images by
|
-# Depending on how paranoid you're feeling today, verify the images by
|
||||||
downloading them from the websites and making sure there are no
|
downloading them from the websites and making sure there are no
|
||||||
differences between the downloaded copies and your originals.
|
differences between the downloaded copies and your originals.
|
||||||
@@ -372,16 +365,15 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
|||||||
User's Guide, and HTML for the developer's guide ... you can
|
User's Guide, and HTML for the developer's guide ... you can
|
||||||
instantiate a shell.sourceforge.net instance and set up symlinks
|
instantiate a shell.sourceforge.net instance and set up symlinks
|
||||||
from your home directory, to simplify this process.
|
from your home directory, to simplify this process.
|
||||||
-# (How to update the Berlios web site with the same data?)
|
|
||||||
-# Post announcement e-mail to the openocd-development list.
|
-# Post announcement e-mail to the openocd-development list.
|
||||||
-# optionally:
|
-# optionally:
|
||||||
-# Post an update on the Berlios blog (if it lets you)
|
-# Post an update on the OpenOCD blog.
|
||||||
-# Announce updates on freshmeat.net and other trackers.
|
-# Announce updates on freshmeat.net and other trackers.
|
||||||
-# Submit updates to news feeds (e.g. Digg, Reddit, etc.).
|
-# Submit updates to news feeds (e.g. Digg, Reddit, etc.).
|
||||||
-# Resume normal development on mainline, by opening the merge window for
|
-# Resume normal development on mainline, by opening the merge window for
|
||||||
the next major or minor release cycle. (You might want to do this
|
the next major or minor release cycle. (You might want to do this
|
||||||
before all the release bits are fully published.)
|
before all the release bits are fully published.)
|
||||||
- Update the version label in the @c configure.in file:
|
- Update the version label in the @c configure.ac file:
|
||||||
- Restore @c -dev version tag.
|
- Restore @c -dev version tag.
|
||||||
- For a new minor release cycle, increment the release's minor number
|
- For a new minor release cycle, increment the release's minor number
|
||||||
- For a new major release cycle, increment the release's major number
|
- For a new major release cycle, increment the release's major number
|
||||||
@@ -404,7 +396,7 @@ To start a bug-fix release branch:
|
|||||||
-# Create a new branch, starting from a major or
|
-# Create a new branch, starting from a major or
|
||||||
minor release tag
|
minor release tag
|
||||||
-# Restore @c -dev version tag.
|
-# Restore @c -dev version tag.
|
||||||
-# Bump micro version number in configure.in
|
-# Bump micro version number in configure.ac
|
||||||
-# Backport bugfix patches from mainline into that branch.
|
-# Backport bugfix patches from mainline into that branch.
|
||||||
(Always be sure mainline has the fix first, so it's hard
|
(Always be sure mainline has the fix first, so it's hard
|
||||||
to just lose a bugfix.)
|
to just lose a bugfix.)
|
||||||
|
|||||||
@@ -309,3 +309,8 @@ This section needs to be expanded.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @page serverhttp OpenOCD http Server API
|
||||||
|
|
||||||
|
This section needs to be expanded.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ Finally, try to avoid lines of code that are longer than than 72-80 columns:
|
|||||||
- inline functions
|
- inline functions
|
||||||
- @c // comments -- in new code, prefer these for single-line comments
|
- @c // comments -- in new code, prefer these for single-line comments
|
||||||
- trailing comma allowed in enum declarations
|
- trailing comma allowed in enum declarations
|
||||||
- designated initializers (@{ .field = value @})
|
- designated initializers ( .field = value )
|
||||||
- variables declarations should occur at the point of first use
|
- variables declarations should occur at the point of first use
|
||||||
- new block scopes for selection and iteration statements
|
- new block scopes for selection and iteration statements
|
||||||
- use malloc() to create dynamic arrays. Do @b not use @c alloca
|
- use malloc() to create dynamic arrays. Do @b not use @c alloca
|
||||||
@@ -370,7 +370,7 @@ Maintainers must also be sure to follow additional guidelines:
|
|||||||
|
|
||||||
This page contains style guidelines for the OpenOCD autotools scripts.
|
This page contains style guidelines for the OpenOCD autotools scripts.
|
||||||
|
|
||||||
The following guidelines apply to the @c configure.in file:
|
The following guidelines apply to the @c configure.ac file:
|
||||||
- Better guidelines need to be developed, but until then...
|
- Better guidelines need to be developed, but until then...
|
||||||
- Use good judgement.
|
- Use good judgement.
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ The Target Support module contains APIs that cover several functional areas:
|
|||||||
|
|
||||||
- @subpage targetarm
|
- @subpage targetarm
|
||||||
- @subpage targetnotarm
|
- @subpage targetnotarm
|
||||||
|
- @subpage targetmips
|
||||||
- @subpage targetregister
|
- @subpage targetregister
|
||||||
- @subpage targetimage
|
- @subpage targetimage
|
||||||
- @subpage targettrace
|
- @subpage targettrace
|
||||||
|
|||||||
536
doc/manual/target/mips.txt
Normal file
536
doc/manual/target/mips.txt
Normal file
@@ -0,0 +1,536 @@
|
|||||||
|
/** @page targetmips OpenOCD MIPS Targets
|
||||||
|
|
||||||
|
@section ejatgmem EJTAG Memory Addresses
|
||||||
|
|
||||||
|
An optional uncached and unmapped debug segment dseg (EJTAG area) appears in the address range
|
||||||
|
0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF3F FFFF. The dseg segment thereby appears in the kseg part of the
|
||||||
|
compatibility segment, and access to kseg is possible with the dseg segment.
|
||||||
|
|
||||||
|
The dseg segment is subdivided into dmseg (EJTAG memory) segment and the drseg (EJTAG registers) segment. The
|
||||||
|
dmseg segment is used when the probe services the memory segment. The drseg segment is used when the
|
||||||
|
memory-mapped debug registers are accessed. Table 5-2 shows the subdivision and attributes for the segments.
|
||||||
|
|
||||||
|
dseg is divided in :
|
||||||
|
|
||||||
|
- dmseg (0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF2F FFFF)
|
||||||
|
- drseg (0xFFFF FFFF FF30 0000 to 0xFFFF FFFF FF3F FFFF)
|
||||||
|
|
||||||
|
Because the dseg segment is serviced exclusively by the EJTAG features, there
|
||||||
|
are no physical address per se. Instead the lower 21 bits of the virtual address select
|
||||||
|
the appropriate reference in either EJTAG memory or registers. References are not mapped through the
|
||||||
|
TLB, nor do the accesses appear on the external system memory interface.
|
||||||
|
|
||||||
|
Both of this memory segments are Uncached.
|
||||||
|
|
||||||
|
On debug exception (break) CPU jumps to the beginning of dmseg. This some kind of memory shared
|
||||||
|
between CPU and EJTAG dongle.
|
||||||
|
|
||||||
|
There CPU stops (correct terminology is : stalls, because it stops it's pipeline), and is waiting for some action of dongle.
|
||||||
|
|
||||||
|
If the dongle gives it instruction, CPU executes it, augments it's PC to 0xFFFF FFFF FF20 0001 - but it again points to dmseg area,
|
||||||
|
so it stops waiting for next instruction.
|
||||||
|
|
||||||
|
This will all become clear later, after reading following prerequisite chapters.
|
||||||
|
|
||||||
|
@section impflags Important flags
|
||||||
|
|
||||||
|
@subsection pnnw PNnW
|
||||||
|
|
||||||
|
Indicates read or write of a pending processor access:
|
||||||
|
|
||||||
|
- 0 : Read processor access, for a fetch/load access
|
||||||
|
- 1 : Write processor access, for a store access
|
||||||
|
|
||||||
|
This value is defined only when a processor access is pending.
|
||||||
|
|
||||||
|
Processor will do the action for us : it can for example read internal state (register values),
|
||||||
|
and send us back the information via EJTAG memory (dmseg), or it can take some data from dmseg and write it into the registers or RAM.
|
||||||
|
|
||||||
|
Every time when it sees address (i.e. when this address is the part of the opcode it is executing, wether it is instruction or data fetch)
|
||||||
|
that falls into dmseg, processor stalls. That acutally meand that CPU stops it's pipeline and it is waitning for dongle to take some action.
|
||||||
|
|
||||||
|
CPU is now either waiting for dongle to take some data from dmseg (if we requested for CPU do give us internal state, for example),
|
||||||
|
or it will wait for some data from dongle (if it needs following instruction because it did previous, or if the operand address of the currently executed opcode
|
||||||
|
falls somewhere (anywhere) in dmseg (0xff..ff20000 - 0xff..ff2fffff)).
|
||||||
|
|
||||||
|
Bit PNnW describes character of CPU access to EJTAG memory (the memry where dongle puts/takes data) - CPU can either READ for it (PNnW == 0) or
|
||||||
|
WRITE to it (PNnW == 1).
|
||||||
|
|
||||||
|
By reading PNnW bit OpenOCD will know if it has to send (PNnW == 0) or to take (PNnW == 1) data (from dmseg, via dongle).
|
||||||
|
|
||||||
|
@subsection pracc PrAcc
|
||||||
|
|
||||||
|
Indicates a pending processor access and controls finishing of a pending processor access.
|
||||||
|
|
||||||
|
When read:
|
||||||
|
|
||||||
|
- 0 : No pending processor access
|
||||||
|
- 1 : Pending processor access
|
||||||
|
|
||||||
|
A write of 0 finishes a processor access if pending;
|
||||||
|
otherwise operation of the processor is UNDEFINED
|
||||||
|
if the bit is written to 0 when no processor access is
|
||||||
|
pending. A write of 1 is ignored.
|
||||||
|
|
||||||
|
A successful FASTDATA access will clear this bit.
|
||||||
|
|
||||||
|
As noted above, on any access to dmseg, processor will stall. It waits for dongle to do some action - either to take or put some data.
|
||||||
|
OpenOCD can figure out which action has to be taken by reading PrAcc bit.
|
||||||
|
|
||||||
|
Once action from dongle has been done, i.e. after the data is taken/put, OpenOCD can signal to CPU to proceed with executing the instruction.
|
||||||
|
This can be the next instruction (if previous was finished before pending), or the same instruction - if for example CPU was waiting on dongle
|
||||||
|
to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That prowoked the CPU to stall (it tried operand fetch to dmseg and stopped),
|
||||||
|
and PNnW bit is 0 (CPU does read from dmseg), and PrAcc is 1 (CPU is pending on dmseg access).
|
||||||
|
|
||||||
|
@subsection spracc SPrAcc
|
||||||
|
|
||||||
|
Shifting in a zero value requests completion of the Fastdata access.
|
||||||
|
|
||||||
|
The PrAcc bit in the EJTAG Control register is overwritten with zero when the access
|
||||||
|
succeeds. (The access succeeds if PrAcc is one and the operation address is in the legal dmseg segment
|
||||||
|
Fastdata area.)
|
||||||
|
|
||||||
|
When successful, a one is shifted out. Shifting out a zero indicates a Fastdata access failure.
|
||||||
|
Shifting in a one does not complete the Fastdata access and the PrAcc bit is unchanged. Shifting out a
|
||||||
|
one indicates that the access would have been successful if allowed to complete and a zero indicates
|
||||||
|
the access would not have successfully completed.
|
||||||
|
|
||||||
|
@section fdreg Fastdata Register (TAP Instruction FASTDATA)
|
||||||
|
|
||||||
|
The width of the Fastdata register is 1 bit.
|
||||||
|
|
||||||
|
During a Fastdata access, the Fastdata register is written and read, i.e., a bit is
|
||||||
|
shifted in and a bit is shifted out.
|
||||||
|
|
||||||
|
Also during a Fastdata access, the Fastdata register value shifted in specifies whether the Fastdata
|
||||||
|
access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata access was
|
||||||
|
successful or not (if completion was requested).
|
||||||
|
|
||||||
|
@section ejtagacc EJTAG Access Implementation
|
||||||
|
|
||||||
|
OpenOCD reads/writes data to JTAG via mips_m4k_read_memory() and mips_m4k_write_memory() functions defined in src/target/mips_m4k.c.
|
||||||
|
Internally, these functions call mips32_pracc_read_mem() and mips32_pracc_write_mem() defined in src/target/mips32_pracc.c
|
||||||
|
|
||||||
|
Let's take for example function mips32_pracc_read_mem32() which describes CPU reads (fetches) from dmseg (EJTAG memory) :
|
||||||
|
|
||||||
|
@code
|
||||||
|
static const uint32_t code[] = {
|
||||||
|
/* start: */
|
||||||
|
MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
|
||||||
|
MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
|
||||||
|
MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
|
||||||
|
MIPS32_SW(8,0,15), /* sw $8,($15) */
|
||||||
|
MIPS32_SW(9,0,15), /* sw $9,($15) */
|
||||||
|
MIPS32_SW(10,0,15), /* sw $10,($15) */
|
||||||
|
MIPS32_SW(11,0,15), /* sw $11,($15) */
|
||||||
|
|
||||||
|
MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
|
||||||
|
MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
|
||||||
|
MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */
|
||||||
|
MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */
|
||||||
|
MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
|
||||||
|
MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
|
||||||
|
/* loop: */
|
||||||
|
MIPS32_BEQ(0,10,8), /* beq 0, $10, end */
|
||||||
|
MIPS32_NOP,
|
||||||
|
|
||||||
|
MIPS32_LW(8,0,9), /* lw $8,0($9), Load $8 with the word @mem[$9] */
|
||||||
|
MIPS32_SW(8,0,11), /* sw $8,0($11) */
|
||||||
|
|
||||||
|
MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
|
||||||
|
MIPS32_ADDI(9,9,4), /* $1 += 4 */
|
||||||
|
MIPS32_ADDI(11,11,4), /* $11 += 4 */
|
||||||
|
|
||||||
|
MIPS32_B(NEG16(8)), /* b loop */
|
||||||
|
MIPS32_NOP,
|
||||||
|
/* end: */
|
||||||
|
MIPS32_LW(11,0,15), /* lw $11,($15) */
|
||||||
|
MIPS32_LW(10,0,15), /* lw $10,($15) */
|
||||||
|
MIPS32_LW(9,0,15), /* lw $9,($15) */
|
||||||
|
MIPS32_LW(8,0,15), /* lw $8,($15) */
|
||||||
|
MIPS32_B(NEG16(27)), /* b start */
|
||||||
|
MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
We have to pass this code to CPU via dongle via dmseg.
|
||||||
|
|
||||||
|
After debug exception CPU will find itself stalling at the begining of the dmseg. It waits for the first instruction from dongle.
|
||||||
|
This is MIPS32_MTC0(15,31,0), so CPU saves C0 and continues to addr 0xFF20 0001, which falls also to dmseg, so it stalls.
|
||||||
|
Dongle proceeds giving to CPU one by one instruction in this manner.
|
||||||
|
|
||||||
|
However, things are not so simple. If you take a look at the program, you will see that some instructions take operands. If it has to take
|
||||||
|
operand from the address in dmseg, CPU will stall witing for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0.
|
||||||
|
If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to nex instruction. But since PC for next instruction
|
||||||
|
points to dmseg, it will stall, so that dongle can pass next instruction.
|
||||||
|
|
||||||
|
Some instuctions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed -
|
||||||
|
will not stall on addresses in RAM).
|
||||||
|
|
||||||
|
To have information about CPU is currently (does it stalls wanting on operand or it jumped somewhere waiting for next instruction),
|
||||||
|
OpenOCD has to call TAP ADDRESS instruction, which will ask CPU to give us his address within EJTAG memory :
|
||||||
|
|
||||||
|
@code
|
||||||
|
address = data = 0;
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
|
||||||
|
mips_ejtag_drscan_32(ejtag_info, &address);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
And then, upon the results, we can conclude where it is in our code so far, so we can give it what it wants next :
|
||||||
|
|
||||||
|
@code
|
||||||
|
if ((address >= MIPS32_PRACC_PARAM_IN)
|
||||||
|
&& (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
|
||||||
|
{
|
||||||
|
offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
|
||||||
|
data = ctx->local_iparam[offset];
|
||||||
|
}
|
||||||
|
else if ((address >= MIPS32_PRACC_PARAM_OUT)
|
||||||
|
&& (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
|
||||||
|
{
|
||||||
|
offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
|
||||||
|
data = ctx->local_oparam[offset];
|
||||||
|
}
|
||||||
|
else if ((address >= MIPS32_PRACC_TEXT)
|
||||||
|
&& (address <= MIPS32_PRACC_TEXT + ctx->code_len * 4))
|
||||||
|
{
|
||||||
|
offset = (address - MIPS32_PRACC_TEXT) / 4;
|
||||||
|
data = ctx->code[offset];
|
||||||
|
}
|
||||||
|
else if (address == MIPS32_PRACC_STACK)
|
||||||
|
{
|
||||||
|
/* save to our debug stack */
|
||||||
|
data = ctx->stack[--ctx->stack_offset];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: send JMP 0xFF200000 instruction.
|
||||||
|
Hopefully processor jump back to start of debug vector */
|
||||||
|
data = 0;
|
||||||
|
LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address);
|
||||||
|
return ERROR_JTAG_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
i.e. if CPU is stalling on addresses in dmseg that are reserved for input parameters, we can conclude that it actually tried to take (read)
|
||||||
|
parametar from there, and saw that address of param falls in dmseg, so it stopped. Obviously, now dongle have to give to it operand.
|
||||||
|
|
||||||
|
Similarly, mips32_pracc_exec_write() describes CPU writes into EJTAG memory (dmseg).
|
||||||
|
Obvioulsy, code is RO, and CPU can change only parameters :
|
||||||
|
|
||||||
|
@code
|
||||||
|
mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
|
||||||
|
mips_ejtag_drscan_32(ctx->ejtag_info, &data);
|
||||||
|
|
||||||
|
/* Clear access pending bit */
|
||||||
|
ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
|
||||||
|
mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
|
||||||
|
mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl);
|
||||||
|
|
||||||
|
//jtag_add_clocks(5);
|
||||||
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
if ((address >= MIPS32_PRACC_PARAM_IN)
|
||||||
|
&& (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
|
||||||
|
{
|
||||||
|
offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
|
||||||
|
ctx->local_iparam[offset] = data;
|
||||||
|
}
|
||||||
|
else if ((address >= MIPS32_PRACC_PARAM_OUT)
|
||||||
|
&& (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
|
||||||
|
{
|
||||||
|
offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
|
||||||
|
ctx->local_oparam[offset] = data;
|
||||||
|
}
|
||||||
|
else if (address == MIPS32_PRACC_STACK)
|
||||||
|
{
|
||||||
|
/* save data onto our stack */
|
||||||
|
ctx->stack[ctx->stack_offset++] = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address);
|
||||||
|
return ERROR_JTAG_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
CPU loops here :
|
||||||
|
|
||||||
|
@code
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
address = data = 0;
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
|
||||||
|
mips_ejtag_drscan_32(ejtag_info, &address);
|
||||||
|
|
||||||
|
/* Check for read or write */
|
||||||
|
if (ejtag_ctrl & EJTAG_CTRL_PRNW)
|
||||||
|
{
|
||||||
|
if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check to see if its reading at the debug vector. The first pass through
|
||||||
|
* the module is always read at the vector, so the first one we allow. When
|
||||||
|
* the second read from the vector occurs we are done and just exit. */
|
||||||
|
if ((address == MIPS32_PRACC_TEXT) && (pass++))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cycle == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
and using presented R (mips32_pracc_exec_read()) and W (mips32_pracc_exec_write()) functions it reads in the code (RO) and reads and writes operands (RW).
|
||||||
|
|
||||||
|
@section fdimpl OpenOCD FASTDATA Implementation
|
||||||
|
|
||||||
|
OpenOCD FASTDATA write function, mips32_pracc_fastdata_xfer() is called from bulk_write_memory callback, which writes a count items of 4 bytes
|
||||||
|
to the memory of a target at the an address given. Because it operates only on whole words, this should be faster than target_write_memory().
|
||||||
|
|
||||||
|
In order to implement FASTDATA write, mips32_pracc_fastdata_xfer() uses the following handler :
|
||||||
|
|
||||||
|
@code
|
||||||
|
uint32_t handler_code[] = {
|
||||||
|
/* caution when editing, table is modified below */
|
||||||
|
/* r15 points to the start of this code */
|
||||||
|
MIPS32_SW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15),
|
||||||
|
MIPS32_SW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15),
|
||||||
|
MIPS32_SW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15),
|
||||||
|
MIPS32_SW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15),
|
||||||
|
/* start of fastdata area in t0 */
|
||||||
|
MIPS32_LUI(8,UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
|
||||||
|
MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
|
||||||
|
MIPS32_LW(9,0,8), /* start addr in t1 */
|
||||||
|
MIPS32_LW(10,0,8), /* end addr to t2 */
|
||||||
|
/* loop: */
|
||||||
|
/* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */
|
||||||
|
/* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */
|
||||||
|
MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */
|
||||||
|
MIPS32_ADDI(9,9,4), /* addi t1,t1,4 */
|
||||||
|
|
||||||
|
MIPS32_LW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15),
|
||||||
|
MIPS32_LW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15),
|
||||||
|
MIPS32_LW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15),
|
||||||
|
MIPS32_LW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15),
|
||||||
|
|
||||||
|
MIPS32_LUI(15,UPPER16(MIPS32_PRACC_TEXT)),
|
||||||
|
MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_TEXT)),
|
||||||
|
MIPS32_JR(15), /* jr start */
|
||||||
|
MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
In the begining and the end of the handler we have fuction prologue (save the regs that will be clobbered) and epilogue (restore regs),
|
||||||
|
and in the very end, after all the xfer have been done, we do jump to the MIPS32_PRACC_TEXT address, i.e. Debug Exception Vector location.
|
||||||
|
We will use this fact (that we came back to MIPS32_PRACC_TEXT) to verify later if all the handler is executed (because when in RAM,
|
||||||
|
processor do not stall - it executes all instructions untill one of them do not demand access to dmseg (if one of it's opernads is there)).
|
||||||
|
|
||||||
|
This handler is put into the RAM and executed from there, and not instruction by instruction, like in previous simple write
|
||||||
|
(mips_m4k_write_memory()) and read (mips_m4k_read_memory()) functions.
|
||||||
|
|
||||||
|
N.B. When it is executing this code in RAM, CPU will not stall on instructions, but execute all until it comes to the :
|
||||||
|
|
||||||
|
@code
|
||||||
|
MIPS32_LW(9,0,8) /* start addr in t1 */
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
and there it will stall - because it will see that one of the operands have to be fetched from dmseg (EJTAG memory, in this case FASTDATA memory segment).
|
||||||
|
|
||||||
|
This handler is loaded in the RAM, ath the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected
|
||||||
|
in that way that it is not clobbered (overwritten) by data we want to write-in using FASTDATA.
|
||||||
|
|
||||||
|
What is executed instruction by instruction which is passed by dongle (via EJATG memory) is small jump code, which jumps at the handler in RAM.
|
||||||
|
CPU stalls on dmseg when receiving these jmp_code instructions, but once it jumps in RAM, CPU do not stall anymore and executes bunch of handler instructions.
|
||||||
|
Untill it comes to the first instruction which has an operand in FASTDATA area. There it stalls and waits on action from probe.
|
||||||
|
It happens actually when CPU comes to this loop :
|
||||||
|
|
||||||
|
@code
|
||||||
|
MIPS32_LW(9,0,8), /* start addr in t1 */
|
||||||
|
MIPS32_LW(10,0,8), /* end addr to t2 */
|
||||||
|
/* loop: */
|
||||||
|
/* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */
|
||||||
|
/* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */
|
||||||
|
MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
and then it stalls because operand in r8 points to FASTDATA area.
|
||||||
|
|
||||||
|
OpenOCD first verifies that CPU came to this place by :
|
||||||
|
|
||||||
|
@code
|
||||||
|
/* next fetch to dmseg should be in FASTDATA_AREA, check */
|
||||||
|
address = 0;
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
|
||||||
|
mips_ejtag_drscan_32(ejtag_info, &address);
|
||||||
|
|
||||||
|
if (address != MIPS32_PRACC_FASTDATA_AREA)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
and then passes to CPU start and end address of the loop region for handler in RAM.
|
||||||
|
|
||||||
|
In the loop in handler, CPU sees that it has to take and operand from FSTDATA area (to write it to the dst in RAM after), and so it stalls, putting PrAcc to "1".
|
||||||
|
OpenOCD fills the data via this loop :
|
||||||
|
|
||||||
|
@code
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
/* Send the data out using fastdata (clears the access pending bit) */
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
|
||||||
|
if ((retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds in executing the endler. However, since handler is in a assembly loop,
|
||||||
|
CPU comes to next instruction which also fetches data from FASTDATA area. So it stalls.
|
||||||
|
Then OpenOCD fills the data again, from it's (OpenOCD's) loop. And this game continues untill all the data has been filled.
|
||||||
|
|
||||||
|
After the last data has beend given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, rhis instruction do not point into dmseg, so
|
||||||
|
CPU executes bunch of handler instructions (all prologue) and in the end jumps to MIPS32_PRACC_TEXT address.
|
||||||
|
|
||||||
|
On it's side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correclty executed all the rest of the handler in RAM,
|
||||||
|
and that is not stuck somewhere in the RAM, or stalling on some acces in dmseg - that would be an error :
|
||||||
|
|
||||||
|
@code
|
||||||
|
address = 0;
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
|
||||||
|
mips_ejtag_drscan_32(ejtag_info, &address);
|
||||||
|
|
||||||
|
if (address != MIPS32_PRACC_TEXT)
|
||||||
|
LOG_ERROR("mini program did not return to start");
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@section fdejtagspec EJTAG spec on FASTDATA access
|
||||||
|
|
||||||
|
The width of the Fastdata register is 1 bit. During a Fastdata access, the Fastdata register is written and read, i.e., a bit
|
||||||
|
is shifted in and a bit is shifted out. During a Fastdata access, the Fastdata register value shifted in specifies whether
|
||||||
|
the Fastdata access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata
|
||||||
|
access was successful or not (if completion was requested).
|
||||||
|
|
||||||
|
The FASTDATA access is used for efficient block transfers between dmseg (on the probe) and target memory (on the
|
||||||
|
processor). An "upload" is defined as a sequence of processor loads from target memory and stores to dmseg. A
|
||||||
|
"download" is a sequence of processor loads from dmseg and stores to target memory. The "Fastdata area" specifies
|
||||||
|
the legal range of dmseg addresses (0xFF20.0000 - 0xFF20.000F) that can be used for uploads and downloads. The
|
||||||
|
Data + Fastdata registers (selected with the FASTDATA instruction) allow efficient completion of pending Fastdata
|
||||||
|
area accesses.
|
||||||
|
During Fastdata uploads and downloads, the processor will stall on accesses to the Fastdata area. The PrAcc (processor
|
||||||
|
access pending bit) will be 1 indicating the probe is required to complete the access. Both upload and download
|
||||||
|
accesses are attempted by shifting in a zero SPrAcc value (to request access completion) and shifting out SPrAcc to
|
||||||
|
see if the attempt will be successful (i.e., there was an access pending and a legal Fastdata area address was used).
|
||||||
|
Downloads will also shift in the data to be used to satisfy the load from dmseg’s Fastdata area, while uploads will
|
||||||
|
shift out the data being stored to dmseg’s Fastdata area.
|
||||||
|
As noted above, two conditions must be true for the Fastdata access to succeed. These are:
|
||||||
|
|
||||||
|
- PrAcc must be 1, i.e., there must be a pending processor access.
|
||||||
|
- The Fastdata operation must use a valid Fastdata area address in dmseg (0xFF20.0000 to 0xFF20.000F).
|
||||||
|
|
||||||
|
Basically, because FASTDATA area in dmseg is 16 bytes, we transfer (0xFF20.0000 - 0xFF20.000F)
|
||||||
|
FASTDATA scan TAP instruction selects the Data and the Fastdata registers at once.
|
||||||
|
|
||||||
|
They come in order :
|
||||||
|
TDI -> | Data register| -> | Fastdata register | -> TDO
|
||||||
|
|
||||||
|
FASTDATA register is 1-bit width register. It takes in SPrAcc bit which should be shifted first,
|
||||||
|
followed by 32 bit of data.
|
||||||
|
|
||||||
|
Scan width of FASTDTA is 33 bits in total : 33 bits are shifted in and 33 bits are shifted out.
|
||||||
|
|
||||||
|
First bit that is shifted out is SPrAcc that comes out of Fastdata register and should give us status on FATSDATA write we want to do.
|
||||||
|
|
||||||
|
@section fdcheck OpenOCD misses FASTDATA check
|
||||||
|
|
||||||
|
Download flow (probe -> target block transfer) :
|
||||||
|
|
||||||
|
1) Probe transfer target execution to a loop in target memory doing a fixed number of "loads" to fastdata area of dmseg (and stores to the target download destination.)
|
||||||
|
|
||||||
|
2) Probe loops attempting to satisfy the loads "expected" from the target.
|
||||||
|
On FASTDATA access "successful" move on to next "load".
|
||||||
|
On FASTDATA access "failure" repeat until "successful" or timeout.
|
||||||
|
(A "failure" is an attempt to satisfy an access when none are pending.)
|
||||||
|
|
||||||
|
Note: A failure may have a recoverable (and even expected) cause like slow target execution of the load loop. Other failures may be due to unexpected more troublesome causes like an exception while in debug mode or a target hang on a bad target memory access.
|
||||||
|
|
||||||
|
Shifted out SPrAcc bit inform us that there was CPU access pendingand that it can be complete.
|
||||||
|
|
||||||
|
Basically, we should do following procedure :
|
||||||
|
|
||||||
|
- Download (dongle -> CPU) :
|
||||||
|
You shift "download" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete.
|
||||||
|
|
||||||
|
If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.)
|
||||||
|
|
||||||
|
- Upload (CPU -> dongle) :
|
||||||
|
You shift "dummy" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. The "upload" is the DATA shifted out of the target.
|
||||||
|
|
||||||
|
If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.)
|
||||||
|
|
||||||
|
Basically, if checking first (before scan) if CPU is pending on FASTDATA access (PrAcc is "1"), like this
|
||||||
|
|
||||||
|
@code
|
||||||
|
wait(ready);
|
||||||
|
do_scan();
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
which is inefficient, we should do it like this :
|
||||||
|
|
||||||
|
@code
|
||||||
|
BEGIN :
|
||||||
|
do_scan();
|
||||||
|
if (!was_ready)
|
||||||
|
goto BEGIN;
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
by checking SPrAcc that we shifted out.
|
||||||
|
|
||||||
|
If some FASTDATA write fails, OpenOCD will continue with it's loop (on the host side), but CPU will rest pending (on the target side)
|
||||||
|
waiting for correct FASTDATA write.
|
||||||
|
|
||||||
|
Since OpenOCD goes ahead, it will eventually finish it's loop, and proceede to check if CPU took all the data. But since CPU did not took all the data,
|
||||||
|
it is still turns in handler's loop in RAM, stalling on Fastdata area so this check :
|
||||||
|
|
||||||
|
@code
|
||||||
|
address = 0;
|
||||||
|
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
|
||||||
|
retval = mips_ejtag_drscan_32(ejtag_info, &address);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (address != MIPS32_PRACC_TEXT)
|
||||||
|
LOG_ERROR("mini program did not return to start");
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
fails, and that gives us enough information of the failure.
|
||||||
|
|
||||||
|
In this case, we can lower the JTAG frquency and try again, bacuse most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access).
|
||||||
|
However, the reasons for failure might be numerous : reset, exceptions which can occur in debug mode, bus hangs, etc.
|
||||||
|
|
||||||
|
If lowering the JTAG freq does not work either, we can fall back to more robust solution with patch posted below.
|
||||||
|
|
||||||
|
To summarize, FASTDATA communication goes as following :
|
||||||
|
|
||||||
|
-# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signall it by putting PrAcc to "0"
|
||||||
|
-# When PrAcc goes to "0" CPU execute one opcode sent by EJTAG via DATA reg. Then it pends on next access, waiting for PrAcc to be put to "0" again
|
||||||
|
-# Following this game, OpenOCD first loads handler code in RAM, and then sends the jmp_code - instruction by instruction via DATA reg, which redirects CPU to handler previously set up in RAM
|
||||||
|
-# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions untill first "fetch" to Fastdata area - then it stops and pends.
|
||||||
|
-# So - when it comes to any instruction (opcode) in this handler in RAM which reads (or writes) to Fastdata area (0xF..F20.0000 to 0xF..F20.000F), CPU stops (i.e. stalls access).
|
||||||
|
I.e. it stops on this lw opcode and waits to FASTDATA TAP command from the probe.
|
||||||
|
-# CPU continues only if OpenOCD shifted in SPrAcc "0" (and if the PrAcc was "1"). It shifts-out "1" to tell us that it was OK (processor was stalled, so it can complete the access),
|
||||||
|
and that it continued execution of the handler in RAM.
|
||||||
|
-# If PrAcc was not "1" CPU will not continue (go to next instruction), but will shift-out "0" and keep stalling on the same instruction of my handler in RAM.
|
||||||
|
-# When Fastdata loop is finished, CPU executes all following hadler instructions in RAM (prologue).
|
||||||
|
-# In the end of my handler in RAM, I jumps back to begining of Debug Exception Vector Location 0xFF200200 in dmseg.
|
||||||
|
-# When it jumps back to 0xFF200200 in dmseg processor stops and pends, waiting for OpenOCD to send it instruction via DATA reg and signal it by putting PrAcc to "0".
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -78,7 +78,7 @@ Show a help text and exit.
|
|||||||
Show version information and exit.
|
Show version information and exit.
|
||||||
.SH "BUGS"
|
.SH "BUGS"
|
||||||
Please report any bugs on the mailing list at
|
Please report any bugs on the mailing list at
|
||||||
.BR openocd\-development@lists.berlios.de .
|
.BR openocd\-devel@lists.sourceforge.net .
|
||||||
.SH "LICENCE"
|
.SH "LICENCE"
|
||||||
.B OpenOCD
|
.B OpenOCD
|
||||||
is covered by the GNU General Public License (GPL), version 2 or later.
|
is covered by the GNU General Public License (GPL), version 2 or later.
|
||||||
|
|||||||
1214
doc/openocd.texi
1214
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
|||||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
|
||||||
## -------------------------------------------
|
|
||||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
|
||||||
## Copyright (C) 2008 Øyvind Harboe
|
|
||||||
##
|
|
||||||
## eCos is free software; you can redistribute it and/or modify it under
|
|
||||||
## the terms of the GNU General Public License as published by the Free
|
|
||||||
## Software Foundation; either version 2 or (at your option) any later version.
|
|
||||||
##
|
|
||||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
## for more details.
|
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along
|
|
||||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
##
|
|
||||||
## As a special exception, if other files instantiate templates or use macros
|
|
||||||
## or inline functions from this file, or you compile this file and link it
|
|
||||||
## with other works to produce a work based on this file, this file does not
|
|
||||||
## by itself cause the resulting work to be covered by the GNU General Public
|
|
||||||
## License. However the source code for this file must still be made available
|
|
||||||
## in accordance with section (3) of the GNU General Public License.
|
|
||||||
##
|
|
||||||
## This exception does not invalidate any other reasons why a work based on
|
|
||||||
## this file might be covered by the GNU General Public License.
|
|
||||||
## -------------------------------------------
|
|
||||||
#####ECOSGPLCOPYRIGHTEND####
|
|
||||||
|
|
||||||
# Create OpenOCD eCos flash driver
|
|
||||||
# Syntax: make INSTALL_DIR=ecosinstalldir OUTPUT=outputname
|
|
||||||
|
|
||||||
include $(INSTALL_DIR)/include/pkgconf/ecos.mak
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(ECOS_COMMAND_PREFIX)gcc $(ECOS_GLOBAL_CFLAGS) $(ECOS_GLOBAL_LDFLAGS) -g -o debug_$(OUTPUT).elf -nostdlib flash.S flash.c -Wl,--gc-sections -I$(INSTALL_DIR)/include -Wl,$(INSTALL_DIR)/lib/libtarget.a -Wl,-Map,flash.map
|
|
||||||
cp debug_$(OUTPUT).elf $(OUTPUT).elf
|
|
||||||
$(ECOS_COMMAND_PREFIX)strip $(OUTPUT).elf
|
|
||||||
echo Flash driver $(OUTPUT).elf
|
|
||||||
|
|
||||||
Binary file not shown.
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
|
||||||
## -------------------------------------------
|
|
||||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
|
||||||
## Copyright (C) 2008 Øyvind Harboe
|
|
||||||
##
|
|
||||||
## eCos is free software; you can redistribute it and/or modify it under
|
|
||||||
## the terms of the GNU General Public License as published by the Free
|
|
||||||
## Software Foundation; either version 2 or (at your option) any later version.
|
|
||||||
##
|
|
||||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
## for more details.
|
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along
|
|
||||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
##
|
|
||||||
## As a special exception, if other files instantiate templates or use macros
|
|
||||||
## or inline functions from this file, or you compile this file and link it
|
|
||||||
## with other works to produce a work based on this file, this file does not
|
|
||||||
## by itself cause the resulting work to be covered by the GNU General Public
|
|
||||||
## License. However the source code for this file must still be made available
|
|
||||||
## in accordance with section (3) of the GNU General Public License.
|
|
||||||
##
|
|
||||||
## This exception does not invalidate any other reasons why a work based on
|
|
||||||
## this file might be covered by the GNU General Public License.
|
|
||||||
## -------------------------------------------
|
|
||||||
#####ECOSGPLCOPYRIGHTEND####
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Jump table for flash driver
|
|
||||||
|
|
||||||
Registers in ARM callling convention is to place args in registers
|
|
||||||
starting at r0.
|
|
||||||
|
|
||||||
So for:
|
|
||||||
|
|
||||||
void foo(int a, int b, int c).
|
|
||||||
|
|
||||||
a=r0
|
|
||||||
b=r1
|
|
||||||
c=r2
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
.global _stack_base
|
|
||||||
.global _stack_start
|
|
||||||
.global _workarea
|
|
||||||
.global _start
|
|
||||||
.global _start_bss_clear
|
|
||||||
_start:
|
|
||||||
// offset=0
|
|
||||||
// int erase(void *address, int len)
|
|
||||||
ldr sp,=_stack_start
|
|
||||||
bl erase
|
|
||||||
nop // Stop CPU here using hw breakpoint
|
|
||||||
|
|
||||||
// offset=0xc
|
|
||||||
// int program(void *buffer, void *address, int len)
|
|
||||||
ldr sp,=_stack_start
|
|
||||||
bl program
|
|
||||||
nop // Stop CPU here using hw breakpoint
|
|
||||||
|
|
||||||
// offset=0x18
|
|
||||||
ldr r0,=_workarea
|
|
||||||
nop // Stop CPU here using hw breakpoint
|
|
||||||
|
|
||||||
// offset=0x20
|
|
||||||
// int init() - returns error message if the flash chip can't be detected
|
|
||||||
ldr sp,=_stack_start
|
|
||||||
bl init
|
|
||||||
nop // Stop CPU here using hw breakpoint
|
|
||||||
|
|
||||||
.section ".bss"
|
|
||||||
.balign 4
|
|
||||||
_stack_base:
|
|
||||||
.rept 4096
|
|
||||||
.byte 0
|
|
||||||
.endr
|
|
||||||
_stack_start:
|
|
||||||
.balign 4
|
|
||||||
_workarea:
|
|
||||||
.rept 8192
|
|
||||||
.byte 0
|
|
||||||
.endr
|
|
||||||
// NB!!! we clear bss while the stack is in use, so we start BSS clearing here !!! :-)
|
|
||||||
_start_bss_clear:
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
|
||||||
## -------------------------------------------
|
|
||||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
|
||||||
## Copyright (C) 2008 Øyvind Harboe
|
|
||||||
##
|
|
||||||
## eCos is free software; you can redistribute it and/or modify it under
|
|
||||||
## the terms of the GNU General Public License as published by the Free
|
|
||||||
## Software Foundation; either version 2 or (at your option) any later version.
|
|
||||||
##
|
|
||||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
## for more details.
|
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along
|
|
||||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
##
|
|
||||||
## As a special exception, if other files instantiate templates or use macros
|
|
||||||
## or inline functions from this file, or you compile this file and link it
|
|
||||||
## with other works to produce a work based on this file, this file does not
|
|
||||||
## by itself cause the resulting work to be covered by the GNU General Public
|
|
||||||
## License. However the source code for this file must still be made available
|
|
||||||
## in accordance with section (3) of the GNU General Public License.
|
|
||||||
##
|
|
||||||
## This exception does not invalidate any other reasons why a work based on
|
|
||||||
## this file might be covered by the GNU General Public License.
|
|
||||||
## -------------------------------------------
|
|
||||||
#####ECOSGPLCOPYRIGHTEND####
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#define _FLASH_PRIVATE_
|
|
||||||
#include <cyg/io/flash.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int myprintf(char *format, ...)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern char _start_bss_clear;
|
|
||||||
extern char __bss_end__;
|
|
||||||
|
|
||||||
int init()
|
|
||||||
{
|
|
||||||
// set up runtime environment
|
|
||||||
char *t;
|
|
||||||
for (t=&_start_bss_clear; t<&__bss_end__; t++)
|
|
||||||
{
|
|
||||||
*t=0;
|
|
||||||
}
|
|
||||||
return flash_init((_printf *)&myprintf);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int checkFlash(void *addr, int len)
|
|
||||||
{
|
|
||||||
// Return error for illegal addresses
|
|
||||||
if ((addr<flash_info.start)||(addr>flash_info.end))
|
|
||||||
return FLASH_ERR_INVALID;
|
|
||||||
if ((((cyg_uint8 *)addr)+len)>(cyg_uint8 *)flash_info.end)
|
|
||||||
return FLASH_ERR_INVALID;
|
|
||||||
return FLASH_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int erase(void *address, int len)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
void *failAddress;
|
|
||||||
|
|
||||||
retval=checkFlash(address, len);
|
|
||||||
if (retval!=0)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
retval=init();
|
|
||||||
if (retval!=0)
|
|
||||||
return retval;
|
|
||||||
return flash_erase(address, len, &failAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern char _end;
|
|
||||||
|
|
||||||
// Data follows immediately after program, long word aligned.
|
|
||||||
int program(void *buffer, void *address, int len)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
void *failAddress;
|
|
||||||
retval=checkFlash(address, len);
|
|
||||||
if (retval!=0)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
retval=init();
|
|
||||||
if (retval!=0)
|
|
||||||
return retval;
|
|
||||||
//int flash_program(void *_addr, void *_data, int len, void **err_addr)
|
|
||||||
return flash_program(address, buffer, len, &failAddress);
|
|
||||||
}
|
|
||||||
@@ -1,390 +0,0 @@
|
|||||||
Archive member included because of file (symbol)
|
|
||||||
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
/ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o (flash_init)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (flash_hwr_init)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (memcpy)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (memcmp)
|
|
||||||
|
|
||||||
Memory Configuration
|
|
||||||
|
|
||||||
Name Origin Length Attributes
|
|
||||||
*default* 0x00000000 0xffffffff
|
|
||||||
|
|
||||||
Linker script and memory map
|
|
||||||
|
|
||||||
LOAD /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
LOAD /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
LOAD /tmp/ecosboard/ecos/install/lib/libtarget.a
|
|
||||||
0x00008000 PROVIDE (__executable_start, 0x8000)
|
|
||||||
0x00008000 . = 0x8000
|
|
||||||
|
|
||||||
.interp
|
|
||||||
*(.interp)
|
|
||||||
|
|
||||||
.hash
|
|
||||||
*(.hash)
|
|
||||||
|
|
||||||
.dynsym
|
|
||||||
*(.dynsym)
|
|
||||||
|
|
||||||
.dynstr
|
|
||||||
*(.dynstr)
|
|
||||||
|
|
||||||
.gnu.version
|
|
||||||
*(.gnu.version)
|
|
||||||
|
|
||||||
.gnu.version_d
|
|
||||||
*(.gnu.version_d)
|
|
||||||
|
|
||||||
.gnu.version_r
|
|
||||||
*(.gnu.version_r)
|
|
||||||
|
|
||||||
.rel.dyn
|
|
||||||
*(.rel.init)
|
|
||||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
|
||||||
*(.rel.fini)
|
|
||||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
|
||||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
|
||||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
|
||||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
|
||||||
*(.rel.ctors)
|
|
||||||
*(.rel.dtors)
|
|
||||||
*(.rel.got)
|
|
||||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
|
||||||
|
|
||||||
.rela.dyn
|
|
||||||
*(.rela.init)
|
|
||||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
|
||||||
*(.rela.fini)
|
|
||||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
|
||||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
|
||||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
|
||||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
|
||||||
*(.rela.ctors)
|
|
||||||
*(.rela.dtors)
|
|
||||||
*(.rela.got)
|
|
||||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
|
||||||
|
|
||||||
.rel.plt
|
|
||||||
*(.rel.plt)
|
|
||||||
|
|
||||||
.rela.plt
|
|
||||||
*(.rela.plt)
|
|
||||||
|
|
||||||
.init
|
|
||||||
*(.init)
|
|
||||||
|
|
||||||
.plt
|
|
||||||
*(.plt)
|
|
||||||
|
|
||||||
.text 0x00008000 0x6f8
|
|
||||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
|
||||||
.text 0x00008000 0x34 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
0x00008000 _start
|
|
||||||
.text.myprintf
|
|
||||||
0x00008034 0x10 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
0x00008034 myprintf
|
|
||||||
.text.init 0x00008044 0x50 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
0x00008044 init
|
|
||||||
.text.erase 0x00008094 0xc0 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
0x00008094 erase
|
|
||||||
.text.program 0x00008154 0xc8 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
0x00008154 program
|
|
||||||
.text.flash_init
|
|
||||||
0x0000821c 0x6c /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x0000821c flash_init
|
|
||||||
.text.flash_dev_query
|
|
||||||
0x00008288 0x20 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x00008288 flash_dev_query
|
|
||||||
.text.flash_erase
|
|
||||||
0x000082a8 0x140 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x000082a8 flash_erase
|
|
||||||
.text.flash_program
|
|
||||||
0x000083e8 0x154 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x000083e8 flash_program
|
|
||||||
.text.flash_hwr_init
|
|
||||||
0x0000853c 0xa4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x0000853c flash_hwr_init
|
|
||||||
.text.flash_hwr_map_error
|
|
||||||
0x000085e0 0x4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x000085e0 flash_hwr_map_error
|
|
||||||
.text.__memcmp
|
|
||||||
0x000085e4 0x114 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
0x000085e4 memcmp
|
|
||||||
0x000085e4 __memcmp
|
|
||||||
*(.gnu.warning)
|
|
||||||
*(.glue_7t)
|
|
||||||
*(.glue_7)
|
|
||||||
|
|
||||||
.2ram.flash_query
|
|
||||||
0x000086f8 0x54
|
|
||||||
.2ram.flash_query
|
|
||||||
0x000086f8 0x54 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x000086f8 flash_query
|
|
||||||
|
|
||||||
.2ram.flash_erase_block
|
|
||||||
0x0000874c 0x230
|
|
||||||
.2ram.flash_erase_block
|
|
||||||
0x0000874c 0x230 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x0000874c flash_erase_block
|
|
||||||
|
|
||||||
.2ram.flash_program_buf
|
|
||||||
0x0000897c 0xe8
|
|
||||||
.2ram.flash_program_buf
|
|
||||||
0x0000897c 0xe8 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x0000897c flash_program_buf
|
|
||||||
|
|
||||||
.fini
|
|
||||||
*(.fini)
|
|
||||||
0x00008a64 PROVIDE (__etext, .)
|
|
||||||
0x00008a64 PROVIDE (_etext, .)
|
|
||||||
0x00008a64 PROVIDE (etext, .)
|
|
||||||
|
|
||||||
.rodata 0x00008a64 0x318
|
|
||||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
|
||||||
.rodata.str1.4
|
|
||||||
0x00008a64 0x1fb /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x1fc (size before relaxing)
|
|
||||||
*fill* 0x00008c5f 0x1 00
|
|
||||||
.rodata.supported_devices
|
|
||||||
0x00008c60 0x11c /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
|
|
||||||
.rodata1
|
|
||||||
*(.rodata1)
|
|
||||||
|
|
||||||
.eh_frame_hdr
|
|
||||||
*(.eh_frame_hdr)
|
|
||||||
0x00008e7c . = (ALIGN (0x100) + (. & 0xff))
|
|
||||||
0x00008e7c . = ALIGN (0x4)
|
|
||||||
0x00008e7c PROVIDE (__preinit_array_start, .)
|
|
||||||
|
|
||||||
.preinit_array
|
|
||||||
*(.preinit_array)
|
|
||||||
0x00008e7c PROVIDE (__preinit_array_end, .)
|
|
||||||
0x00008e7c PROVIDE (__init_array_start, .)
|
|
||||||
|
|
||||||
.init_array
|
|
||||||
*(.init_array)
|
|
||||||
0x00008e7c PROVIDE (__init_array_end, .)
|
|
||||||
0x00008e7c PROVIDE (__fini_array_start, .)
|
|
||||||
|
|
||||||
.fini_array
|
|
||||||
*(.fini_array)
|
|
||||||
0x00008e7c PROVIDE (__fini_array_end, .)
|
|
||||||
|
|
||||||
.data 0x00008e7c 0x0
|
|
||||||
0x00008e7c __data_start = .
|
|
||||||
*(.data .data.* .gnu.linkonce.d.*)
|
|
||||||
|
|
||||||
.data1
|
|
||||||
*(.data1)
|
|
||||||
|
|
||||||
.tdata
|
|
||||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
|
||||||
|
|
||||||
.tbss
|
|
||||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
|
||||||
*(.tcommon)
|
|
||||||
|
|
||||||
.eh_frame
|
|
||||||
*(.eh_frame)
|
|
||||||
|
|
||||||
.gcc_except_table
|
|
||||||
*(.gcc_except_table)
|
|
||||||
|
|
||||||
.dynamic
|
|
||||||
*(.dynamic)
|
|
||||||
|
|
||||||
.ctors
|
|
||||||
*crtbegin*.o(.ctors)
|
|
||||||
*(EXCLUDE_FILE(*crtend*.o) .ctors)
|
|
||||||
*(SORT(.ctors.*))
|
|
||||||
*(.ctors)
|
|
||||||
|
|
||||||
.dtors
|
|
||||||
*crtbegin*.o(.dtors)
|
|
||||||
*(EXCLUDE_FILE(*crtend*.o) .dtors)
|
|
||||||
*(SORT(.dtors.*))
|
|
||||||
*(.dtors)
|
|
||||||
|
|
||||||
.jcr
|
|
||||||
*(.jcr)
|
|
||||||
|
|
||||||
.got
|
|
||||||
*(.got.plt)
|
|
||||||
*(.got)
|
|
||||||
0x00008e7c _edata = .
|
|
||||||
0x00008e7c PROVIDE (edata, .)
|
|
||||||
0x00008e7c __bss_start = .
|
|
||||||
0x00008e7c __bss_start__ = .
|
|
||||||
|
|
||||||
.bss 0x00008e7c 0x3024
|
|
||||||
*(.dynbss)
|
|
||||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
|
||||||
.bss 0x00008e7c 0x3000 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
0x00008e7c _stack_base
|
|
||||||
0x0000be7c _start_bss_clear
|
|
||||||
0x00009e7c _workarea
|
|
||||||
0x00009e7c _stack_start
|
|
||||||
.bss.flash_info
|
|
||||||
0x0000be7c 0x20 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x0000be7c flash_info
|
|
||||||
.bss.flash_dev_info
|
|
||||||
0x0000be9c 0x4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
*(COMMON)
|
|
||||||
0x0000bea0 . = ALIGN (0x4)
|
|
||||||
0x0000bea0 . = ALIGN (0x4)
|
|
||||||
0x0000bea0 _end = .
|
|
||||||
0x0000bea0 _bss_end__ = .
|
|
||||||
0x0000bea0 __bss_end__ = .
|
|
||||||
0x0000bea0 __end__ = .
|
|
||||||
0x0000bea0 PROVIDE (end, .)
|
|
||||||
|
|
||||||
.stab
|
|
||||||
*(.stab)
|
|
||||||
|
|
||||||
.stabstr
|
|
||||||
*(.stabstr)
|
|
||||||
|
|
||||||
.stab.excl
|
|
||||||
*(.stab.excl)
|
|
||||||
|
|
||||||
.stab.exclstr
|
|
||||||
*(.stab.exclstr)
|
|
||||||
|
|
||||||
.stab.index
|
|
||||||
*(.stab.index)
|
|
||||||
|
|
||||||
.stab.indexstr
|
|
||||||
*(.stab.indexstr)
|
|
||||||
|
|
||||||
.comment
|
|
||||||
*(.comment)
|
|
||||||
|
|
||||||
.debug
|
|
||||||
*(.debug)
|
|
||||||
|
|
||||||
.line
|
|
||||||
*(.line)
|
|
||||||
|
|
||||||
.debug_srcinfo
|
|
||||||
*(.debug_srcinfo)
|
|
||||||
|
|
||||||
.debug_sfnames
|
|
||||||
*(.debug_sfnames)
|
|
||||||
|
|
||||||
.debug_aranges 0x00000000 0x170
|
|
||||||
*(.debug_aranges)
|
|
||||||
.debug_aranges
|
|
||||||
0x00000000 0x20 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
.debug_aranges
|
|
||||||
0x00000020 0x48 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_aranges
|
|
||||||
0x00000068 0x68 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_aranges
|
|
||||||
0x000000d0 0x50 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_aranges
|
|
||||||
0x00000120 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_aranges
|
|
||||||
0x00000148 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_pubnames
|
|
||||||
0x00000000 0x1e5
|
|
||||||
*(.debug_pubnames)
|
|
||||||
.debug_pubnames
|
|
||||||
0x00000000 0x4d /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_pubnames
|
|
||||||
0x0000004d 0xca /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_pubnames
|
|
||||||
0x00000117 0x91 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_pubnames
|
|
||||||
0x000001a8 0x1e /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_pubnames
|
|
||||||
0x000001c6 0x1f /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_info 0x00000000 0x1122
|
|
||||||
*(.debug_info .gnu.linkonce.wi.*)
|
|
||||||
.debug_info 0x00000000 0x6e /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
.debug_info 0x0000006e 0x322 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_info 0x00000390 0x4f6 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_info 0x00000886 0x5b2 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_info 0x00000e38 0x1c7 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_info 0x00000fff 0x123 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_abbrev 0x00000000 0x67c
|
|
||||||
*(.debug_abbrev)
|
|
||||||
.debug_abbrev 0x00000000 0x14 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
.debug_abbrev 0x00000014 0x17d /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_abbrev 0x00000191 0x15f /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_abbrev 0x000002f0 0x238 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_abbrev 0x00000528 0xb4 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_abbrev 0x000005dc 0xa0 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_line 0x00000000 0x8de
|
|
||||||
*(.debug_line)
|
|
||||||
.debug_line 0x00000000 0x3e /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
|
||||||
.debug_line 0x0000003e 0xf6 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_line 0x00000134 0x255 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_line 0x00000389 0x287 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_line 0x00000610 0x16c /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_line 0x0000077c 0x162 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_frame 0x00000000 0x2c0
|
|
||||||
*(.debug_frame)
|
|
||||||
.debug_frame 0x00000000 0xa4 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
.debug_frame 0x000000a4 0x110 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_frame 0x000001b4 0xac /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_frame 0x00000260 0x38 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_frame 0x00000298 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
|
|
||||||
.debug_str 0x00000000 0x508
|
|
||||||
*(.debug_str)
|
|
||||||
.debug_str 0x00000000 0x131 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
|
||||||
0x191 (size before relaxing)
|
|
||||||
.debug_str 0x00000131 0x152 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
0x24e (size before relaxing)
|
|
||||||
.debug_str 0x00000283 0x194 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
0x2c5 (size before relaxing)
|
|
||||||
.debug_str 0x00000417 0x7e /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
0x11e (size before relaxing)
|
|
||||||
.debug_str 0x00000495 0x73 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
0x119 (size before relaxing)
|
|
||||||
|
|
||||||
.debug_loc
|
|
||||||
*(.debug_loc)
|
|
||||||
|
|
||||||
.debug_macinfo
|
|
||||||
*(.debug_macinfo)
|
|
||||||
|
|
||||||
.debug_weaknames
|
|
||||||
*(.debug_weaknames)
|
|
||||||
|
|
||||||
.debug_funcnames
|
|
||||||
*(.debug_funcnames)
|
|
||||||
|
|
||||||
.debug_typenames
|
|
||||||
*(.debug_typenames)
|
|
||||||
|
|
||||||
.debug_varnames
|
|
||||||
*(.debug_varnames)
|
|
||||||
|
|
||||||
.stack 0x00080000 0x0
|
|
||||||
0x00080000 _stack = .
|
|
||||||
*(.stack)
|
|
||||||
|
|
||||||
.note.gnu.arm.ident
|
|
||||||
*(.note.gnu.arm.ident)
|
|
||||||
|
|
||||||
/DISCARD/
|
|
||||||
*(.note.GNU-stack)
|
|
||||||
OUTPUT(debug_eb40a.elf elf32-littlearm)
|
|
||||||
|
|
||||||
.debug_ranges 0x00000000 0xb8
|
|
||||||
.debug_ranges 0x00000000 0x18 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
|
||||||
.debug_ranges 0x00000018 0x48 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
|
||||||
.debug_ranges 0x00000060 0x30 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
|
||||||
.debug_ranges 0x00000090 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
Some of these binaries are build & linked using eCos.
|
|
||||||
|
|
||||||
For source for the flash drivers, see:
|
|
||||||
|
|
||||||
http://ecos.sourceware.org/
|
|
||||||
|
|
||||||
2
jimtcl
2
jimtcl
Submodule jimtcl updated: 6233a6c5d3...2c1eba991e
@@ -15,11 +15,7 @@ SUBDIRS = \
|
|||||||
lib_LTLIBRARIES = libopenocd.la
|
lib_LTLIBRARIES = libopenocd.la
|
||||||
bin_PROGRAMS = openocd
|
bin_PROGRAMS = openocd
|
||||||
|
|
||||||
if ECOSBOARD
|
|
||||||
MAINFILE = ecosboard.c
|
|
||||||
else
|
|
||||||
MAINFILE = main.c
|
MAINFILE = main.c
|
||||||
endif
|
|
||||||
|
|
||||||
openocd_SOURCES = $(MAINFILE)
|
openocd_SOURCES = $(MAINFILE)
|
||||||
openocd_LDADD = libopenocd.la
|
openocd_LDADD = libopenocd.la
|
||||||
@@ -30,6 +26,10 @@ else
|
|||||||
openocd_LDADD += -ljim
|
openocd_LDADD += -ljim
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ULINK
|
||||||
|
openocd_LDADD += -lm
|
||||||
|
endif
|
||||||
|
|
||||||
libopenocd_la_SOURCES = \
|
libopenocd_la_SOURCES = \
|
||||||
hello.c \
|
hello.c \
|
||||||
openocd.c \
|
openocd.c \
|
||||||
@@ -77,26 +77,13 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USBPROG
|
|
||||||
LIBUSB = -lusb
|
|
||||||
else
|
|
||||||
if JLINK
|
|
||||||
LIBUSB = -lusb
|
|
||||||
else
|
|
||||||
if RLINK
|
|
||||||
LIBUSB = -lusb
|
|
||||||
else
|
|
||||||
if ULINK
|
|
||||||
LIBUSB = -lusb
|
|
||||||
else
|
|
||||||
if VSLLINK
|
|
||||||
LIBUSB = -lusb
|
|
||||||
else
|
|
||||||
LIBUSB =
|
LIBUSB =
|
||||||
|
if USE_LIBUSB1
|
||||||
|
LIBUSB += -lusb-1.0
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
endif
|
if USE_LIBUSB0
|
||||||
endif
|
LIBUSB += -lusb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libopenocd_la_LIBADD = \
|
libopenocd_la_LIBADD = \
|
||||||
|
|||||||
1670
src/ecosboard.c
1670
src/ecosboard.c
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -32,17 +33,17 @@ unsigned get_flash_name_index(const char *name)
|
|||||||
return ~0U;
|
return ~0U;
|
||||||
unsigned requested;
|
unsigned requested;
|
||||||
int retval = parse_uint(name_index + 1, &requested);
|
int retval = parse_uint(name_index + 1, &requested);
|
||||||
// detect parsing error by forcing past end of bank list
|
/* detect parsing error by forcing past end of bank list */
|
||||||
return (ERROR_OK == retval) ? requested : ~0U;
|
return (ERROR_OK == retval) ? requested : ~0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flash_driver_name_matches(const char *name, const char *expected)
|
bool flash_driver_name_matches(const char *name, const char *expected)
|
||||||
{
|
{
|
||||||
unsigned blen = strlen(name);
|
unsigned blen = strlen(name);
|
||||||
// only match up to the length of the driver name...
|
/* only match up to the length of the driver name... */
|
||||||
if (strncmp(name, expected, blen) != 0)
|
if (strncmp(name, expected, blen) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// ...then check that name terminates at this spot.
|
/* ...then check that name terminates at this spot. */
|
||||||
return expected[blen] == '.' || expected[blen] == '\0';
|
return expected[blen] == '.' || expected[blen] == '\0';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_COMMON_H
|
#ifndef FLASH_COMMON_H
|
||||||
#define FLASH_COMMON_H
|
#define FLASH_COMMON_H
|
||||||
|
|
||||||
@@ -46,4 +47,4 @@ bool flash_driver_name_matches(const char *name, const char *expected);
|
|||||||
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
||||||
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
|
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
|
||||||
|
|
||||||
#endif // FLASH_COMMON_H
|
#endif /* FLASH_COMMON_H */
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include <helper/fileio.h>
|
#include <helper/fileio.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
|
|
||||||
|
|
||||||
static int s3c2440_set_gpio_to_output(struct mflash_gpio_num gpio);
|
static int s3c2440_set_gpio_to_output(struct mflash_gpio_num gpio);
|
||||||
static int s3c2440_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val);
|
static int s3c2440_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val);
|
||||||
static int pxa270_set_gpio_to_output(struct mflash_gpio_num gpio);
|
static int pxa270_set_gpio_to_output(struct mflash_gpio_num gpio);
|
||||||
@@ -47,8 +46,7 @@ static struct mflash_gpio_drv s3c2440_gpio = {
|
|||||||
.set_gpio_output_val = s3c2440_set_gpio_output_val
|
.set_gpio_output_val = s3c2440_set_gpio_output_val
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mflash_gpio_drv *mflash_gpio[] =
|
static struct mflash_gpio_drv *mflash_gpio[] = {
|
||||||
{
|
|
||||||
&pxa270_gpio,
|
&pxa270_gpio,
|
||||||
&s3c2440_gpio,
|
&s3c2440_gpio,
|
||||||
NULL
|
NULL
|
||||||
@@ -74,14 +72,16 @@ static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio)
|
|||||||
|
|
||||||
addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4;
|
addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4;
|
||||||
|
|
||||||
if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
|
ret = target_read_u32(target, addr, &value);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
value &= ~mask;
|
value &= ~mask;
|
||||||
if (addr == PXA270_GAFR3_U)
|
if (addr == PXA270_GAFR3_U)
|
||||||
value &= ~PXA270_GAFR3_U_RESERVED_BITS;
|
value &= ~PXA270_GAFR3_U_RESERVED_BITS;
|
||||||
|
|
||||||
if ((ret = target_write_u32(target, addr, value)) != ERROR_OK)
|
ret = target_write_u32(target, addr, value);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* set direction to output */
|
/* set direction to output */
|
||||||
@@ -89,7 +89,8 @@ static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio)
|
|||||||
|
|
||||||
addr = PXA270_GPDR0 + (gpio.num >> 5) * 4;
|
addr = PXA270_GPDR0 + (gpio.num >> 5) * 4;
|
||||||
|
|
||||||
if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
|
ret = target_read_u32(target, addr, &value);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
value |= mask;
|
value |= mask;
|
||||||
@@ -108,13 +109,13 @@ static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
|
|||||||
|
|
||||||
mask = 0x1u << (gpio.num & 0x1F);
|
mask = 0x1u << (gpio.num & 0x1F);
|
||||||
|
|
||||||
if (val) {
|
if (val)
|
||||||
addr = PXA270_GPSR0 + (gpio.num >> 5) * 4;
|
addr = PXA270_GPSR0 + (gpio.num >> 5) * 4;
|
||||||
} else {
|
else
|
||||||
addr = PXA270_GPCR0 + (gpio.num >> 5) * 4;
|
addr = PXA270_GPCR0 + (gpio.num >> 5) * 4;
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = target_read_u32(target, addr, &value)) != ERROR_OK)
|
ret = target_read_u32(target, addr, &value);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
value |= mask;
|
value |= mask;
|
||||||
@@ -135,13 +136,13 @@ static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio)
|
|||||||
struct target *target = mflash_bank->target;
|
struct target *target = mflash_bank->target;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
|
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h')
|
||||||
gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10;
|
gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10;
|
||||||
} else if (gpio.port[0] == 'j') {
|
else if (gpio.port[0] == 'j')
|
||||||
gpio_con = S3C2440_GPJCON;
|
gpio_con = S3C2440_GPJCON;
|
||||||
} else {
|
else {
|
||||||
LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
|
LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = target_read_u32(target, gpio_con, &data);
|
ret = target_read_u32(target, gpio_con, &data);
|
||||||
@@ -167,13 +168,13 @@ static int s3c2440_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val
|
|||||||
struct target *target = mflash_bank->target;
|
struct target *target = mflash_bank->target;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
|
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h')
|
||||||
gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10;
|
gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10;
|
||||||
} else if (gpio.port[0] == 'j') {
|
else if (gpio.port[0] == 'j')
|
||||||
gpio_dat = S3C2440_GPJDAT;
|
gpio_dat = S3C2440_GPJDAT;
|
||||||
} else {
|
else {
|
||||||
LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
|
LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port);
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = target_read_u32(target, gpio_dat, &data);
|
ret = target_read_u32(target, gpio_dat, &data);
|
||||||
@@ -226,13 +227,11 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
|
|||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (status & mg_io_rbit_status_busy)
|
if (status & mg_io_rbit_status_busy) {
|
||||||
{
|
|
||||||
if (wait_local == mg_io_wait_bsy)
|
if (wait_local == mg_io_wait_bsy)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else {
|
} else {
|
||||||
switch (wait_local)
|
switch (wait_local) {
|
||||||
{
|
|
||||||
case mg_io_wait_not_bsy:
|
case mg_io_wait_not_bsy:
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
case mg_io_wait_rdy_noerr:
|
case mg_io_wait_rdy_noerr:
|
||||||
@@ -248,8 +247,7 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now we check the error condition! */
|
/* Now we check the error condition! */
|
||||||
if (status & mg_io_rbit_status_error)
|
if (status & mg_io_rbit_status_error) {
|
||||||
{
|
|
||||||
ret = target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error);
|
ret = target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error);
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -259,8 +257,7 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
|
|||||||
return ERROR_MG_IO;
|
return ERROR_MG_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (wait_local)
|
switch (wait_local) {
|
||||||
{
|
|
||||||
case mg_io_wait_rdy:
|
case mg_io_wait_rdy:
|
||||||
if (status & mg_io_rbit_status_ready)
|
if (status & mg_io_rbit_status_ready)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -295,14 +292,14 @@ static int mg_dsk_srst(uint8_t on)
|
|||||||
uint8_t value;
|
uint8_t value;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value)) != ERROR_OK)
|
ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (on) {
|
if (on)
|
||||||
value |= (mg_io_rbit_devc_srst);
|
value |= (mg_io_rbit_devc_srst);
|
||||||
} else {
|
else
|
||||||
value &= ~mg_io_rbit_devc_srst;
|
value &= ~mg_io_rbit_devc_srst;
|
||||||
}
|
|
||||||
|
|
||||||
ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value);
|
ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -339,7 +336,8 @@ static int mg_dsk_drv_info(void)
|
|||||||
uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;
|
uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_io_cmd(0, 1, mg_io_cmd_identify)) != ERROR_OK)
|
ret = mg_dsk_io_cmd(0, 1, mg_io_cmd_identify);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
||||||
@@ -357,41 +355,53 @@ static int mg_dsk_drv_info(void)
|
|||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mflash_bank->drv_info->tot_sects = (uint32_t)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16)
|
mflash_bank->drv_info->tot_sects =
|
||||||
|
(uint32_t)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16)
|
||||||
+ mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo;
|
+ mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo;
|
||||||
|
|
||||||
return target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);
|
return target_write_u8(target,
|
||||||
|
mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND,
|
||||||
|
mg_io_cmd_confirm_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mg_mflash_rst(void)
|
static int mg_mflash_rst(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_init_gpio()) != ERROR_OK)
|
ret = mg_init_gpio();
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_hdrst(0)) != ERROR_OK)
|
ret = mg_hdrst(0);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
|
ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_hdrst(1)) != ERROR_OK)
|
ret = mg_hdrst(1);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
|
ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_srst(1)) != ERROR_OK)
|
ret = mg_dsk_srst(1);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
|
ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_srst(0)) != ERROR_OK)
|
ret = mg_dsk_srst(0);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG)) != ERROR_OK)
|
ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_INFO("mflash: reset ok");
|
LOG_INFO("mflash: reset ok");
|
||||||
@@ -401,9 +411,8 @@ static int mg_mflash_rst(void)
|
|||||||
|
|
||||||
static int mg_mflash_probe(void)
|
static int mg_mflash_probe(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = mg_mflash_rst();
|
||||||
|
if (ret != ERROR_OK)
|
||||||
if ((ret = mg_mflash_rst()) != ERROR_OK)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return mg_dsk_drv_info();
|
return mg_dsk_drv_info();
|
||||||
@@ -416,8 +425,10 @@ COMMAND_HANDLER(mg_probe_cmd)
|
|||||||
ret = mg_mflash_probe();
|
ret = mg_mflash_probe();
|
||||||
|
|
||||||
if (ret == ERROR_OK) {
|
if (ret == ERROR_OK) {
|
||||||
command_print(CMD_CTX, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
|
command_print(CMD_CTX,
|
||||||
mflash_bank->drv_info->tot_sects, mflash_bank->base);
|
"mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
|
||||||
|
mflash_bank->drv_info->tot_sects,
|
||||||
|
mflash_bank->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -430,7 +441,8 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
|
|||||||
struct target *target = mflash_bank->target;
|
struct target *target = mflash_bank->target;
|
||||||
uint8_t *buff_ptr = buff;
|
uint8_t *buff_ptr = buff;
|
||||||
|
|
||||||
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read)) != ERROR_OK)
|
ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||||
@@ -449,11 +461,14 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
|
|||||||
|
|
||||||
buff_ptr += MG_MFLASH_SECTOR_SIZE;
|
buff_ptr += MG_MFLASH_SECTOR_SIZE;
|
||||||
|
|
||||||
ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read);
|
ret = target_write_u8(target,
|
||||||
|
mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND,
|
||||||
|
mg_io_cmd_confirm_read);
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i,
|
||||||
|
(sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = duration_measure(&bench);
|
ret = duration_measure(&bench);
|
||||||
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
||||||
@@ -495,14 +510,15 @@ static int mg_mflash_read_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt,
|
static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt,
|
||||||
mg_io_type_cmd cmd)
|
uint8_t cmd)
|
||||||
{
|
{
|
||||||
uint32_t i, address;
|
uint32_t i, address;
|
||||||
int ret;
|
int ret;
|
||||||
struct target *target = mflash_bank->target;
|
struct target *target = mflash_bank->target;
|
||||||
uint8_t *buff_ptr = buff;
|
uint8_t *buff_ptr = buff;
|
||||||
|
|
||||||
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd)) != ERROR_OK)
|
ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||||
@@ -521,11 +537,14 @@ static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect
|
|||||||
|
|
||||||
buff_ptr += MG_MFLASH_SECTOR_SIZE;
|
buff_ptr += MG_MFLASH_SECTOR_SIZE;
|
||||||
|
|
||||||
ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write);
|
ret = target_write_u8(target,
|
||||||
|
mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND,
|
||||||
|
mg_io_cmd_confirm_write);
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i,
|
||||||
|
(sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
||||||
|
|
||||||
ret = duration_measure(&bench);
|
ret = duration_measure(&bench);
|
||||||
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
||||||
@@ -591,12 +610,22 @@ static int mg_mflash_read (uint32_t addr, uint8_t *buff, uint32_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (end_addr < next_sec_addr) {
|
if (end_addr < next_sec_addr) {
|
||||||
memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr);
|
memcpy(buff_ptr,
|
||||||
LOG_DEBUG("mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr);
|
sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK),
|
||||||
|
end_addr - cur_addr);
|
||||||
|
LOG_DEBUG(
|
||||||
|
"mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "",
|
||||||
|
end_addr - cur_addr,
|
||||||
|
cur_addr);
|
||||||
cur_addr = end_addr;
|
cur_addr = end_addr;
|
||||||
} else {
|
} else {
|
||||||
memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr);
|
memcpy(buff_ptr,
|
||||||
LOG_DEBUG("mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr);
|
sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK),
|
||||||
|
next_sec_addr - cur_addr);
|
||||||
|
LOG_DEBUG(
|
||||||
|
"mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "",
|
||||||
|
next_sec_addr - cur_addr,
|
||||||
|
cur_addr);
|
||||||
buff_ptr += (next_sec_addr - cur_addr);
|
buff_ptr += (next_sec_addr - cur_addr);
|
||||||
cur_addr = next_sec_addr;
|
cur_addr = next_sec_addr;
|
||||||
}
|
}
|
||||||
@@ -612,9 +641,11 @@ static int mg_mflash_read (uint32_t addr, uint8_t *buff, uint32_t len)
|
|||||||
next_sec_addr += MG_MFLASH_SECTOR_SIZE;
|
next_sec_addr += MG_MFLASH_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt)
|
if (cnt) {
|
||||||
if ((ret = mg_mflash_read_sects(buff_ptr, sect_num, cnt)) != ERROR_OK)
|
ret = mg_mflash_read_sects(buff_ptr, sect_num, cnt);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
|
buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
|
||||||
cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;
|
cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;
|
||||||
@@ -628,7 +659,6 @@ static int mg_mflash_read (uint32_t addr, uint8_t *buff, uint32_t len)
|
|||||||
|
|
||||||
memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
|
memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
|
||||||
LOG_DEBUG("mflash: copies %u byte", (unsigned)(end_addr - cur_addr));
|
LOG_DEBUG("mflash: copies %u byte", (unsigned)(end_addr - cur_addr));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,12 +685,22 @@ static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (end_addr < next_sec_addr) {
|
if (end_addr < next_sec_addr) {
|
||||||
memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr);
|
memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK),
|
||||||
LOG_DEBUG("mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr);
|
buff_ptr,
|
||||||
|
end_addr - cur_addr);
|
||||||
|
LOG_DEBUG(
|
||||||
|
"mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "",
|
||||||
|
end_addr - cur_addr,
|
||||||
|
cur_addr);
|
||||||
cur_addr = end_addr;
|
cur_addr = end_addr;
|
||||||
} else {
|
} else {
|
||||||
memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr);
|
memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK),
|
||||||
LOG_DEBUG("mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr);
|
buff_ptr,
|
||||||
|
next_sec_addr - cur_addr);
|
||||||
|
LOG_DEBUG(
|
||||||
|
"mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "",
|
||||||
|
next_sec_addr - cur_addr,
|
||||||
|
cur_addr);
|
||||||
buff_ptr += (next_sec_addr - cur_addr);
|
buff_ptr += (next_sec_addr - cur_addr);
|
||||||
cur_addr = next_sec_addr;
|
cur_addr = next_sec_addr;
|
||||||
}
|
}
|
||||||
@@ -680,9 +720,11 @@ static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len)
|
|||||||
next_sec_addr += MG_MFLASH_SECTOR_SIZE;
|
next_sec_addr += MG_MFLASH_SECTOR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt)
|
if (cnt) {
|
||||||
if ((ret = mg_mflash_write_sects(buff_ptr, sect_num, cnt)) != ERROR_OK)
|
ret = mg_mflash_write_sects(buff_ptr, sect_num, cnt);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
|
buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE;
|
||||||
cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;
|
cur_addr += cnt * MG_MFLASH_SECTOR_SIZE;
|
||||||
@@ -710,9 +752,8 @@ COMMAND_HANDLER(mg_write_cmd)
|
|||||||
struct fileio fileio;
|
struct fileio fileio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (CMD_ARGC != 3) {
|
if (CMD_ARGC != 3)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
||||||
|
|
||||||
@@ -729,6 +770,7 @@ COMMAND_HANDLER(mg_write_cmd)
|
|||||||
int retval = fileio_size(&fileio, &filesize);
|
int retval = fileio_size(&fileio, &filesize);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
fileio_close(&fileio);
|
fileio_close(&fileio);
|
||||||
|
free(buffer);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,23 +782,25 @@ COMMAND_HANDLER(mg_write_cmd)
|
|||||||
|
|
||||||
size_t buf_cnt;
|
size_t buf_cnt;
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
if ((ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt)) !=
|
ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt);
|
||||||
ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
goto mg_write_cmd_err;
|
goto mg_write_cmd_err;
|
||||||
if ((ret = mg_mflash_write(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
|
ret = mg_mflash_write(address, buffer, MG_FILEIO_CHUNK);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_write_cmd_err;
|
goto mg_write_cmd_err;
|
||||||
address += MG_FILEIO_CHUNK;
|
address += MG_FILEIO_CHUNK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
if ((ret = fileio_read(&fileio, res, buffer, &buf_cnt)) != ERROR_OK)
|
ret = fileio_read(&fileio, res, buffer, &buf_cnt);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_write_cmd_err;
|
goto mg_write_cmd_err;
|
||||||
if ((ret = mg_mflash_write(address, buffer, res)) != ERROR_OK)
|
ret = mg_mflash_write(address, buffer, res);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_write_cmd_err;
|
goto mg_write_cmd_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration_measure(&bench) == ERROR_OK)
|
if (duration_measure(&bench) == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "wrote %ld bytes from file %s "
|
command_print(CMD_CTX, "wrote %ld bytes from file %s "
|
||||||
"in %fs (%0.3f kB/s)", (long)filesize, CMD_ARGV[1],
|
"in %fs (%0.3f kB/s)", (long)filesize, CMD_ARGV[1],
|
||||||
duration_elapsed(&bench), duration_kbps(&bench, filesize));
|
duration_elapsed(&bench), duration_kbps(&bench, filesize));
|
||||||
@@ -781,9 +825,8 @@ COMMAND_HANDLER(mg_dump_cmd)
|
|||||||
struct fileio fileio;
|
struct fileio fileio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (CMD_ARGC != 4) {
|
if (CMD_ARGC != 4)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], size);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], size);
|
||||||
@@ -806,23 +849,25 @@ COMMAND_HANDLER(mg_dump_cmd)
|
|||||||
|
|
||||||
size_t size_written;
|
size_t size_written;
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
if ((ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
|
ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_dump_cmd_err;
|
goto mg_dump_cmd_err;
|
||||||
if ((ret = fileio_write(&fileio, MG_FILEIO_CHUNK, buffer, &size_written))
|
ret = fileio_write(&fileio, MG_FILEIO_CHUNK, buffer, &size_written);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
goto mg_dump_cmd_err;
|
goto mg_dump_cmd_err;
|
||||||
address += MG_FILEIO_CHUNK;
|
address += MG_FILEIO_CHUNK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
if ((ret = mg_mflash_read(address, buffer, res)) != ERROR_OK)
|
ret = mg_mflash_read(address, buffer, res);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_dump_cmd_err;
|
goto mg_dump_cmd_err;
|
||||||
if ((ret = fileio_write(&fileio, res, buffer, &size_written)) != ERROR_OK)
|
ret = fileio_write(&fileio, res, buffer, &size_written);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
goto mg_dump_cmd_err;
|
goto mg_dump_cmd_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration_measure(&bench) == ERROR_OK)
|
if (duration_measure(&bench) == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "dump image (address 0x%8.8" PRIx32 " "
|
command_print(CMD_CTX, "dump image (address 0x%8.8" PRIx32 " "
|
||||||
"size %" PRIu32 ") to file %s in %fs (%0.3f kB/s)",
|
"size %" PRIu32 ") to file %s in %fs (%0.3f kB/s)",
|
||||||
address, size, CMD_ARGV[1],
|
address, size, CMD_ARGV[1],
|
||||||
@@ -847,8 +892,8 @@ static int mg_set_feature(mg_feature_id feature, mg_feature_val config)
|
|||||||
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL))
|
ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = target_write_u8(target, mg_task_reg + MG_REG_FEATURE, feature);
|
ret = target_write_u8(target, mg_task_reg + MG_REG_FEATURE, feature);
|
||||||
@@ -928,9 +973,10 @@ static double mg_do_calc_pll(double XIN, mg_pll_t * p_pll_val, int is_approximat
|
|||||||
|
|
||||||
if ((int)((CLK_OUT + ROUND) / DIV)
|
if ((int)((CLK_OUT + ROUND) / DIV)
|
||||||
== (int)(MG_PLL_CLK_OUT / DIV)) {
|
== (int)(MG_PLL_CLK_OUT / DIV)) {
|
||||||
if (mg_is_valid_pll(XIN, N, CLK_OUT, NO) == ERROR_OK)
|
if (mg_is_valid_pll(XIN, N, CLK_OUT, NO) == ERROR_OK) {
|
||||||
{
|
p_pll_val->lock_cyc =
|
||||||
p_pll_val->lock_cyc = (int)(XIN * MG_PLL_STD_LOCKCYCLE / MG_PLL_STD_INPUTCLK);
|
(int)(XIN * MG_PLL_STD_LOCKCYCLE /
|
||||||
|
MG_PLL_STD_INPUTCLK);
|
||||||
p_pll_val->feedback_div = i;
|
p_pll_val->feedback_div = i;
|
||||||
p_pll_val->input_div = j;
|
p_pll_val->input_div = j;
|
||||||
p_pll_val->output_div = k;
|
p_pll_val->output_div = k;
|
||||||
@@ -1123,18 +1169,18 @@ static int mg_storage_config(void)
|
|||||||
uint8_t buff[512];
|
uint8_t buff[512];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mg_gen_ataid((mg_io_type_drv_info *)(void *)buff);
|
mg_gen_ataid((mg_io_type_drv_info *)(void *)buff);
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo))
|
ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_INFO("mflash: storage config ok");
|
LOG_INFO("mflash: storage config ok");
|
||||||
@@ -1146,8 +1192,8 @@ static int mg_boot_config(void)
|
|||||||
uint8_t buff[512];
|
uint8_t buff[512];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
memset(buff, 0xff, 512);
|
memset(buff, 0xff, 512);
|
||||||
@@ -1157,12 +1203,12 @@ static int mg_boot_config(void)
|
|||||||
buff[2] = 4; /* boot size */
|
buff[2] = 4; /* boot size */
|
||||||
*((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */
|
*((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo))
|
ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_INFO("mflash: boot config ok");
|
LOG_INFO("mflash: boot config ok");
|
||||||
@@ -1181,16 +1227,16 @@ static int mg_set_pll(mg_pll_t *pll)
|
|||||||
buff[6] = pll->input_div; /* PLL Input 5bit Divider */
|
buff[6] = pll->input_div; /* PLL Input 5bit Divider */
|
||||||
buff[7] = pll->output_div; /* PLL Output Divider */
|
buff[7] = pll->output_div; /* PLL Output Divider */
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_wr_pll))
|
ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_wr_pll);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_INFO("mflash: set pll ok");
|
LOG_INFO("mflash: set pll ok");
|
||||||
@@ -1201,16 +1247,16 @@ static int mg_erase_nand(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(NULL, 0, 0, mg_vcmd_purge_nand))
|
ret = mg_mflash_do_write_sects(NULL, 0, 0, mg_vcmd_purge_nand);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default))
|
ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
|
||||||
!= ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
LOG_INFO("mflash: erase nand ok");
|
LOG_INFO("mflash: erase nand ok");
|
||||||
@@ -1223,10 +1269,12 @@ COMMAND_HANDLER(mg_config_cmd)
|
|||||||
mg_pll_t pll;
|
mg_pll_t pll;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = mg_verify_interface()) != ERROR_OK)
|
ret = mg_verify_interface();
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = mg_mflash_rst()) != ERROR_OK)
|
ret = mg_mflash_rst();
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
switch (CMD_ARGC) {
|
switch (CMD_ARGC) {
|
||||||
@@ -1262,7 +1310,8 @@ COMMAND_HANDLER(mg_config_cmd)
|
|||||||
pll.input_div, pll.output_div,
|
pll.input_div, pll.output_div,
|
||||||
pll.lock_cyc);
|
pll.lock_cyc);
|
||||||
|
|
||||||
if ((ret = mg_erase_nand()) != ERROR_OK)
|
ret = mg_erase_nand();
|
||||||
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return mg_set_pll(&pll);
|
return mg_set_pll(&pll);
|
||||||
@@ -1320,9 +1369,8 @@ COMMAND_HANDLER(handle_mflash_init_command)
|
|||||||
if (CMD_ARGC != 0)
|
if (CMD_ARGC != 0)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
static bool mflash_initialized = false;
|
static bool mflash_initialized;
|
||||||
if (mflash_initialized)
|
if (mflash_initialized) {
|
||||||
{
|
|
||||||
LOG_INFO("'mflash init' has already been called");
|
LOG_INFO("'mflash init' has already been called");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -1338,19 +1386,17 @@ COMMAND_HANDLER(mg_bank_cmd)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (CMD_ARGC < 4)
|
if (CMD_ARGC < 4)
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
if ((target = get_target(CMD_ARGV[3])) == NULL)
|
target = get_target(CMD_ARGV[3]);
|
||||||
{
|
if (target == NULL) {
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[3]);
|
LOG_ERROR("target '%s' not defined", CMD_ARGV[3]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mflash_bank = calloc(sizeof(struct mflash_bank), 1);
|
mflash_bank = calloc(sizeof(struct mflash_bank), 1);
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mflash_bank->base);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mflash_bank->base);
|
||||||
/// @todo Verify how this parsing should work, then document it.
|
/** @todo Verify how this parsing should work, then document it. */
|
||||||
char *str;
|
char *str;
|
||||||
mflash_bank->rst_pin.num = strtoul(CMD_ARGV[2], &str, 0);
|
mflash_bank->rst_pin.num = strtoul(CMD_ARGV[2], &str, 0);
|
||||||
if (*str)
|
if (*str)
|
||||||
@@ -1360,10 +1406,9 @@ COMMAND_HANDLER(mg_bank_cmd)
|
|||||||
mflash_bank->target = target;
|
mflash_bank->target = target;
|
||||||
|
|
||||||
for (i = 0; mflash_gpio[i]; i++) {
|
for (i = 0; mflash_gpio[i]; i++) {
|
||||||
if (! strcmp(mflash_gpio[i]->name, CMD_ARGV[0])) {
|
if (!strcmp(mflash_gpio[i]->name, CMD_ARGV[0]))
|
||||||
mflash_bank->gpio_drv = mflash_gpio[i];
|
mflash_bank->gpio_drv = mflash_gpio[i];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!mflash_bank->gpio_drv) {
|
if (!mflash_bank->gpio_drv) {
|
||||||
LOG_ERROR("%s is unsupported soc", CMD_ARGV[0]);
|
LOG_ERROR("%s is unsupported soc", CMD_ARGV[0]);
|
||||||
@@ -1386,6 +1431,7 @@ static const struct command_registration mflash_config_command_handlers[] = {
|
|||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.handler = handle_mflash_init_command,
|
.handler = handle_mflash_init_command,
|
||||||
.help = "initialize mflash devices",
|
.help = "initialize mflash devices",
|
||||||
|
.usage = ""
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
@@ -1394,6 +1440,7 @@ static const struct command_registration mflash_command_handler[] = {
|
|||||||
.name = "mflash",
|
.name = "mflash",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "mflash command group",
|
.help = "mflash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = mflash_config_command_handlers,
|
.chain = mflash_config_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
|
|||||||
@@ -26,14 +26,12 @@ typedef unsigned long mg_io_uint32;
|
|||||||
typedef unsigned short mg_io_uint16;
|
typedef unsigned short mg_io_uint16;
|
||||||
typedef unsigned char mg_io_uint8;
|
typedef unsigned char mg_io_uint8;
|
||||||
|
|
||||||
struct mflash_gpio_num
|
struct mflash_gpio_num {
|
||||||
{
|
|
||||||
char port[2];
|
char port[2];
|
||||||
signed short num;
|
signed short num;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mflash_gpio_drv
|
struct mflash_gpio_drv {
|
||||||
{
|
|
||||||
const char *name;
|
const char *name;
|
||||||
int (*set_gpio_to_output)(struct mflash_gpio_num gpio);
|
int (*set_gpio_to_output)(struct mflash_gpio_num gpio);
|
||||||
int (*set_gpio_output_val)(struct mflash_gpio_num gpio, uint8_t val);
|
int (*set_gpio_output_val)(struct mflash_gpio_num gpio, uint8_t val);
|
||||||
@@ -117,8 +115,7 @@ typedef struct _mg_io_type_drv_info {
|
|||||||
|
|
||||||
} mg_io_type_drv_info;
|
} mg_io_type_drv_info;
|
||||||
|
|
||||||
typedef struct _mg_pll_t
|
typedef struct _mg_pll_t {
|
||||||
{
|
|
||||||
unsigned int lock_cyc;
|
unsigned int lock_cyc;
|
||||||
unsigned short feedback_div; /* 9bit divider */
|
unsigned short feedback_div; /* 9bit divider */
|
||||||
unsigned char input_div; /* 5bit divider */
|
unsigned char input_div; /* 5bit divider */
|
||||||
@@ -130,8 +127,7 @@ struct mg_drv_info {
|
|||||||
uint32_t tot_sects;
|
uint32_t tot_sects;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mflash_bank
|
struct mflash_bank {
|
||||||
{
|
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
|
|
||||||
struct mflash_gpio_num rst_pin;
|
struct mflash_gpio_num rst_pin;
|
||||||
@@ -239,8 +235,7 @@ typedef enum _mg_io_type_rval_dev{
|
|||||||
|
|
||||||
} mg_io_type_rval_dev;
|
} mg_io_type_rval_dev;
|
||||||
|
|
||||||
typedef enum _mg_io_type_cmd
|
typedef enum _mg_io_type_cmd {
|
||||||
{
|
|
||||||
mg_io_cmd_read = 0x20,
|
mg_io_cmd_read = 0x20,
|
||||||
mg_io_cmd_write = 0x30,
|
mg_io_cmd_write = 0x30,
|
||||||
|
|
||||||
@@ -264,20 +259,17 @@ typedef enum _mg_io_type_cmd
|
|||||||
|
|
||||||
} mg_io_type_cmd;
|
} mg_io_type_cmd;
|
||||||
|
|
||||||
typedef enum _mg_feature_id
|
typedef enum _mg_feature_id {
|
||||||
{
|
|
||||||
mg_feature_id_transmode = 0x3
|
mg_feature_id_transmode = 0x3
|
||||||
} mg_feature_id;
|
} mg_feature_id;
|
||||||
|
|
||||||
typedef enum _mg_feature_val
|
typedef enum _mg_feature_val {
|
||||||
{
|
|
||||||
mg_feature_val_trans_default = 0x0,
|
mg_feature_val_trans_default = 0x0,
|
||||||
mg_feature_val_trans_vcmd = 0x3,
|
mg_feature_val_trans_vcmd = 0x3,
|
||||||
mg_feature_val_trand_vcmds = 0x2
|
mg_feature_val_trand_vcmds = 0x2
|
||||||
} mg_feature_val;
|
} mg_feature_val;
|
||||||
|
|
||||||
typedef enum _mg_vcmd
|
typedef enum _mg_vcmd {
|
||||||
{
|
|
||||||
mg_vcmd_update_xipinfo = 0xFA, /* FWPATCH commmand through IOM I/O */
|
mg_vcmd_update_xipinfo = 0xFA, /* FWPATCH commmand through IOM I/O */
|
||||||
mg_vcmd_verify_fwpatch = 0xFB, /* FWPATCH commmand through IOM I/O */
|
mg_vcmd_verify_fwpatch = 0xFB, /* FWPATCH commmand through IOM I/O */
|
||||||
mg_vcmd_update_stgdrvinfo = 0xFC, /* IOM identificatin info program command */
|
mg_vcmd_update_stgdrvinfo = 0xFC, /* IOM identificatin info program command */
|
||||||
@@ -290,8 +282,7 @@ typedef enum _mg_vcmd
|
|||||||
mg_vcmd_wr_otp = 0x8F
|
mg_vcmd_wr_otp = 0x8F
|
||||||
} mg_vcmd;
|
} mg_vcmd;
|
||||||
|
|
||||||
typedef enum _mg_opmode
|
typedef enum _mg_opmode {
|
||||||
{
|
|
||||||
mg_op_mode_xip = 1, /* TRUE XIP */
|
mg_op_mode_xip = 1, /* TRUE XIP */
|
||||||
mg_op_mode_snd = 2, /* BOOT + Storage */
|
mg_op_mode_snd = 2, /* BOOT + Storage */
|
||||||
mg_op_mode_stg = 0 /* Only Storage */
|
mg_op_mode_stg = 0 /* Only Storage */
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ NAND_DRIVERS = \
|
|||||||
davinci.c \
|
davinci.c \
|
||||||
lpc3180.c \
|
lpc3180.c \
|
||||||
lpc32xx.c \
|
lpc32xx.c \
|
||||||
mx2.c \
|
mxc.c \
|
||||||
mx3.c \
|
mx3.c \
|
||||||
orion.c \
|
orion.c \
|
||||||
s3c24xx.c \
|
s3c24xx.c \
|
||||||
@@ -37,7 +37,7 @@ noinst_HEADERS = \
|
|||||||
imp.h \
|
imp.h \
|
||||||
lpc3180.h \
|
lpc3180.h \
|
||||||
lpc32xx.h \
|
lpc32xx.h \
|
||||||
mx2.h \
|
mxc.h \
|
||||||
mx3.h \
|
mx3.h \
|
||||||
s3c24xx.h \
|
s3c24xx.h \
|
||||||
s3c24xx_regs.h \
|
s3c24xx_regs.h \
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
#include "arm_io.h"
|
#include "arm_io.h"
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
#include <target/arm.h>
|
#include <target/arm.h>
|
||||||
|
#include <target/armv7m.h>
|
||||||
#include <target/algorithm.h>
|
#include <target/algorithm.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies code to a working area. This will allocate room for the code plus the
|
* Copies code to a working area. This will allocate room for the code plus the
|
||||||
* additional amount requested if the working area pointer is null.
|
* additional amount requested if the working area pointer is null.
|
||||||
@@ -61,7 +61,7 @@ static int arm_code_to_working_area(struct target *target,
|
|||||||
if (NULL == *area) {
|
if (NULL == *area) {
|
||||||
retval = target_alloc_working_area(target, size, area);
|
retval = target_alloc_working_area(target, size, area);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
LOG_DEBUG("%s: no %d byte buffer", __FUNCTION__, (int) size);
|
LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size);
|
||||||
return ERROR_NAND_NO_BUFFER;
|
return ERROR_NAND_NO_BUFFER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,14 +79,13 @@ static int arm_code_to_working_area(struct target *target,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
|
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
|
||||||
* For now this only supports ARMv4 and ARMv5 cores.
|
* For now this supports ARMv4,ARMv5 and ARMv7-M cores.
|
||||||
*
|
*
|
||||||
* Enhancements to target_run_algorithm() could enable:
|
* Enhancements to target_run_algorithm() could enable:
|
||||||
* - ARMv6 and ARMv7 cores in ARM mode
|
* - ARMv6 and ARMv7 cores in ARM mode
|
||||||
*
|
*
|
||||||
* Different code fragments could handle:
|
* Different code fragments could handle:
|
||||||
* - Thumb2 cores like Cortex-M (needs different byteswapping)
|
* - 16-bit wide data (needs different setup)
|
||||||
* - 16-bit wide data (needs different setup too)
|
|
||||||
*
|
*
|
||||||
* @param nand Pointer to the arm_nand_data struct that defines the I/O
|
* @param nand Pointer to the arm_nand_data struct that defines the I/O
|
||||||
* @param data Pointer to the data to be copied to flash
|
* @param data Pointer to the data to be copied to flash
|
||||||
@@ -96,8 +95,10 @@ static int arm_code_to_working_area(struct target *target,
|
|||||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
||||||
{
|
{
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
struct arm_algorithm algo;
|
struct arm_algorithm armv4_5_algo;
|
||||||
struct arm *armv4_5 = target->arch_info;
|
struct armv7m_algorithm armv7m_algo;
|
||||||
|
void *arm_algo;
|
||||||
|
struct arm *arm = target->arch_info;
|
||||||
struct reg_param reg_params[3];
|
struct reg_param reg_params[3];
|
||||||
uint32_t target_buf;
|
uint32_t target_buf;
|
||||||
uint32_t exit_var = 0;
|
uint32_t exit_var = 0;
|
||||||
@@ -108,7 +109,7 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
* r1 buffer address
|
* r1 buffer address
|
||||||
* r2 buffer length
|
* r2 buffer length
|
||||||
*/
|
*/
|
||||||
static const uint32_t code[] = {
|
static const uint32_t code_armv4_5[] = {
|
||||||
0xe4d13001, /* s: ldrb r3, [r1], #1 */
|
0xe4d13001, /* s: ldrb r3, [r1], #1 */
|
||||||
0xe5c03000, /* strb r3, [r0] */
|
0xe5c03000, /* strb r3, [r0] */
|
||||||
0xe2522001, /* subs r2, r2, #1 */
|
0xe2522001, /* subs r2, r2, #1 */
|
||||||
@@ -118,31 +119,55 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
0xe1200070, /* e: bkpt #0 */
|
0xe1200070, /* e: bkpt #0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
|
/* Inputs:
|
||||||
retval = arm_code_to_working_area(target, code, sizeof(code),
|
* r0 NAND data address (byte wide)
|
||||||
nand->chunk_size, &nand->copy_area);
|
* r1 buffer address
|
||||||
if (retval != ERROR_OK) {
|
* r2 buffer length
|
||||||
return retval;
|
*
|
||||||
|
* see contrib/loaders/flash/armv7m_io.s for src
|
||||||
|
*/
|
||||||
|
static const uint32_t code_armv7m[] = {
|
||||||
|
0x3b01f811,
|
||||||
|
0x3a017003,
|
||||||
|
0xaffaf47f,
|
||||||
|
0xbf00be00,
|
||||||
|
};
|
||||||
|
|
||||||
|
int target_code_size = 0;
|
||||||
|
const uint32_t *target_code_src = NULL;
|
||||||
|
|
||||||
|
/* set up algorithm */
|
||||||
|
if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
|
||||||
|
armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_algo.core_mode = ARM_MODE_THREAD;
|
||||||
|
arm_algo = &armv7m_algo;
|
||||||
|
target_code_size = sizeof(code_armv7m);
|
||||||
|
target_code_src = code_armv7m;
|
||||||
|
} else {
|
||||||
|
armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
|
||||||
|
armv4_5_algo.core_mode = ARM_MODE_SVC;
|
||||||
|
armv4_5_algo.core_state = ARM_STATE_ARM;
|
||||||
|
arm_algo = &armv4_5_algo;
|
||||||
|
target_code_size = sizeof(code_armv4_5);
|
||||||
|
target_code_src = code_armv4_5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
|
||||||
|
retval = arm_code_to_working_area(target, target_code_src, target_code_size,
|
||||||
|
nand->chunk_size, &nand->copy_area);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
nand->op = ARM_NAND_WRITE;
|
nand->op = ARM_NAND_WRITE;
|
||||||
|
|
||||||
/* copy data to work area */
|
/* copy data to work area */
|
||||||
target_buf = nand->copy_area->address + sizeof(code);
|
target_buf = nand->copy_area->address + target_code_size;
|
||||||
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
|
retval = target_write_buffer(target, target_buf, size, data);
|
||||||
if (retval == ERROR_OK && (size & 3) != 0)
|
|
||||||
retval = target_write_memory(target,
|
|
||||||
target_buf + (size & ~3),
|
|
||||||
1, size & 3, data + (size & ~3));
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* set up algorithm and parameters */
|
/* set up parameters */
|
||||||
algo.common_magic = ARM_COMMON_MAGIC;
|
|
||||||
algo.core_mode = ARM_MODE_SVC;
|
|
||||||
algo.core_state = ARM_STATE_ARM;
|
|
||||||
|
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||||
@@ -152,12 +177,12 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||||
|
|
||||||
/* armv4 must exit using a hardware breakpoint */
|
/* armv4 must exit using a hardware breakpoint */
|
||||||
if (armv4_5->is_armv4)
|
if (arm->is_armv4)
|
||||||
exit_var = nand->copy_area->address + sizeof(code) - 4;
|
exit_var = nand->copy_area->address + target_code_size - 4;
|
||||||
|
|
||||||
/* use alg to write data from work area to NAND chip */
|
/* use alg to write data from work area to NAND chip */
|
||||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||||
nand->copy_area->address, exit_var, 1000, &algo);
|
nand->copy_area->address, exit_var, 1000, arm_algo);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
LOG_ERROR("error executing hosted NAND write");
|
LOG_ERROR("error executing hosted NAND write");
|
||||||
|
|
||||||
@@ -180,8 +205,10 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
||||||
{
|
{
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
struct arm_algorithm algo;
|
struct arm_algorithm armv4_5_algo;
|
||||||
struct arm *armv4_5 = target->arch_info;
|
struct armv7m_algorithm armv7m_algo;
|
||||||
|
void *arm_algo;
|
||||||
|
struct arm *arm = target->arch_info;
|
||||||
struct reg_param reg_params[3];
|
struct reg_param reg_params[3];
|
||||||
uint32_t target_buf;
|
uint32_t target_buf;
|
||||||
uint32_t exit_var = 0;
|
uint32_t exit_var = 0;
|
||||||
@@ -192,7 +219,7 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
* r1 NAND data address (byte wide)
|
* r1 NAND data address (byte wide)
|
||||||
* r2 buffer length
|
* r2 buffer length
|
||||||
*/
|
*/
|
||||||
static const uint32_t code[] = {
|
static const uint32_t code_armv4_5[] = {
|
||||||
0xe5d13000, /* s: ldrb r3, [r1] */
|
0xe5d13000, /* s: ldrb r3, [r1] */
|
||||||
0xe4c03001, /* strb r3, [r0], #1 */
|
0xe4c03001, /* strb r3, [r0], #1 */
|
||||||
0xe2522001, /* subs r2, r2, #1 */
|
0xe2522001, /* subs r2, r2, #1 */
|
||||||
@@ -202,23 +229,51 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
0xe1200070, /* e: bkpt #0 */
|
0xe1200070, /* e: bkpt #0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Inputs:
|
||||||
|
* r0 buffer address
|
||||||
|
* r1 NAND data address (byte wide)
|
||||||
|
* r2 buffer length
|
||||||
|
*
|
||||||
|
* see contrib/loaders/flash/armv7m_io.s for src
|
||||||
|
*/
|
||||||
|
static const uint32_t code_armv7m[] = {
|
||||||
|
0xf800780b,
|
||||||
|
0x3a013b01,
|
||||||
|
0xaffaf47f,
|
||||||
|
0xbf00be00,
|
||||||
|
};
|
||||||
|
|
||||||
|
int target_code_size = 0;
|
||||||
|
const uint32_t *target_code_src = NULL;
|
||||||
|
|
||||||
|
/* set up algorithm */
|
||||||
|
if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
|
||||||
|
armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_algo.core_mode = ARM_MODE_THREAD;
|
||||||
|
arm_algo = &armv7m_algo;
|
||||||
|
target_code_size = sizeof(code_armv7m);
|
||||||
|
target_code_src = code_armv7m;
|
||||||
|
} else {
|
||||||
|
armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
|
||||||
|
armv4_5_algo.core_mode = ARM_MODE_SVC;
|
||||||
|
armv4_5_algo.core_state = ARM_STATE_ARM;
|
||||||
|
arm_algo = &armv4_5_algo;
|
||||||
|
target_code_size = sizeof(code_armv4_5);
|
||||||
|
target_code_src = code_armv4_5;
|
||||||
|
}
|
||||||
|
|
||||||
/* create the copy area if not yet available */
|
/* create the copy area if not yet available */
|
||||||
if (nand->op != ARM_NAND_READ || !nand->copy_area) {
|
if (nand->op != ARM_NAND_READ || !nand->copy_area) {
|
||||||
retval = arm_code_to_working_area(target, code, sizeof(code),
|
retval = arm_code_to_working_area(target, target_code_src, target_code_size,
|
||||||
nand->chunk_size, &nand->copy_area);
|
nand->chunk_size, &nand->copy_area);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nand->op = ARM_NAND_READ;
|
nand->op = ARM_NAND_READ;
|
||||||
target_buf = nand->copy_area->address + sizeof(code);
|
target_buf = nand->copy_area->address + target_code_size;
|
||||||
|
|
||||||
/* set up algorithm and parameters */
|
|
||||||
algo.common_magic = ARM_COMMON_MAGIC;
|
|
||||||
algo.core_mode = ARM_MODE_SVC;
|
|
||||||
algo.core_state = ARM_STATE_ARM;
|
|
||||||
|
|
||||||
|
/* set up parameters */
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||||
@@ -228,12 +283,12 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||||
|
|
||||||
/* armv4 must exit using a hardware breakpoint */
|
/* armv4 must exit using a hardware breakpoint */
|
||||||
if (armv4_5->is_armv4)
|
if (arm->is_armv4)
|
||||||
exit_var = nand->copy_area->address + sizeof(code) - 4;
|
exit_var = nand->copy_area->address + target_code_size - 4;
|
||||||
|
|
||||||
/* use alg to write data from NAND chip to work area */
|
/* use alg to write data from NAND chip to work area */
|
||||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||||
nand->copy_area->address, exit_var, 1000, &algo);
|
nand->copy_area->address, exit_var, 1000, arm_algo);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
LOG_ERROR("error executing hosted NAND read");
|
LOG_ERROR("error executing hosted NAND read");
|
||||||
|
|
||||||
@@ -246,4 +301,3 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* Free Software Foundation, Inc.,
|
* Free Software Foundation, Inc.,
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -97,9 +98,8 @@ static int at91sam9_init(struct nand_device *nand)
|
|||||||
{
|
{
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "init")) {
|
if (!at91sam9_halted(target, "init"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -144,9 +144,8 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
|||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "command")) {
|
if (!at91sam9_halted(target, "command"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
at91sam9_enable(nand);
|
at91sam9_enable(nand);
|
||||||
|
|
||||||
@@ -161,9 +160,8 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
|||||||
*/
|
*/
|
||||||
static int at91sam9_reset(struct nand_device *nand)
|
static int at91sam9_reset(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
if (!at91sam9_halted(nand->target, "reset")) {
|
if (!at91sam9_halted(nand->target, "reset"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return at91sam9_disable(nand);
|
return at91sam9_disable(nand);
|
||||||
}
|
}
|
||||||
@@ -180,9 +178,8 @@ static int at91sam9_address(struct nand_device *nand, uint8_t address)
|
|||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(nand->target, "address")) {
|
if (!at91sam9_halted(nand->target, "address"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return target_write_u8(target, info->addr, address);
|
return target_write_u8(target, info->addr, address);
|
||||||
}
|
}
|
||||||
@@ -200,9 +197,8 @@ static int at91sam9_read_data(struct nand_device *nand, void *data)
|
|||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(nand->target, "read data")) {
|
if (!at91sam9_halted(nand->target, "read data"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return target_read_u8(target, info->data, data);
|
return target_read_u8(target, info->data, data);
|
||||||
}
|
}
|
||||||
@@ -220,9 +216,8 @@ static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "write data")) {
|
if (!at91sam9_halted(target, "write data"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return target_write_u8(target, info->data, data);
|
return target_write_u8(target, info->data, data);
|
||||||
}
|
}
|
||||||
@@ -240,16 +235,14 @@ static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
|
|||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "nand ready")) {
|
if (!at91sam9_halted(target, "nand ready"))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status);
|
target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status);
|
||||||
|
|
||||||
if (status & (1 << info->busy.num)) {
|
if (status & (1 << info->busy.num))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
} while (timeout-- > 0);
|
} while (timeout-- > 0);
|
||||||
@@ -272,9 +265,8 @@ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int
|
|||||||
struct arm_nand_data *io = &info->io;
|
struct arm_nand_data *io = &info->io;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!at91sam9_halted(nand->target, "read block")) {
|
if (!at91sam9_halted(nand->target, "read block"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
io->chunk_size = nand->page_size;
|
io->chunk_size = nand->page_size;
|
||||||
status = arm_nandread(io, data, size);
|
status = arm_nandread(io, data, size);
|
||||||
@@ -297,9 +289,8 @@ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, in
|
|||||||
struct arm_nand_data *io = &info->io;
|
struct arm_nand_data *io = &info->io;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!at91sam9_halted(nand->target, "write block")) {
|
if (!at91sam9_halted(nand->target, "write block"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
io->chunk_size = nand->page_size;
|
io->chunk_size = nand->page_size;
|
||||||
status = arm_nandwrite(io, data, size);
|
status = arm_nandwrite(io, data, size);
|
||||||
@@ -321,7 +312,7 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset ECC parity registers
|
/* reset ECC parity registers */
|
||||||
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
|
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,16 +329,16 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
|
|||||||
static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size)
|
static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size)
|
||||||
{
|
{
|
||||||
if (!oob) {
|
if (!oob) {
|
||||||
// user doesn't want OOB, allocate it
|
/* user doesn't want OOB, allocate it */
|
||||||
if (nand->page_size == 512) {
|
if (nand->page_size == 512)
|
||||||
*size = 16;
|
*size = 16;
|
||||||
} else if (nand->page_size == 2048) {
|
else if (nand->page_size == 2048)
|
||||||
*size = 64;
|
*size = 64;
|
||||||
}
|
|
||||||
|
|
||||||
oob = malloc(*size);
|
oob = malloc(*size);
|
||||||
if (!oob) {
|
if (!oob) {
|
||||||
LOG_ERROR("Unable to allocate space for OOB");
|
LOG_ERROR("Unable to allocate space for OOB");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(oob, 0xFF, *size);
|
memset(oob, 0xFF, *size);
|
||||||
@@ -379,21 +370,18 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
retval = at91sam9_ecc_init(target, info);
|
retval = at91sam9_ecc_init(target, info);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
|
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
retval = nand_read_data_page(nand, data, data_size);
|
retval = nand_read_data_page(nand, data, data_size);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
||||||
retval = nand_read_data_page(nand, oob_data, oob_size);
|
retval = nand_read_data_page(nand, oob_data, oob_size);
|
||||||
@@ -401,10 +389,10 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
|
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
|
||||||
if (status & 1) {
|
if (status & 1) {
|
||||||
LOG_ERROR("Error detected!");
|
LOG_ERROR("Error detected!");
|
||||||
if (status & 4) {
|
if (status & 4)
|
||||||
LOG_ERROR("Multiple errors encountered; unrecoverable!");
|
LOG_ERROR("Multiple errors encountered; unrecoverable!");
|
||||||
} else {
|
else {
|
||||||
// attempt recovery
|
/* attempt recovery */
|
||||||
uint32_t parity;
|
uint32_t parity;
|
||||||
|
|
||||||
target_read_u32(target,
|
target_read_u32(target,
|
||||||
@@ -421,13 +409,13 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status & 2) {
|
if (status & 2) {
|
||||||
// we could write back correct ECC data
|
/* we could write back correct ECC data */
|
||||||
LOG_ERROR("Error in ECC bytes detected");
|
LOG_ERROR("Error in ECC bytes detected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!oob) {
|
if (!oob) {
|
||||||
// if it wasn't asked for, free it
|
/* if it wasn't asked for, free it */
|
||||||
free(oob_data);
|
free(oob_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,14 +445,12 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
uint32_t parity, nparity;
|
uint32_t parity, nparity;
|
||||||
|
|
||||||
retval = at91sam9_ecc_init(target, info);
|
retval = at91sam9_ecc_init(target, info);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
retval = nand_write_data_page(nand, data, data_size);
|
retval = nand_write_data_page(nand, data, data_size);
|
||||||
@@ -477,7 +463,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
||||||
|
|
||||||
if (!oob) {
|
if (!oob) {
|
||||||
// no OOB given, so read in the ECC parity from the ECC controller
|
/* no OOB given, so read in the ECC parity from the ECC controller */
|
||||||
target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity);
|
target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity);
|
||||||
target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity);
|
target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity);
|
||||||
|
|
||||||
@@ -489,9 +475,8 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
retval = nand_write_data_page(nand, oob_data, oob_size);
|
retval = nand_write_data_page(nand, oob_data, oob_size);
|
||||||
|
|
||||||
if (!oob) {
|
if (!oob)
|
||||||
free(oob_data);
|
free(oob_data);
|
||||||
}
|
|
||||||
|
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval) {
|
||||||
LOG_ERROR("Unable to write OOB data to NAND");
|
LOG_ERROR("Unable to write OOB data to NAND");
|
||||||
@@ -593,9 +578,8 @@ COMMAND_HANDLER(handle_at91sam9_ale_command)
|
|||||||
struct at91sam9_nand *info = NULL;
|
struct at91sam9_nand *info = NULL;
|
||||||
unsigned num, address_line;
|
unsigned num, address_line;
|
||||||
|
|
||||||
if (CMD_ARGC != 2) {
|
if (CMD_ARGC != 2)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||||
nand = get_nand_device_by_num(num);
|
nand = get_nand_device_by_num(num);
|
||||||
@@ -622,9 +606,8 @@ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command)
|
|||||||
struct at91sam9_nand *info = NULL;
|
struct at91sam9_nand *info = NULL;
|
||||||
unsigned num, base_pioc, pin_num;
|
unsigned num, base_pioc, pin_num;
|
||||||
|
|
||||||
if (CMD_ARGC != 3) {
|
if (CMD_ARGC != 3)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||||
nand = get_nand_device_by_num(num);
|
nand = get_nand_device_by_num(num);
|
||||||
@@ -654,9 +637,8 @@ COMMAND_HANDLER(handle_at91sam9_ce_command)
|
|||||||
struct at91sam9_nand *info = NULL;
|
struct at91sam9_nand *info = NULL;
|
||||||
unsigned num, base_pioc, pin_num;
|
unsigned num, base_pioc, pin_num;
|
||||||
|
|
||||||
if (CMD_ARGC != 3) {
|
if (CMD_ARGC != 3)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||||
nand = get_nand_device_by_num(num);
|
nand = get_nand_device_by_num(num);
|
||||||
@@ -715,6 +697,7 @@ static const struct command_registration at91sam9_command_handler[] = {
|
|||||||
.name = "at91sam9",
|
.name = "at91sam9",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "AT91SAM9 NAND flash controller commands",
|
.help = "AT91SAM9 NAND flash controller commands",
|
||||||
|
.usage = "",
|
||||||
.chain = at91sam9_sub_command_handlers,
|
.chain = at91sam9_sub_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -27,13 +28,14 @@
|
|||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
|
|
||||||
/* configured NAND devices and NAND Flash command handler */
|
/* configured NAND devices and NAND Flash command handler */
|
||||||
struct nand_device *nand_devices = NULL;
|
struct nand_device *nand_devices;
|
||||||
|
|
||||||
void nand_device_add(struct nand_device *c)
|
void nand_device_add(struct nand_device *c)
|
||||||
{
|
{
|
||||||
if (nand_devices) {
|
if (nand_devices) {
|
||||||
struct nand_device *p = nand_devices;
|
struct nand_device *p = nand_devices;
|
||||||
while (p && p->next) p = p->next;
|
while (p && p->next)
|
||||||
|
p = p->next;
|
||||||
p->next = c;
|
p->next = c;
|
||||||
} else
|
} else
|
||||||
nand_devices = c;
|
nand_devices = c;
|
||||||
@@ -50,11 +52,12 @@ void nand_device_add(struct nand_device *c)
|
|||||||
* 256 256 Byte page size
|
* 256 256 Byte page size
|
||||||
* 512 512 Byte page size
|
* 512 512 Byte page size
|
||||||
*/
|
*/
|
||||||
static struct nand_info nand_flash_ids[] =
|
static struct nand_info nand_flash_ids[] = {
|
||||||
{
|
|
||||||
/* Vendor Specific Entries */
|
/* Vendor Specific Entries */
|
||||||
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"},
|
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS,
|
||||||
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"},
|
"K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"},
|
||||||
|
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS,
|
||||||
|
"K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"},
|
||||||
|
|
||||||
/* start "museum" IDs */
|
/* start "museum" IDs */
|
||||||
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
|
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
|
||||||
@@ -136,8 +139,7 @@ static struct nand_info nand_flash_ids[] =
|
|||||||
|
|
||||||
/* Manufacturer ID list
|
/* Manufacturer ID list
|
||||||
*/
|
*/
|
||||||
static struct nand_manufacturer nand_manuf_ids[] =
|
static struct nand_manufacturer nand_manuf_ids[] = {
|
||||||
{
|
|
||||||
{0x0, "unknown"},
|
{0x0, "unknown"},
|
||||||
{NAND_MFR_TOSHIBA, "Toshiba"},
|
{NAND_MFR_TOSHIBA, "Toshiba"},
|
||||||
{NAND_MFR_SAMSUNG, "Samsung"},
|
{NAND_MFR_SAMSUNG, "Samsung"},
|
||||||
@@ -162,7 +164,8 @@ static struct nand_ecclayout nand_oob_8 = {
|
|||||||
{.offset = 3,
|
{.offset = 3,
|
||||||
.length = 2},
|
.length = 2},
|
||||||
{.offset = 6,
|
{.offset = 6,
|
||||||
.length = 2}}
|
.length = 2}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -179,8 +182,7 @@ static struct nand_device *get_nand_device_by_name(const char *name)
|
|||||||
unsigned found = 0;
|
unsigned found = 0;
|
||||||
|
|
||||||
struct nand_device *nand;
|
struct nand_device *nand;
|
||||||
for (nand = nand_devices; NULL != nand; nand = nand->next)
|
for (nand = nand_devices; NULL != nand; nand = nand->next) {
|
||||||
{
|
|
||||||
if (strcmp(nand->name, name) == 0)
|
if (strcmp(nand->name, name) == 0)
|
||||||
return nand;
|
return nand;
|
||||||
if (!flash_driver_name_matches(nand->controller->name, name))
|
if (!flash_driver_name_matches(nand->controller->name, name))
|
||||||
@@ -197,13 +199,10 @@ struct nand_device *get_nand_device_by_num(int num)
|
|||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (p = nand_devices; p; p = p->next)
|
for (p = nand_devices; p; p = p->next) {
|
||||||
{
|
|
||||||
if (i++ == num)
|
if (i++ == num)
|
||||||
{
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -221,7 +220,7 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
|||||||
*nand = get_nand_device_by_num(num);
|
*nand = get_nand_device_by_num(num);
|
||||||
if (!*nand) {
|
if (!*nand) {
|
||||||
command_print(CMD_CTX, "NAND flash device '%s' not found", str);
|
command_print(CMD_CTX, "NAND flash device '%s' not found", str);
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -241,23 +240,18 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
|
|||||||
last = nand->num_blocks - 1;
|
last = nand->num_blocks - 1;
|
||||||
|
|
||||||
page = first * pages_per_block;
|
page = first * pages_per_block;
|
||||||
for (i = first; i <= last; i++)
|
for (i = first; i <= last; i++) {
|
||||||
{
|
|
||||||
ret = nand_read_page(nand, page, NULL, 0, oob, 6);
|
ret = nand_read_page(nand, page, NULL, 0, oob, 6);
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|
||||||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
||||||
((nand->page_size == 2048) && (oob[0] != 0xff))))
|
((nand->page_size == 2048) && (oob[0] != 0xff)))) {
|
||||||
{
|
|
||||||
LOG_WARNING("bad block: %i", i);
|
LOG_WARNING("bad block: %i", i);
|
||||||
nand->blocks[i].is_bad = 1;
|
nand->blocks[i].is_bad = 1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
nand->blocks[i].is_bad = 0;
|
nand->blocks[i].is_bad = 0;
|
||||||
}
|
|
||||||
|
|
||||||
page += pages_per_block;
|
page += pages_per_block;
|
||||||
}
|
}
|
||||||
@@ -276,16 +270,12 @@ int nand_read_status(struct nand_device *nand, uint8_t *status)
|
|||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
|
|
||||||
/* read status */
|
/* read status */
|
||||||
if (nand->device->options & NAND_BUSWIDTH_16)
|
if (nand->device->options & NAND_BUSWIDTH_16) {
|
||||||
{
|
|
||||||
uint16_t data;
|
uint16_t data;
|
||||||
nand->controller->read_data(nand, &data);
|
nand->controller->read_data(nand, &data);
|
||||||
*status = data & 0xff;
|
*status = data & 0xff;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
nand->controller->read_data(nand, status);
|
nand->controller->read_data(nand, status);
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -300,9 +290,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout)
|
|||||||
uint16_t data;
|
uint16_t data;
|
||||||
nand->controller->read_data(nand, &data);
|
nand->controller->read_data(nand, &data);
|
||||||
status = data & 0xff;
|
status = data & 0xff;
|
||||||
} else {
|
} else
|
||||||
nand->controller->read_data(nand, &status);
|
nand->controller->read_data(nand, &status);
|
||||||
}
|
|
||||||
if (status & NAND_STATUS_READY)
|
if (status & NAND_STATUS_READY)
|
||||||
break;
|
break;
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
@@ -329,15 +318,15 @@ int nand_probe(struct nand_device *nand)
|
|||||||
nand->erase_size = 0;
|
nand->erase_size = 0;
|
||||||
|
|
||||||
/* initialize controller (device parameters are zero, use controller default) */
|
/* initialize controller (device parameters are zero, use controller default) */
|
||||||
if ((retval = nand->controller->init(nand) != ERROR_OK))
|
retval = nand->controller->init(nand);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
switch (retval)
|
switch (retval) {
|
||||||
{
|
|
||||||
case ERROR_NAND_OPERATION_FAILED:
|
case ERROR_NAND_OPERATION_FAILED:
|
||||||
LOG_DEBUG("controller initialization failed");
|
LOG_DEBUG("controller initialization failed");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
|
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
|
||||||
LOG_ERROR("BUG: controller reported that it doesn't support default parameters");
|
LOG_ERROR(
|
||||||
|
"BUG: controller reported that it doesn't support default parameters");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("BUG: unknown controller initialization failure");
|
LOG_ERROR("BUG: unknown controller initialization failure");
|
||||||
@@ -351,13 +340,10 @@ int nand_probe(struct nand_device *nand)
|
|||||||
nand->controller->command(nand, NAND_CMD_READID);
|
nand->controller->command(nand, NAND_CMD_READID);
|
||||||
nand->controller->address(nand, 0x0);
|
nand->controller->address(nand, 0x0);
|
||||||
|
|
||||||
if (nand->bus_width == 8)
|
if (nand->bus_width == 8) {
|
||||||
{
|
|
||||||
nand->controller->read_data(nand, &manufacturer_id);
|
nand->controller->read_data(nand, &manufacturer_id);
|
||||||
nand->controller->read_data(nand, &device_id);
|
nand->controller->read_data(nand, &device_id);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
uint16_t data_buf;
|
uint16_t data_buf;
|
||||||
nand->controller->read_data(nand, &data_buf);
|
nand->controller->read_data(nand, &data_buf);
|
||||||
manufacturer_id = data_buf & 0xff;
|
manufacturer_id = data_buf & 0xff;
|
||||||
@@ -365,36 +351,32 @@ int nand_probe(struct nand_device *nand)
|
|||||||
device_id = data_buf & 0xff;
|
device_id = data_buf & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; nand_flash_ids[i].name; i++)
|
for (i = 0; nand_flash_ids[i].name; i++) {
|
||||||
{
|
|
||||||
if (nand_flash_ids[i].id == device_id &&
|
if (nand_flash_ids[i].id == device_id &&
|
||||||
(nand_flash_ids[i].mfr_id == manufacturer_id ||
|
(nand_flash_ids[i].mfr_id == manufacturer_id ||
|
||||||
nand_flash_ids[i].mfr_id == 0 ))
|
nand_flash_ids[i].mfr_id == 0)) {
|
||||||
{
|
|
||||||
nand->device = &nand_flash_ids[i];
|
nand->device = &nand_flash_ids[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; nand_manuf_ids[i].name; i++)
|
for (i = 0; nand_manuf_ids[i].name; i++) {
|
||||||
{
|
if (nand_manuf_ids[i].id == manufacturer_id) {
|
||||||
if (nand_manuf_ids[i].id == manufacturer_id)
|
|
||||||
{
|
|
||||||
nand->manufacturer = &nand_manuf_ids[i];
|
nand->manufacturer = &nand_manuf_ids[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nand->manufacturer)
|
if (!nand->manufacturer) {
|
||||||
{
|
|
||||||
nand->manufacturer = &nand_manuf_ids[0];
|
nand->manufacturer = &nand_manuf_ids[0];
|
||||||
nand->manufacturer->id = manufacturer_id;
|
nand->manufacturer->id = manufacturer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nand->device)
|
if (!nand->device) {
|
||||||
{
|
LOG_ERROR(
|
||||||
LOG_ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
|
"unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
|
||||||
manufacturer_id, device_id);
|
manufacturer_id,
|
||||||
|
device_id);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,16 +392,12 @@ int nand_probe(struct nand_device *nand)
|
|||||||
|
|
||||||
/* Do we need extended device probe information? */
|
/* Do we need extended device probe information? */
|
||||||
if (nand->device->page_size == 0 ||
|
if (nand->device->page_size == 0 ||
|
||||||
nand->device->erase_size == 0)
|
nand->device->erase_size == 0) {
|
||||||
{
|
if (nand->bus_width == 8) {
|
||||||
if (nand->bus_width == 8)
|
|
||||||
{
|
|
||||||
nand->controller->read_data(nand, id_buff + 3);
|
nand->controller->read_data(nand, id_buff + 3);
|
||||||
nand->controller->read_data(nand, id_buff + 4);
|
nand->controller->read_data(nand, id_buff + 4);
|
||||||
nand->controller->read_data(nand, id_buff + 5);
|
nand->controller->read_data(nand, id_buff + 5);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
uint16_t data_buf;
|
uint16_t data_buf;
|
||||||
|
|
||||||
nand->controller->read_data(nand, &data_buf);
|
nand->controller->read_data(nand, &data_buf);
|
||||||
@@ -435,50 +413,38 @@ int nand_probe(struct nand_device *nand)
|
|||||||
|
|
||||||
/* page size */
|
/* page size */
|
||||||
if (nand->device->page_size == 0)
|
if (nand->device->page_size == 0)
|
||||||
{
|
|
||||||
nand->page_size = 1 << (10 + (id_buff[4] & 3));
|
nand->page_size = 1 << (10 + (id_buff[4] & 3));
|
||||||
}
|
else if (nand->device->page_size == 256) {
|
||||||
else if (nand->device->page_size == 256)
|
|
||||||
{
|
|
||||||
LOG_ERROR("NAND flashes with 256 byte pagesize are not supported");
|
LOG_ERROR("NAND flashes with 256 byte pagesize are not supported");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
nand->page_size = nand->device->page_size;
|
nand->page_size = nand->device->page_size;
|
||||||
}
|
|
||||||
|
|
||||||
/* number of address cycles */
|
/* number of address cycles */
|
||||||
if (nand->page_size <= 512)
|
if (nand->page_size <= 512) {
|
||||||
{
|
|
||||||
/* small page devices */
|
/* small page devices */
|
||||||
if (nand->device->chip_size <= 32)
|
if (nand->device->chip_size <= 32)
|
||||||
nand->address_cycles = 3;
|
nand->address_cycles = 3;
|
||||||
else if (nand->device->chip_size <= 8*1024)
|
else if (nand->device->chip_size <= 8*1024)
|
||||||
nand->address_cycles = 4;
|
nand->address_cycles = 4;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
|
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
|
||||||
nand->address_cycles = 5;
|
nand->address_cycles = 5;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* large page devices */
|
/* large page devices */
|
||||||
if (nand->device->chip_size <= 128)
|
if (nand->device->chip_size <= 128)
|
||||||
nand->address_cycles = 4;
|
nand->address_cycles = 4;
|
||||||
else if (nand->device->chip_size <= 32*1024)
|
else if (nand->device->chip_size <= 32*1024)
|
||||||
nand->address_cycles = 5;
|
nand->address_cycles = 5;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
|
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
|
||||||
nand->address_cycles = 6;
|
nand->address_cycles = 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* erase size */
|
/* erase size */
|
||||||
if (nand->device->erase_size == 0)
|
if (nand->device->erase_size == 0) {
|
||||||
{
|
|
||||||
switch ((id_buff[4] >> 4) & 3) {
|
switch ((id_buff[4] >> 4) & 3) {
|
||||||
case 0:
|
case 0:
|
||||||
nand->erase_size = 64 << 10;
|
nand->erase_size = 64 << 10;
|
||||||
@@ -493,23 +459,22 @@ int nand_probe(struct nand_device *nand)
|
|||||||
nand->erase_size = 512 << 10;
|
nand->erase_size = 512 << 10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
nand->erase_size = nand->device->erase_size;
|
nand->erase_size = nand->device->erase_size;
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize controller, but leave parameters at the controllers default */
|
/* initialize controller, but leave parameters at the controllers default */
|
||||||
if ((retval = nand->controller->init(nand) != ERROR_OK))
|
retval = nand->controller->init(nand);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
switch (retval)
|
switch (retval) {
|
||||||
{
|
|
||||||
case ERROR_NAND_OPERATION_FAILED:
|
case ERROR_NAND_OPERATION_FAILED:
|
||||||
LOG_DEBUG("controller initialization failed");
|
LOG_DEBUG("controller initialization failed");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
|
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
|
||||||
LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
|
LOG_ERROR(
|
||||||
nand->bus_width, nand->address_cycles, nand->page_size);
|
"controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
|
||||||
|
nand->bus_width,
|
||||||
|
nand->address_cycles,
|
||||||
|
nand->page_size);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("BUG: unknown controller initialization failure");
|
LOG_ERROR("BUG: unknown controller initialization failure");
|
||||||
@@ -520,8 +485,7 @@ int nand_probe(struct nand_device *nand)
|
|||||||
nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024);
|
nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024);
|
||||||
nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks);
|
nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks);
|
||||||
|
|
||||||
for (i = 0; i < nand->num_blocks; i++)
|
for (i = 0; i < nand->num_blocks; i++) {
|
||||||
{
|
|
||||||
nand->blocks[i].size = nand->erase_size;
|
nand->blocks[i].size = nand->erase_size;
|
||||||
nand->blocks[i].offset = i * nand->erase_size;
|
nand->blocks[i].offset = i * nand->erase_size;
|
||||||
nand->blocks[i].is_erased = -1;
|
nand->blocks[i].is_erased = -1;
|
||||||
@@ -542,28 +506,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
|||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
|
|
||||||
if ((first_block < 0) || (last_block >= nand->num_blocks))
|
if ((first_block < 0) || (last_block >= nand->num_blocks))
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
/* make sure we know if a block is bad before erasing it */
|
/* make sure we know if a block is bad before erasing it */
|
||||||
for (i = first_block; i <= last_block; i++)
|
for (i = first_block; i <= last_block; i++) {
|
||||||
{
|
if (nand->blocks[i].is_bad == -1) {
|
||||||
if (nand->blocks[i].is_bad == -1)
|
|
||||||
{
|
|
||||||
nand_build_bbt(nand, i, last_block);
|
nand_build_bbt(nand, i, last_block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = first_block; i <= last_block; i++)
|
for (i = first_block; i <= last_block; i++) {
|
||||||
{
|
|
||||||
/* Send erase setup command */
|
/* Send erase setup command */
|
||||||
nand->controller->command(nand, NAND_CMD_ERASE1);
|
nand->controller->command(nand, NAND_CMD_ERASE1);
|
||||||
|
|
||||||
page = i * (nand->erase_size / nand->page_size);
|
page = i * (nand->erase_size / nand->page_size);
|
||||||
|
|
||||||
/* Send page address */
|
/* Send page address */
|
||||||
if (nand->page_size <= 512)
|
if (nand->page_size <= 512) {
|
||||||
{
|
|
||||||
/* row */
|
/* row */
|
||||||
nand->controller->address(nand, page & 0xff);
|
nand->controller->address(nand, page & 0xff);
|
||||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||||
@@ -575,9 +535,7 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
|||||||
/* 4th cycle only on devices with more than 8 GiB */
|
/* 4th cycle only on devices with more than 8 GiB */
|
||||||
if (nand->address_cycles >= 5)
|
if (nand->address_cycles >= 5)
|
||||||
nand->controller->address(nand, (page >> 24) & 0xff);
|
nand->controller->address(nand, (page >> 24) & 0xff);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* row */
|
/* row */
|
||||||
nand->controller->address(nand, page & 0xff);
|
nand->controller->address(nand, page & 0xff);
|
||||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||||
@@ -598,14 +556,13 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
|||||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((retval = nand_read_status(nand, &status)) != ERROR_OK)
|
retval = nand_read_status(nand, &status);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("couldn't read status");
|
LOG_ERROR("couldn't read status");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & 0x1)
|
if (status & 0x1) {
|
||||||
{
|
|
||||||
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
|
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
|
||||||
(nand->blocks[i].is_bad == 1)
|
(nand->blocks[i].is_bad == 1)
|
||||||
? "bad " : "",
|
? "bad " : "",
|
||||||
@@ -620,23 +577,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size)
|
static int nand_read_plain(struct nand_device *nand,
|
||||||
|
uint32_t address,
|
||||||
|
uint8_t *data,
|
||||||
|
uint32_t data_size)
|
||||||
{
|
{
|
||||||
uint8_t *page;
|
uint8_t *page;
|
||||||
|
|
||||||
if (!nand->device)
|
if (!nand->device)
|
||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
|
|
||||||
if (address % nand->page_size)
|
if (address % nand->page_size) {
|
||||||
{
|
|
||||||
LOG_ERROR("reads need to be page aligned");
|
LOG_ERROR("reads need to be page aligned");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = malloc(nand->page_size);
|
page = malloc(nand->page_size);
|
||||||
|
|
||||||
while (data_size > 0)
|
while (data_size > 0) {
|
||||||
{
|
|
||||||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
||||||
uint32_t page_address;
|
uint32_t page_address;
|
||||||
|
|
||||||
@@ -657,23 +615,24 @@ static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size)
|
static int nand_write_plain(struct nand_device *nand,
|
||||||
|
uint32_t address,
|
||||||
|
uint8_t *data,
|
||||||
|
uint32_t data_size)
|
||||||
{
|
{
|
||||||
uint8_t *page;
|
uint8_t *page;
|
||||||
|
|
||||||
if (!nand->device)
|
if (!nand->device)
|
||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
|
|
||||||
if (address % nand->page_size)
|
if (address % nand->page_size) {
|
||||||
{
|
|
||||||
LOG_ERROR("writes need to be page aligned");
|
LOG_ERROR("writes need to be page aligned");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = malloc(nand->page_size);
|
page = malloc(nand->page_size);
|
||||||
|
|
||||||
while (data_size > 0)
|
while (data_size > 0) {
|
||||||
{
|
|
||||||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
||||||
uint32_t page_address;
|
uint32_t page_address;
|
||||||
|
|
||||||
@@ -917,4 +876,3 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
return nand_write_finish(nand);
|
return nand_write_finish(nand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NAND_CORE_H
|
#ifndef FLASH_NAND_CORE_H
|
||||||
#define FLASH_NAND_CORE_H
|
#define FLASH_NAND_CORE_H
|
||||||
|
|
||||||
@@ -30,8 +31,7 @@
|
|||||||
/**
|
/**
|
||||||
* Representation of a single NAND block in a NAND device.
|
* Representation of a single NAND block in a NAND device.
|
||||||
*/
|
*/
|
||||||
struct nand_block
|
struct nand_block {
|
||||||
{
|
|
||||||
/** Offset to the block. */
|
/** Offset to the block. */
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
@@ -57,8 +57,7 @@ struct nand_ecclayout {
|
|||||||
struct nand_oobfree oobfree[2];
|
struct nand_oobfree oobfree[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nand_device
|
struct nand_device {
|
||||||
{
|
|
||||||
const char *name;
|
const char *name;
|
||||||
struct target *target;
|
struct target *target;
|
||||||
struct nand_flash_controller *controller;
|
struct nand_flash_controller *controller;
|
||||||
@@ -77,8 +76,7 @@ struct nand_device
|
|||||||
|
|
||||||
/* NAND Flash Manufacturer ID Codes
|
/* NAND Flash Manufacturer ID Codes
|
||||||
*/
|
*/
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
NAND_MFR_TOSHIBA = 0x98,
|
NAND_MFR_TOSHIBA = 0x98,
|
||||||
NAND_MFR_SAMSUNG = 0xec,
|
NAND_MFR_SAMSUNG = 0xec,
|
||||||
NAND_MFR_FUJITSU = 0x04,
|
NAND_MFR_FUJITSU = 0x04,
|
||||||
@@ -89,14 +87,12 @@ enum
|
|||||||
NAND_MFR_MICRON = 0x2c,
|
NAND_MFR_MICRON = 0x2c,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nand_manufacturer
|
struct nand_manufacturer {
|
||||||
{
|
|
||||||
int id;
|
int id;
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nand_info
|
struct nand_info {
|
||||||
{
|
|
||||||
int mfr_id;
|
int mfr_id;
|
||||||
int id;
|
int id;
|
||||||
int page_size;
|
int page_size;
|
||||||
@@ -152,8 +148,7 @@ enum {
|
|||||||
LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16),
|
LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
/* Standard NAND flash commands */
|
/* Standard NAND flash commands */
|
||||||
NAND_CMD_READ0 = 0x0,
|
NAND_CMD_READ0 = 0x0,
|
||||||
NAND_CMD_READ1 = 0x1,
|
NAND_CMD_READ1 = 0x1,
|
||||||
@@ -176,8 +171,7 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Status bits */
|
/* Status bits */
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
NAND_STATUS_FAIL = 0x01,
|
NAND_STATUS_FAIL = 0x01,
|
||||||
NAND_STATUS_FAIL_N1 = 0x02,
|
NAND_STATUS_FAIL_N1 = 0x02,
|
||||||
NAND_STATUS_TRUE_READY = 0x20,
|
NAND_STATUS_TRUE_READY = 0x20,
|
||||||
@@ -186,10 +180,10 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* OOB (spare) data formats */
|
/* OOB (spare) data formats */
|
||||||
enum oob_formats
|
enum oob_formats {
|
||||||
{
|
|
||||||
NAND_OOB_NONE = 0x0, /* no OOB data at all */
|
NAND_OOB_NONE = 0x0, /* no OOB data at all */
|
||||||
NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for 2048b page sizes) */
|
NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for
|
||||||
|
*2048b page sizes) */
|
||||||
NAND_OOB_ONLY = 0x2, /* only OOB data */
|
NAND_OOB_ONLY = 0x2, /* only OOB data */
|
||||||
NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */
|
NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */
|
||||||
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
|
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
|
||||||
@@ -224,7 +218,7 @@ int nand_calculate_ecc_kw(struct nand_device *nand,
|
|||||||
|
|
||||||
int nand_register_commands(struct command_context *cmd_ctx);
|
int nand_register_commands(struct command_context *cmd_ctx);
|
||||||
|
|
||||||
/// helper for parsing a nand device command argument string
|
/** helper for parsing a nand device command argument string */
|
||||||
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||||
struct nand_device **nand);
|
struct nand_device **nand);
|
||||||
|
|
||||||
@@ -237,5 +231,4 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
|||||||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
||||||
#define ERROR_NAND_NO_BUFFER (-1106)
|
#define ERROR_NAND_NO_BUFFER (-1106)
|
||||||
|
|
||||||
#endif // FLASH_NAND_CORE_H
|
#endif /* FLASH_NAND_CORE_H */
|
||||||
|
|
||||||
|
|||||||
@@ -688,12 +688,8 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
|||||||
* - aemif address
|
* - aemif address
|
||||||
* Plus someday, optionally, ALE and CLE masks.
|
* Plus someday, optionally, ALE and CLE masks.
|
||||||
*/
|
*/
|
||||||
if (CMD_ARGC < 5) {
|
if (CMD_ARGC < 5)
|
||||||
LOG_ERROR("parameters: %s target "
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
"chip_addr hwecc_mode aemif_addr",
|
|
||||||
CMD_ARGV[0]);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||||
if (chip == 0) {
|
if (chip == 0) {
|
||||||
@@ -783,6 +779,7 @@ fail:
|
|||||||
|
|
||||||
struct nand_flash_controller davinci_nand_controller = {
|
struct nand_flash_controller davinci_nand_controller = {
|
||||||
.name = "davinci",
|
.name = "davinci",
|
||||||
|
.usage = "chip_addr hwecc_mode aemif_addr",
|
||||||
.nand_device_command = davinci_nand_device_command,
|
.nand_device_command = davinci_nand_device_command,
|
||||||
.init = davinci_init,
|
.init = davinci_init,
|
||||||
.reset = davinci_reset,
|
.reset = davinci_reset,
|
||||||
|
|||||||
@@ -38,15 +38,14 @@ extern struct nand_flash_controller s3c2412_nand_controller;
|
|||||||
extern struct nand_flash_controller s3c2440_nand_controller;
|
extern struct nand_flash_controller s3c2440_nand_controller;
|
||||||
extern struct nand_flash_controller s3c2443_nand_controller;
|
extern struct nand_flash_controller s3c2443_nand_controller;
|
||||||
extern struct nand_flash_controller s3c6400_nand_controller;
|
extern struct nand_flash_controller s3c6400_nand_controller;
|
||||||
extern struct nand_flash_controller imx27_nand_flash_controller;
|
extern struct nand_flash_controller mxc_nand_flash_controller;
|
||||||
extern struct nand_flash_controller imx31_nand_flash_controller;
|
extern struct nand_flash_controller imx31_nand_flash_controller;
|
||||||
extern struct nand_flash_controller at91sam9_nand_controller;
|
extern struct nand_flash_controller at91sam9_nand_controller;
|
||||||
extern struct nand_flash_controller nuc910_nand_controller;
|
extern struct nand_flash_controller nuc910_nand_controller;
|
||||||
|
|
||||||
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
|
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
|
||||||
|
|
||||||
static struct nand_flash_controller *nand_flash_controllers[] =
|
static struct nand_flash_controller *nand_flash_controllers[] = {
|
||||||
{
|
|
||||||
&nonce_nand_controller,
|
&nonce_nand_controller,
|
||||||
&davinci_nand_controller,
|
&davinci_nand_controller,
|
||||||
&lpc3180_nand_controller,
|
&lpc3180_nand_controller,
|
||||||
@@ -57,7 +56,7 @@ static struct nand_flash_controller *nand_flash_controllers[] =
|
|||||||
&s3c2440_nand_controller,
|
&s3c2440_nand_controller,
|
||||||
&s3c2443_nand_controller,
|
&s3c2443_nand_controller,
|
||||||
&s3c6400_nand_controller,
|
&s3c6400_nand_controller,
|
||||||
&imx27_nand_flash_controller,
|
&mxc_nand_flash_controller,
|
||||||
&imx31_nand_flash_controller,
|
&imx31_nand_flash_controller,
|
||||||
&at91sam9_nand_controller,
|
&at91sam9_nand_controller,
|
||||||
&nuc910_nand_controller,
|
&nuc910_nand_controller,
|
||||||
@@ -67,8 +66,7 @@ static struct nand_flash_controller *nand_flash_controllers[] =
|
|||||||
|
|
||||||
struct nand_flash_controller *nand_driver_find_by_name(const char *name)
|
struct nand_flash_controller *nand_driver_find_by_name(const char *name)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; nand_flash_controllers[i]; i++)
|
for (unsigned i = 0; nand_flash_controllers[i]; i++) {
|
||||||
{
|
|
||||||
struct nand_flash_controller *controller = nand_flash_controllers[i];
|
struct nand_flash_controller *controller = nand_flash_controllers[i];
|
||||||
if (strcmp(name, controller->name) == 0)
|
if (strcmp(name, controller->name) == 0)
|
||||||
return controller;
|
return controller;
|
||||||
@@ -77,13 +75,10 @@ struct nand_flash_controller *nand_driver_find_by_name(const char *name)
|
|||||||
}
|
}
|
||||||
int nand_driver_walk(nand_driver_walker_t f, void *x)
|
int nand_driver_walk(nand_driver_walker_t f, void *x)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; nand_flash_controllers[i]; i++)
|
for (unsigned i = 0; nand_flash_controllers[i]; i++) {
|
||||||
{
|
|
||||||
int retval = (*f)(nand_flash_controllers[i], x);
|
int retval = (*f)(nand_flash_controllers[i], x);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NAND_DRIVER_H
|
#ifndef FLASH_NAND_DRIVER_H
|
||||||
#define FLASH_NAND_DRIVER_H
|
#define FLASH_NAND_DRIVER_H
|
||||||
|
|
||||||
@@ -32,11 +33,13 @@ struct nand_device;
|
|||||||
* required for full functionality of the NAND driver, but better performance
|
* required for full functionality of the NAND driver, but better performance
|
||||||
* can be achieved by implementing each function.
|
* can be achieved by implementing each function.
|
||||||
*/
|
*/
|
||||||
struct nand_flash_controller
|
struct nand_flash_controller {
|
||||||
{
|
|
||||||
/** Driver name that is used to select it from configuration files. */
|
/** Driver name that is used to select it from configuration files. */
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
/** Usage of flash command registration. */
|
||||||
|
const char *usage;
|
||||||
|
|
||||||
const struct command_registration *commands;
|
const struct command_registration *commands;
|
||||||
|
|
||||||
/** NAND device command called when driver is instantiated during configuration. */
|
/** NAND device command called when driver is instantiated during configuration. */
|
||||||
@@ -67,10 +70,12 @@ struct nand_flash_controller
|
|||||||
int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size);
|
int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size);
|
||||||
|
|
||||||
/** Write a page to the NAND device. */
|
/** Write a page to the NAND device. */
|
||||||
int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data,
|
||||||
|
uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||||
|
|
||||||
/** Read a page from the NAND device. */
|
/** Read a page from the NAND device. */
|
||||||
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size,
|
||||||
|
uint8_t *oob, uint32_t oob_size);
|
||||||
|
|
||||||
/** Check if the NAND device is ready for more instructions with timeout. */
|
/** Check if the NAND device is ready for more instructions with timeout. */
|
||||||
int (*nand_ready)(struct nand_device *nand, int timeout);
|
int (*nand_ready)(struct nand_device *nand, int timeout);
|
||||||
@@ -85,7 +90,7 @@ struct nand_flash_controller
|
|||||||
*/
|
*/
|
||||||
struct nand_flash_controller *nand_driver_find_by_name(const char *name);
|
struct nand_flash_controller *nand_driver_find_by_name(const char *name);
|
||||||
|
|
||||||
/// Signature for callback functions passed to nand_driver_walk
|
/** Signature for callback functions passed to nand_driver_walk */
|
||||||
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *);
|
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *);
|
||||||
/**
|
/**
|
||||||
* Walk the list of drivers, encapsulating the data structure type.
|
* Walk the list of drivers, encapsulating the data structure type.
|
||||||
@@ -97,4 +102,4 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void*);
|
|||||||
*/
|
*/
|
||||||
int nand_driver_walk(nand_driver_walker_t f, void *x);
|
int nand_driver_walk(nand_driver_walker_t f, void *x);
|
||||||
|
|
||||||
#endif // FLASH_NAND_DRIVER_H
|
#endif /* FLASH_NAND_DRIVER_H */
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t
|
|||||||
{
|
{
|
||||||
unsigned int r7, r6, r5, r4, r3, r2, r1, r0;
|
unsigned int r7, r6, r5, r4, r3, r2, r1, r0;
|
||||||
int i;
|
int i;
|
||||||
static int tables_initialized = 0;
|
static int tables_initialized;
|
||||||
|
|
||||||
if (!tables_initialized) {
|
if (!tables_initialized) {
|
||||||
gf_build_log_exp_table();
|
gf_build_log_exp_table();
|
||||||
@@ -121,7 +121,6 @@ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t
|
|||||||
r6 = data[510];
|
r6 = data[510];
|
||||||
r7 = data[511];
|
r7 = data[511];
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shift bytes 503..0 (in that order) into r0, followed
|
* Shift bytes 503..0 (in that order) into r0, followed
|
||||||
* by eight zero bytes, while reducing the polynomial by the
|
* by eight zero bytes, while reducing the polynomial by the
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -32,7 +33,8 @@ static struct nand_ecclayout nand_oob_16 = {
|
|||||||
.eccpos = {0, 1, 2, 3, 6, 7},
|
.eccpos = {0, 1, 2, 3, 6, 7},
|
||||||
.oobfree = {
|
.oobfree = {
|
||||||
{.offset = 8,
|
{.offset = 8,
|
||||||
. length = 8}}
|
.length = 8}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nand_ecclayout nand_oob_64 = {
|
static struct nand_ecclayout nand_oob_64 = {
|
||||||
@@ -40,10 +42,12 @@ static struct nand_ecclayout nand_oob_64 = {
|
|||||||
.eccpos = {
|
.eccpos = {
|
||||||
40, 41, 42, 43, 44, 45, 46, 47,
|
40, 41, 42, 43, 44, 45, 46, 47,
|
||||||
48, 49, 50, 51, 52, 53, 54, 55,
|
48, 49, 50, 51, 52, 53, 54, 55,
|
||||||
56, 57, 58, 59, 60, 61, 62, 63},
|
56, 57, 58, 59, 60, 61, 62, 63
|
||||||
|
},
|
||||||
.oobfree = {
|
.oobfree = {
|
||||||
{.offset = 2,
|
{.offset = 2,
|
||||||
.length = 38}}
|
.length = 38}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void nand_fileio_init(struct nand_fileio_state *state)
|
void nand_fileio_init(struct nand_fileio_state *state)
|
||||||
@@ -56,19 +60,16 @@ int nand_fileio_start(struct command_context *cmd_ctx,
|
|||||||
struct nand_device *nand, const char *filename, int filemode,
|
struct nand_device *nand, const char *filename, int filemode,
|
||||||
struct nand_fileio_state *state)
|
struct nand_fileio_state *state)
|
||||||
{
|
{
|
||||||
if (state->address % nand->page_size)
|
if (state->address % nand->page_size) {
|
||||||
{
|
|
||||||
command_print(cmd_ctx, "only page-aligned addresses are supported");
|
command_print(cmd_ctx, "only page-aligned addresses are supported");
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_start(&state->bench);
|
duration_start(&state->bench);
|
||||||
|
|
||||||
if (NULL != filename)
|
if (NULL != filename) {
|
||||||
{
|
|
||||||
int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
|
int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval) {
|
||||||
{
|
|
||||||
const char *msg = (FILEIO_READ == filemode) ? "read" : "write";
|
const char *msg = (FILEIO_READ == filemode) ? "read" : "write";
|
||||||
command_print(cmd_ctx, "failed to open '%s' for %s access",
|
command_print(cmd_ctx, "failed to open '%s' for %s access",
|
||||||
filename, msg);
|
filename, msg);
|
||||||
@@ -77,21 +78,16 @@ int nand_fileio_start(struct command_context *cmd_ctx,
|
|||||||
state->file_opened = true;
|
state->file_opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(state->oob_format & NAND_OOB_ONLY))
|
if (!(state->oob_format & NAND_OOB_ONLY)) {
|
||||||
{
|
|
||||||
state->page_size = nand->page_size;
|
state->page_size = nand->page_size;
|
||||||
state->page = malloc(nand->page_size);
|
state->page = malloc(nand->page_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
|
if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW)) {
|
||||||
{
|
if (nand->page_size == 512) {
|
||||||
if (nand->page_size == 512)
|
|
||||||
{
|
|
||||||
state->oob_size = 16;
|
state->oob_size = 16;
|
||||||
state->eccpos = nand_oob_16.eccpos;
|
state->eccpos = nand_oob_16.eccpos;
|
||||||
}
|
} else if (nand->page_size == 2048) {
|
||||||
else if (nand->page_size == 2048)
|
|
||||||
{
|
|
||||||
state->oob_size = 64;
|
state->oob_size = 64;
|
||||||
state->eccpos = nand_oob_64.eccpos;
|
state->eccpos = nand_oob_64.eccpos;
|
||||||
}
|
}
|
||||||
@@ -105,13 +101,11 @@ int nand_fileio_cleanup(struct nand_fileio_state *state)
|
|||||||
if (state->file_opened)
|
if (state->file_opened)
|
||||||
fileio_close(&state->fileio);
|
fileio_close(&state->fileio);
|
||||||
|
|
||||||
if (state->oob)
|
if (state->oob) {
|
||||||
{
|
|
||||||
free(state->oob);
|
free(state->oob);
|
||||||
state->oob = NULL;
|
state->oob = NULL;
|
||||||
}
|
}
|
||||||
if (state->page)
|
if (state->page) {
|
||||||
{
|
|
||||||
free(state->page);
|
free(state->page);
|
||||||
state->page = NULL;
|
state->page = NULL;
|
||||||
}
|
}
|
||||||
@@ -138,27 +132,22 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
|||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (NULL == nand->device)
|
if (NULL == nand->device) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
|
||||||
if (need_size)
|
if (need_size) {
|
||||||
{
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
|
||||||
if (state->size % nand->page_size)
|
if (state->size % nand->page_size) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "only page-aligned sizes are supported");
|
command_print(CMD_CTX, "only page-aligned sizes are supported");
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CMD_ARGC > minargs)
|
if (CMD_ARGC > minargs) {
|
||||||
{
|
for (unsigned i = minargs; i < CMD_ARGC; i++) {
|
||||||
for (unsigned i = minargs; i < CMD_ARGC; i++)
|
|
||||||
{
|
|
||||||
if (!strcmp(CMD_ARGV[i], "oob_raw"))
|
if (!strcmp(CMD_ARGV[i], "oob_raw"))
|
||||||
state->oob_format |= NAND_OOB_RAW;
|
state->oob_format |= NAND_OOB_RAW;
|
||||||
else if (!strcmp(CMD_ARGV[i], "oob_only"))
|
else if (!strcmp(CMD_ARGV[i], "oob_only"))
|
||||||
@@ -167,8 +156,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
|||||||
state->oob_format |= NAND_OOB_SW_ECC;
|
state->oob_format |= NAND_OOB_SW_ECC;
|
||||||
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
|
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
|
||||||
state->oob_format |= NAND_OOB_SW_ECC_KW;
|
state->oob_format |= NAND_OOB_SW_ECC_KW;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
|
command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
@@ -179,8 +167,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
|||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!need_size)
|
if (!need_size) {
|
||||||
{
|
|
||||||
int filesize;
|
int filesize;
|
||||||
retval = fileio_size(&state->fileio, &filesize);
|
retval = fileio_size(&state->fileio, &filesize);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
@@ -202,28 +189,23 @@ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
|
|||||||
size_t total_read = 0;
|
size_t total_read = 0;
|
||||||
size_t one_read;
|
size_t one_read;
|
||||||
|
|
||||||
if (NULL != s->page)
|
if (NULL != s->page) {
|
||||||
{
|
|
||||||
fileio_read(&s->fileio, s->page_size, s->page, &one_read);
|
fileio_read(&s->fileio, s->page_size, s->page, &one_read);
|
||||||
if (one_read < s->page_size)
|
if (one_read < s->page_size)
|
||||||
memset(s->page + one_read, 0xff, s->page_size - one_read);
|
memset(s->page + one_read, 0xff, s->page_size - one_read);
|
||||||
total_read += one_read;
|
total_read += one_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->oob_format & NAND_OOB_SW_ECC)
|
if (s->oob_format & NAND_OOB_SW_ECC) {
|
||||||
{
|
|
||||||
uint8_t ecc[3];
|
uint8_t ecc[3];
|
||||||
memset(s->oob, 0xff, s->oob_size);
|
memset(s->oob, 0xff, s->oob_size);
|
||||||
for (uint32_t i = 0, j = 0; i < s->page_size; i += 256)
|
for (uint32_t i = 0, j = 0; i < s->page_size; i += 256) {
|
||||||
{
|
|
||||||
nand_calculate_ecc(nand, s->page + i, ecc);
|
nand_calculate_ecc(nand, s->page + i, ecc);
|
||||||
s->oob[s->eccpos[j++]] = ecc[0];
|
s->oob[s->eccpos[j++]] = ecc[0];
|
||||||
s->oob[s->eccpos[j++]] = ecc[1];
|
s->oob[s->eccpos[j++]] = ecc[1];
|
||||||
s->oob[s->eccpos[j++]] = ecc[2];
|
s->oob[s->eccpos[j++]] = ecc[2];
|
||||||
}
|
}
|
||||||
}
|
} else if (s->oob_format & NAND_OOB_SW_ECC_KW) {
|
||||||
else if (s->oob_format & NAND_OOB_SW_ECC_KW)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* In this case eccpos is not used as
|
* In this case eccpos is not used as
|
||||||
* the ECC data is always stored contigously
|
* the ECC data is always stored contigously
|
||||||
@@ -232,14 +214,11 @@ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
|
|||||||
*/
|
*/
|
||||||
uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10;
|
uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10;
|
||||||
memset(s->oob, 0xff, s->oob_size);
|
memset(s->oob, 0xff, s->oob_size);
|
||||||
for (uint32_t i = 0; i < s->page_size; i += 512)
|
for (uint32_t i = 0; i < s->page_size; i += 512) {
|
||||||
{
|
|
||||||
nand_calculate_ecc_kw(nand, s->page + i, ecc);
|
nand_calculate_ecc_kw(nand, s->page + i, ecc);
|
||||||
ecc += 10;
|
ecc += 10;
|
||||||
}
|
}
|
||||||
}
|
} else if (NULL != s->oob) {
|
||||||
else if (NULL != s->oob)
|
|
||||||
{
|
|
||||||
fileio_read(&s->fileio, s->oob_size, s->oob, &one_read);
|
fileio_read(&s->fileio, s->oob_size, s->oob, &one_read);
|
||||||
if (one_read < s->oob_size)
|
if (one_read < s->oob_size)
|
||||||
memset(s->oob + one_read, 0xff, s->oob_size - one_read);
|
memset(s->oob + one_read, 0xff, s->oob_size - one_read);
|
||||||
@@ -247,4 +226,3 @@ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
|
|||||||
}
|
}
|
||||||
return total_read;
|
return total_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NAND_FILEIO_H
|
#ifndef FLASH_NAND_FILEIO_H
|
||||||
#define FLASH_NAND_FILEIO_H
|
#define FLASH_NAND_FILEIO_H
|
||||||
|
|
||||||
@@ -54,4 +55,4 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
|||||||
|
|
||||||
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s);
|
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s);
|
||||||
|
|
||||||
#endif // FLASH_NAND_FILEIO_H
|
#endif /* FLASH_NAND_FILEIO_H */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NAND_IMP_H
|
#ifndef FLASH_NAND_IMP_H
|
||||||
#define FLASH_NAND_IMP_H
|
#define FLASH_NAND_IMP_H
|
||||||
|
|
||||||
@@ -36,4 +37,4 @@ int nand_probe(struct nand_device *nand);
|
|||||||
int nand_erase(struct nand_device *nand, int first_block, int last_block);
|
int nand_erase(struct nand_device *nand, int first_block, int last_block);
|
||||||
int nand_build_bbt(struct nand_device *nand, int first, int last);
|
int nand_build_bbt(struct nand_device *nand, int first, int last);
|
||||||
|
|
||||||
#endif // FLASH_NAND_IMP_H
|
#endif /* FLASH_NAND_IMP_H */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,18 +17,17 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef LPC3180_NAND_CONTROLLER_H
|
#ifndef LPC3180_NAND_CONTROLLER_H
|
||||||
#define LPC3180_NAND_CONTROLLER_H
|
#define LPC3180_NAND_CONTROLLER_H
|
||||||
|
|
||||||
enum lpc3180_selected_controller
|
enum lpc3180_selected_controller {
|
||||||
{
|
|
||||||
LPC3180_NO_CONTROLLER,
|
LPC3180_NO_CONTROLLER,
|
||||||
LPC3180_MLC_CONTROLLER,
|
LPC3180_MLC_CONTROLLER,
|
||||||
LPC3180_SLC_CONTROLLER,
|
LPC3180_SLC_CONTROLLER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpc3180_nand_controller
|
struct lpc3180_nand_controller {
|
||||||
{
|
|
||||||
int osc_freq;
|
int osc_freq;
|
||||||
enum lpc3180_selected_controller selected_controller;
|
enum lpc3180_selected_controller selected_controller;
|
||||||
int is_bulk;
|
int is_bulk;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -74,10 +75,8 @@ static dmac_ll_t dmalist[(2048/256) * 2 + 1];
|
|||||||
*/
|
*/
|
||||||
NAND_DEVICE_COMMAND_HANDLER(lpc32xx_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(lpc32xx_nand_device_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC < 3) {
|
if (CMD_ARGC < 3)
|
||||||
LOG_WARNING("incomplete 'lpc32xx' nand flash configuration");
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t osc_freq;
|
uint32_t osc_freq;
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq);
|
||||||
@@ -161,9 +160,9 @@ static float lpc32xx_cycle_time(struct nand_device *nand)
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pwr_ctrl & (1 << 2)) == 0) { /* DIRECT RUN mode */
|
if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */
|
||||||
hclk = sysclk;
|
hclk = sysclk;
|
||||||
} else {
|
else {
|
||||||
retval = target_read_u32(target, 0x40004058, &hclkpll_ctrl);
|
retval = target_read_u32(target, 0x40004058, &hclkpll_ctrl);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval) {
|
||||||
LOG_ERROR("could not read HCLKPLL_CTRL");
|
LOG_ERROR("could not read HCLKPLL_CTRL");
|
||||||
@@ -428,8 +427,7 @@ static int lpc32xx_reset(struct nand_device *nand)
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lpc32xx_controller_ready(nand, 100))
|
if (!lpc32xx_controller_ready(nand, 100)) {
|
||||||
{
|
|
||||||
LOG_ERROR("LPC32xx SLC NAND controller timed out "
|
LOG_ERROR("LPC32xx SLC NAND controller timed out "
|
||||||
"after reset");
|
"after reset");
|
||||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||||
@@ -730,7 +728,8 @@ static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page,
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((retval = nand_read_status(nand, &status)) != ERROR_OK) {
|
retval = nand_read_status(nand, &status);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("couldn't read status");
|
LOG_ERROR("couldn't read status");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -866,8 +865,7 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size,
|
|||||||
* data & 32 bytes of ECC data.
|
* data & 32 bytes of ECC data.
|
||||||
* 2. X'fer 64 bytes of Spare area from Flash to Memory.
|
* 2. X'fer 64 bytes of Spare area from Flash to Memory.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < page_size/0x100; i++)
|
for (i = 0; i < page_size/0x100; i++) {
|
||||||
{
|
|
||||||
dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256));
|
dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256));
|
||||||
dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst);
|
dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst);
|
||||||
dmalist[i*2].next_lli =
|
dmalist[i*2].next_lli =
|
||||||
@@ -883,9 +881,8 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size,
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (do_read)
|
if (do_read)
|
||||||
{
|
|
||||||
dmadst = target_mem_base + SPARE_OFFS;
|
dmadst = target_mem_base + SPARE_OFFS;
|
||||||
} else {
|
else {
|
||||||
dmasrc = target_mem_base + SPARE_OFFS;
|
dmasrc = target_mem_base + SPARE_OFFS;
|
||||||
dmalist[(i*2) - 1].next_lli = 0;/* last link = null on write */
|
dmalist[(i*2) - 1].next_lli = 0;/* last link = null on write */
|
||||||
dmalist[(i*2) - 1].next_ctrl |= (1 << 31); /* Set TC enable */
|
dmalist[(i*2) - 1].next_ctrl |= (1 << 31); /* Set TC enable */
|
||||||
@@ -895,7 +892,7 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size,
|
|||||||
dmalist[i*2].next_lli = 0;
|
dmalist[i*2].next_lli = 0;
|
||||||
dmalist[i*2].next_ctrl = oob_ctrl;
|
dmalist[i*2].next_ctrl = oob_ctrl;
|
||||||
|
|
||||||
return (i*2 + 1); /* Number of descriptors */
|
return i * 2 + 1; /* Number of descriptors */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count,
|
static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count,
|
||||||
@@ -996,10 +993,9 @@ static int lpc32xx_dma_ready(struct nand_device *nand, int timeout)
|
|||||||
LOG_ERROR("lpc32xx_dma_ready "
|
LOG_ERROR("lpc32xx_dma_ready "
|
||||||
"DMA error, aborted");
|
"DMA error, aborted");
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
} while (timeout-- > 0);
|
} while (timeout-- > 0);
|
||||||
@@ -1137,9 +1133,9 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
|
|||||||
static uint8_t foob[64];
|
static uint8_t foob[64];
|
||||||
int foob_size = nand->page_size == 2048 ? 64 : 16;
|
int foob_size = nand->page_size == 2048 ? 64 : 16;
|
||||||
memset(foob, 0xFF, foob_size);
|
memset(foob, 0xFF, foob_size);
|
||||||
if (oob) { /* Raw mode */
|
if (oob) /* Raw mode */
|
||||||
memcpy(foob, oob, oob_size);
|
memcpy(foob, oob, oob_size);
|
||||||
} else {
|
else {
|
||||||
/* Get HW generated ECC, made while writing data */
|
/* Get HW generated ECC, made while writing data */
|
||||||
int ecc_count = nand->page_size == 2048 ? 8 : 2;
|
int ecc_count = nand->page_size == 2048 ? 8 : 2;
|
||||||
static uint32_t hw_ecc[8];
|
static uint32_t hw_ecc[8];
|
||||||
@@ -1184,14 +1180,14 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
/* DMACCxConfig=
|
/* DMACCxConfig=
|
||||||
E=1,
|
* E=1,
|
||||||
SrcPeripheral = 1 (SLC),
|
* SrcPeripheral = 1 (SLC),
|
||||||
DestPeripheral = 1 (SLC),
|
* DestPeripheral = 1 (SLC),
|
||||||
FlowCntrl = 2 (Pher -> Mem, DMA),
|
* FlowCntrl = 2 (Pher -> Mem, DMA),
|
||||||
IE = 0,
|
* IE = 0,
|
||||||
ITC = 0,
|
* ITC = 0,
|
||||||
L= 0,
|
* L= 0,
|
||||||
H=0
|
* H=0
|
||||||
*/
|
*/
|
||||||
retval = target_write_u32(target, 0x31000110,
|
retval = target_write_u32(target, 0x31000110,
|
||||||
1 | 1<<1 | 1<<6 | 2<<11 | 0<<14
|
1 | 1<<1 | 1<<6 | 2<<11 | 0<<14
|
||||||
@@ -1318,8 +1314,8 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page,
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
if (nand->page_size == 512) {
|
if (nand->page_size == 512) {
|
||||||
/* small page device */
|
/* small page device
|
||||||
/* MLC_ADDR = 0x0 (one column cycle) */
|
* MLC_ADDR = 0x0 (one column cycle) */
|
||||||
retval = target_write_u32(target, 0x200b8004, 0x0);
|
retval = target_write_u32(target, 0x200b8004, 0x0);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval) {
|
||||||
LOG_ERROR("could not set MLC_ADDR");
|
LOG_ERROR("could not set MLC_ADDR");
|
||||||
@@ -1348,8 +1344,8 @@ static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* large page device */
|
/* large page device
|
||||||
/* MLC_ADDR = 0x0 (two column cycles) */
|
* MLC_ADDR = 0x0 (two column cycles) */
|
||||||
retval = target_write_u32(target, 0x200b8004, 0x0);
|
retval = target_write_u32(target, 0x200b8004, 0x0);
|
||||||
if (ERROR_OK != retval) {
|
if (ERROR_OK != retval) {
|
||||||
LOG_ERROR("could not set MLC_ADDR");
|
LOG_ERROR("could not set MLC_ADDR");
|
||||||
@@ -1759,9 +1755,8 @@ COMMAND_HANDLER(handle_lpc32xx_select_command)
|
|||||||
"no", "mlc", "slc"
|
"no", "mlc", "slc"
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) {
|
if ((CMD_ARGC < 1) || (CMD_ARGC > 3))
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned num;
|
unsigned num;
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||||
@@ -1781,10 +1776,9 @@ COMMAND_HANDLER(handle_lpc32xx_select_command)
|
|||||||
} else if (strcmp(CMD_ARGV[1], "slc") == 0) {
|
} else if (strcmp(CMD_ARGV[1], "slc") == 0) {
|
||||||
lpc32xx_info->selected_controller =
|
lpc32xx_info->selected_controller =
|
||||||
LPC32xx_SLC_CONTROLLER;
|
LPC32xx_SLC_CONTROLLER;
|
||||||
} else {
|
} else
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
command_print(CMD_CTX, "%s controller selected",
|
command_print(CMD_CTX, "%s controller selected",
|
||||||
selected[lpc32xx_info->selected_controller]);
|
selected[lpc32xx_info->selected_controller]);
|
||||||
@@ -1807,6 +1801,7 @@ static const struct command_registration lpc32xx_command_handler[] = {
|
|||||||
.name = "lpc32xx",
|
.name = "lpc32xx",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "LPC32xx NAND flash controller commands",
|
.help = "LPC32xx NAND flash controller commands",
|
||||||
|
.usage = "",
|
||||||
.chain = lpc32xx_exec_command_handlers,
|
.chain = lpc32xx_exec_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
|
|||||||
@@ -17,18 +17,17 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef LPC32xx_NAND_CONTROLLER_H
|
#ifndef LPC32xx_NAND_CONTROLLER_H
|
||||||
#define LPC32xx_NAND_CONTROLLER_H
|
#define LPC32xx_NAND_CONTROLLER_H
|
||||||
|
|
||||||
enum lpc32xx_selected_controller
|
enum lpc32xx_selected_controller {
|
||||||
{
|
|
||||||
LPC32xx_NO_CONTROLLER,
|
LPC32xx_NO_CONTROLLER,
|
||||||
LPC32xx_MLC_CONTROLLER,
|
LPC32xx_MLC_CONTROLLER,
|
||||||
LPC32xx_SLC_CONTROLLER,
|
LPC32xx_SLC_CONTROLLER,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpc32xx_nand_controller
|
struct lpc32xx_nand_controller {
|
||||||
{
|
|
||||||
int osc_freq;
|
int osc_freq;
|
||||||
enum lpc32xx_selected_controller selected_controller;
|
enum lpc32xx_selected_controller selected_controller;
|
||||||
int sw_write_protection;
|
int sw_write_protection;
|
||||||
|
|||||||
@@ -1,761 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Alexei Babich *
|
|
||||||
* Rezonans plc., Chelyabinsk, Russia *
|
|
||||||
* impatt@mail.ru *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2010 by Gaetan CARLIER *
|
|
||||||
* Trump s.a., Belgium *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Freescale iMX2* OpenOCD NAND Flash controller support.
|
|
||||||
* based on Freescale iMX3* OpenOCD NAND Flash controller support.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @imx27
|
|
||||||
* tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #",
|
|
||||||
* "nand write # file 0", "nand verify"
|
|
||||||
*
|
|
||||||
* get_next_halfword_from_sram_buffer() not tested
|
|
||||||
* !! all function only tested with 2k page nand device; imx27_write_page
|
|
||||||
* writes the 4 MAIN_BUFFER's and is not compatible with < 2k page
|
|
||||||
* !! oob must be be used due to NFS bug
|
|
||||||
*/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "imp.h"
|
|
||||||
#include "mx2.h"
|
|
||||||
#include <target/target.h>
|
|
||||||
|
|
||||||
/* This permits to print (in LOG_INFO) how much bytes
|
|
||||||
* has been written after a page read or write.
|
|
||||||
* This is useful when OpenOCD is used with a graphical
|
|
||||||
* front-end to estimate progression of the global read/write
|
|
||||||
*/
|
|
||||||
#undef _MX2_PRINT_STAT
|
|
||||||
//#define _MX2_PRINT_STAT
|
|
||||||
|
|
||||||
static const char target_not_halted_err_msg[] =
|
|
||||||
"target must be halted to use mx2 NAND flash controller";
|
|
||||||
static const char data_block_size_err_msg[] =
|
|
||||||
"minimal granularity is one half-word, %" PRId32 " is incorrect";
|
|
||||||
static const char sram_buffer_bounds_err_msg[] =
|
|
||||||
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
|
|
||||||
static const char get_status_register_err_msg[] = "can't get NAND status";
|
|
||||||
static uint32_t in_sram_address;
|
|
||||||
static unsigned char sign_of_sequental_byte_read;
|
|
||||||
|
|
||||||
static int initialize_nf_controller(struct nand_device *nand);
|
|
||||||
static int get_next_byte_from_sram_buffer(struct target * target, uint8_t * value);
|
|
||||||
static int get_next_halfword_from_sram_buffer(struct target * target,
|
|
||||||
uint16_t * value);
|
|
||||||
static int poll_for_complete_op(struct target * target, const char *text);
|
|
||||||
static int validate_target_state(struct nand_device *nand);
|
|
||||||
static int do_data_output(struct nand_device *nand);
|
|
||||||
|
|
||||||
static int imx27_command(struct nand_device *nand, uint8_t command);
|
|
||||||
static int imx27_address(struct nand_device *nand, uint8_t address);
|
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(imx27_nand_device_command)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info;
|
|
||||||
int hwecc_needed;
|
|
||||||
int x;
|
|
||||||
mx2_nf_info = malloc(sizeof(struct mx2_nf_controller));
|
|
||||||
if (mx2_nf_info == NULL) {
|
|
||||||
LOG_ERROR("no memory for nand controller");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nand->controller_priv = mx2_nf_info;
|
|
||||||
if (CMD_ARGC < 3) {
|
|
||||||
LOG_ERROR("use \"nand device imx27 target noecc|hwecc\"");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* check hwecc requirements
|
|
||||||
*/
|
|
||||||
|
|
||||||
hwecc_needed = strcmp(CMD_ARGV[2], "hwecc");
|
|
||||||
if (hwecc_needed == 0)
|
|
||||||
mx2_nf_info->flags.hw_ecc_enabled = 1;
|
|
||||||
else
|
|
||||||
mx2_nf_info->flags.hw_ecc_enabled = 0;
|
|
||||||
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_NONE;
|
|
||||||
mx2_nf_info->flags.target_little_endian =
|
|
||||||
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
|
|
||||||
/*
|
|
||||||
* testing host endianness
|
|
||||||
*/
|
|
||||||
x = 1;
|
|
||||||
if (*(char *) &x == 1)
|
|
||||||
mx2_nf_info->flags.host_little_endian = 1;
|
|
||||||
else
|
|
||||||
mx2_nf_info->flags.host_little_endian = 0;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_init(struct nand_device *nand)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
|
|
||||||
int validate_target_result;
|
|
||||||
uint16_t buffsize_register_content;
|
|
||||||
uint32_t pcsr_register_content;
|
|
||||||
int retval;
|
|
||||||
uint16_t nand_status_content;
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
|
|
||||||
target_read_u16(target, MX2_NF_BUFSIZ, &buffsize_register_content);
|
|
||||||
mx2_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
|
|
||||||
|
|
||||||
target_read_u32(target, MX2_FMCR, &pcsr_register_content);
|
|
||||||
if (!nand->bus_width) {
|
|
||||||
/* bus_width not yet defined. Read it from MX2_FMCR */
|
|
||||||
nand->bus_width =
|
|
||||||
(pcsr_register_content & MX2_FMCR_NF_16BIT_SEL) ? 16 : 8;
|
|
||||||
} else {
|
|
||||||
/* bus_width forced in soft. Sync it to MX2_FMCR */
|
|
||||||
pcsr_register_content |=
|
|
||||||
((nand->bus_width == 16) ? MX2_FMCR_NF_16BIT_SEL : 0x00000000);
|
|
||||||
target_write_u32(target, MX2_FMCR, pcsr_register_content);
|
|
||||||
}
|
|
||||||
if (nand->bus_width == 16)
|
|
||||||
LOG_DEBUG("MX2_NF : bus is 16-bit width");
|
|
||||||
else
|
|
||||||
LOG_DEBUG("MX2_NF : bus is 8-bit width");
|
|
||||||
|
|
||||||
if (!nand->page_size) {
|
|
||||||
nand->page_size =
|
|
||||||
(pcsr_register_content & MX2_FMCR_NF_FMS) ? 2048 : 512;
|
|
||||||
} else {
|
|
||||||
pcsr_register_content |=
|
|
||||||
((nand->page_size == 2048) ? MX2_FMCR_NF_FMS : 0x00000000);
|
|
||||||
target_write_u32(target, MX2_FMCR, pcsr_register_content);
|
|
||||||
}
|
|
||||||
if (mx2_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
|
|
||||||
LOG_ERROR("NAND controller have only 1 kb SRAM, so "
|
|
||||||
"pagesize 2048 is incompatible with it");
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("MX2_NF : NAND controller can handle pagesize of 2048");
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize_nf_controller(nand);
|
|
||||||
|
|
||||||
retval = ERROR_OK;
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_STATUS);
|
|
||||||
retval |= imx27_address(nand, 0x00);
|
|
||||||
retval |= do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR(get_status_register_err_msg);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
target_read_u16(target, MX2_NF_MAIN_BUFFER0, &nand_status_content);
|
|
||||||
if (!(nand_status_content & 0x0080)) {
|
|
||||||
LOG_INFO("NAND read-only");
|
|
||||||
mx2_nf_info->flags.nand_readonly = 1;
|
|
||||||
} else {
|
|
||||||
mx2_nf_info->flags.nand_readonly = 0;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_read_data(struct nand_device *nand, void *data)
|
|
||||||
{
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int validate_target_result;
|
|
||||||
int try_data_output_from_nand_chip;
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get data from nand chip
|
|
||||||
*/
|
|
||||||
try_data_output_from_nand_chip = do_data_output(nand);
|
|
||||||
if (try_data_output_from_nand_chip != ERROR_OK) {
|
|
||||||
LOG_ERROR("imx27_read_data : read data failed : '%x'",
|
|
||||||
try_data_output_from_nand_chip);
|
|
||||||
return try_data_output_from_nand_chip;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nand->bus_width == 16)
|
|
||||||
get_next_halfword_from_sram_buffer(target, data);
|
|
||||||
else
|
|
||||||
get_next_byte_from_sram_buffer(target, data);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_write_data(struct nand_device *nand, uint16_t data)
|
|
||||||
{
|
|
||||||
LOG_ERROR("write_data() not implemented");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_reset(struct nand_device *nand)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
int validate_target_result;
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
initialize_nf_controller(nand);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_command(struct nand_device *nand, uint8_t command)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int validate_target_result;
|
|
||||||
int poll_result;
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
|
|
||||||
switch(command) {
|
|
||||||
case NAND_CMD_READOOB:
|
|
||||||
command = NAND_CMD_READ0;
|
|
||||||
/* set read point for data_read() and read_block_data() to
|
|
||||||
* spare area in SRAM buffer
|
|
||||||
*/
|
|
||||||
in_sram_address = MX2_NF_SPARE_BUFFER0;
|
|
||||||
break;
|
|
||||||
case NAND_CMD_READ1:
|
|
||||||
command = NAND_CMD_READ0;
|
|
||||||
/*
|
|
||||||
* offset == one half of page size
|
|
||||||
*/
|
|
||||||
in_sram_address =
|
|
||||||
MX2_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_FCMD, command);
|
|
||||||
/*
|
|
||||||
* start command input operation (set MX2_NF_BIT_OP_DONE==0)
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FCI);
|
|
||||||
poll_result = poll_for_complete_op(target, "command");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
/*
|
|
||||||
* reset cursor to begin of the buffer
|
|
||||||
*/
|
|
||||||
sign_of_sequental_byte_read = 0;
|
|
||||||
/* Handle special read command and adjust NF_CFG2(FDO) */
|
|
||||||
switch(command) {
|
|
||||||
case NAND_CMD_READID:
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDID;
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
break;
|
|
||||||
case NAND_CMD_STATUS:
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDSTATUS;
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
target_write_u16 (target, MX2_NF_BUFADDR, 0);
|
|
||||||
in_sram_address = 0;
|
|
||||||
break;
|
|
||||||
case NAND_CMD_READ0:
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Ohter command use the default 'One page data out' FDO */
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_address(struct nand_device *nand, uint8_t address)
|
|
||||||
{
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int validate_target_result;
|
|
||||||
int poll_result;
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_FADDR, address);
|
|
||||||
/*
|
|
||||||
* start address input operation (set MX2_NF_BIT_OP_DONE==0)
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FAI);
|
|
||||||
poll_result = poll_for_complete_op(target, "address");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_nand_ready(struct nand_device *nand, int tout)
|
|
||||||
{
|
|
||||||
uint16_t poll_complete_status;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int validate_target_result;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
validate_target_result = validate_target_state(nand);
|
|
||||||
if (validate_target_result != ERROR_OK)
|
|
||||||
return validate_target_result;
|
|
||||||
|
|
||||||
do {
|
|
||||||
target_read_u16(target, MX2_NF_CFG2, &poll_complete_status);
|
|
||||||
if (poll_complete_status & MX2_NF_BIT_OP_DONE)
|
|
||||||
return tout;
|
|
||||||
|
|
||||||
alive_sleep(1);
|
|
||||||
}
|
|
||||||
while (tout-- > 0);
|
|
||||||
return tout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_write_page(struct nand_device *nand, uint32_t page,
|
|
||||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
|
||||||
uint32_t oob_size)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int retval;
|
|
||||||
uint16_t nand_status_content;
|
|
||||||
uint16_t swap1, swap2, new_swap1;
|
|
||||||
int poll_result;
|
|
||||||
if (data_size % 2) {
|
|
||||||
LOG_ERROR(data_block_size_err_msg, data_size);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
if (oob_size % 2) {
|
|
||||||
LOG_ERROR(data_block_size_err_msg, oob_size);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
if (!data) {
|
|
||||||
LOG_ERROR("nothing to program");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
retval = validate_target_state(nand);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
|
||||||
sign_of_sequental_byte_read = 0;
|
|
||||||
retval = ERROR_OK;
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_SEQIN);
|
|
||||||
retval |= imx27_address(nand, 0); //col
|
|
||||||
retval |= imx27_address(nand, 0); //col
|
|
||||||
retval |= imx27_address(nand, page & 0xff); //page address
|
|
||||||
retval |= imx27_address(nand, (page >> 8) & 0xff); //page address
|
|
||||||
retval |= imx27_address(nand, (page >> 16) & 0xff); //page address
|
|
||||||
|
|
||||||
target_write_buffer(target, MX2_NF_MAIN_BUFFER0, data_size, data);
|
|
||||||
if (oob) {
|
|
||||||
if (mx2_nf_info->flags.hw_ecc_enabled) {
|
|
||||||
/*
|
|
||||||
* part of spare block will be overrided by hardware
|
|
||||||
* ECC generator
|
|
||||||
*/
|
|
||||||
LOG_DEBUG("part of spare block will be overrided "
|
|
||||||
"by hardware ECC generator");
|
|
||||||
}
|
|
||||||
target_write_buffer(target, MX2_NF_SPARE_BUFFER0, oob_size,
|
|
||||||
oob);
|
|
||||||
}
|
|
||||||
//BI-swap - work-around of imx27 NFC for NAND device with page == 2kb
|
|
||||||
target_read_u16(target, MX2_NF_MAIN_BUFFER3 + 464, &swap1);
|
|
||||||
if (oob) {
|
|
||||||
LOG_ERROR("Due to NFC Bug, oob is not correctly implemented "
|
|
||||||
"in mx2 driver");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
//target_read_u16 (target, MX2_NF_SPARE_BUFFER3 + 4, &swap2);
|
|
||||||
swap2 = 0xffff; //Spare buffer unused forced to 0xffff
|
|
||||||
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
|
||||||
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_MAIN_BUFFER3 + 464, new_swap1);
|
|
||||||
target_write_u16(target, MX2_NF_SPARE_BUFFER3 + 4, swap2);
|
|
||||||
/*
|
|
||||||
* start data input operation (set MX2_NF_BIT_OP_DONE==0)
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 0);
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
|
||||||
poll_result = poll_for_complete_op(target, "data input");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 1);
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
|
||||||
poll_result = poll_for_complete_op(target, "data input");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 2);
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
|
||||||
poll_result = poll_for_complete_op(target, "data input");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 3);
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
|
||||||
poll_result = poll_for_complete_op(target, "data input");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_PAGEPROG);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check status register
|
|
||||||
*/
|
|
||||||
retval = ERROR_OK;
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_STATUS);
|
|
||||||
target_write_u16 (target, MX2_NF_BUFADDR, 0);
|
|
||||||
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDSTATUS;
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
retval |= do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR (get_status_register_err_msg);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
target_read_u16 (target, MX2_NF_MAIN_BUFFER0, &nand_status_content);
|
|
||||||
if (nand_status_content & 0x0001) {
|
|
||||||
/*
|
|
||||||
* page not correctly written
|
|
||||||
*/
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
#ifdef _MX2_PRINT_STAT
|
|
||||||
LOG_INFO("%d bytes newly written", data_size);
|
|
||||||
#endif
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx27_read_page(struct nand_device *nand, uint32_t page,
|
|
||||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
|
||||||
uint32_t oob_size)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int retval;
|
|
||||||
uint16_t swap1, swap2, new_swap1;
|
|
||||||
if (data_size % 2) {
|
|
||||||
LOG_ERROR(data_block_size_err_msg, data_size);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
if (oob_size % 2) {
|
|
||||||
LOG_ERROR(data_block_size_err_msg, oob_size);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* validate target state
|
|
||||||
*/
|
|
||||||
retval = validate_target_state(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
/* Reset address_cycles before imx27_command ?? */
|
|
||||||
retval = ERROR_OK;
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_READ0);
|
|
||||||
|
|
||||||
retval |= imx27_address(nand, 0); //col
|
|
||||||
retval |= imx27_address(nand, 0); //col
|
|
||||||
retval |= imx27_address(nand, page & 0xff); //page address
|
|
||||||
retval |= imx27_address(nand, (page >> 8) & 0xff); //page address
|
|
||||||
retval |= imx27_address(nand, (page >> 16) & 0xff); //page address
|
|
||||||
retval |= imx27_command(nand, NAND_CMD_READSTART);
|
|
||||||
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 0);
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
retval = do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("MX2_NF : Error reading page 0");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
//Test nand page size to know how much MAIN_BUFFER must be written
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 1);
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
retval = do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("MX2_NF : Error reading page 1");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 2);
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
retval = do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("MX2_NF : Error reading page 2");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 3);
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
|
||||||
retval = do_data_output(nand);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("MX2_NF : Error reading page 3");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
//BI-swap - work-around of imx27 NFC for NAND device with page == 2k
|
|
||||||
target_read_u16(target, MX2_NF_MAIN_BUFFER3 + 464, &swap1);
|
|
||||||
target_read_u16(target, MX2_NF_SPARE_BUFFER3 + 4, &swap2);
|
|
||||||
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
|
||||||
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
|
||||||
target_write_u16(target, MX2_NF_MAIN_BUFFER3 + 464, new_swap1);
|
|
||||||
target_write_u16(target, MX2_NF_SPARE_BUFFER3 + 4, swap2);
|
|
||||||
|
|
||||||
if (data)
|
|
||||||
target_read_buffer(target, MX2_NF_MAIN_BUFFER0, data_size, data);
|
|
||||||
if (oob)
|
|
||||||
target_read_buffer(target, MX2_NF_SPARE_BUFFER0, oob_size,
|
|
||||||
oob);
|
|
||||||
#ifdef _MX2_PRINT_STAT
|
|
||||||
if (data_size > 0) {
|
|
||||||
/* When Operation Status is read (when page is erased),
|
|
||||||
* this function is used but data_size is null.
|
|
||||||
*/
|
|
||||||
LOG_INFO("%d bytes newly read", data_size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int initialize_nf_controller(struct nand_device *nand)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
uint16_t work_mode;
|
|
||||||
uint16_t temp;
|
|
||||||
/*
|
|
||||||
* resets NAND flash controller in zero time ? I dont know.
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_CFG1, MX2_NF_BIT_RESET_EN);
|
|
||||||
work_mode = MX2_NF_BIT_INT_DIS; /* disable interrupt */
|
|
||||||
if (target->endianness == TARGET_BIG_ENDIAN) {
|
|
||||||
LOG_DEBUG("MX2_NF : work in Big Endian mode");
|
|
||||||
work_mode |= MX2_NF_BIT_BE_EN;
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("MX2_NF : work in Little Endian mode");
|
|
||||||
}
|
|
||||||
if (mx2_nf_info->flags.hw_ecc_enabled) {
|
|
||||||
LOG_DEBUG("MX2_NF : work with ECC mode");
|
|
||||||
work_mode |= MX2_NF_BIT_ECC_EN;
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG("MX2_NF : work without ECC mode");
|
|
||||||
}
|
|
||||||
target_write_u16(target, MX2_NF_CFG1, work_mode);
|
|
||||||
/*
|
|
||||||
* unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_BUFCFG, 2);
|
|
||||||
target_read_u16(target, MX2_NF_FWP, &temp);
|
|
||||||
if ((temp & 0x0007) == 1) {
|
|
||||||
LOG_ERROR("NAND flash is tight-locked, reset needed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* unlock NAND flash for write
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_FWP, 4);
|
|
||||||
target_write_u16(target, MX2_NF_LOCKSTART, 0x0000);
|
|
||||||
target_write_u16(target, MX2_NF_LOCKEND, 0xFFFF);
|
|
||||||
/*
|
|
||||||
* 0x0000 means that first SRAM buffer @0xD800_0000 will be used
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_BUFADDR, 0x0000);
|
|
||||||
/*
|
|
||||||
* address of SRAM buffer
|
|
||||||
*/
|
|
||||||
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
|
||||||
sign_of_sequental_byte_read = 0;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_next_byte_from_sram_buffer(struct target * target, uint8_t * value)
|
|
||||||
{
|
|
||||||
static uint8_t even_byte = 0;
|
|
||||||
uint16_t temp;
|
|
||||||
/*
|
|
||||||
* host-big_endian ??
|
|
||||||
*/
|
|
||||||
if (sign_of_sequental_byte_read == 0)
|
|
||||||
even_byte = 0;
|
|
||||||
|
|
||||||
if (in_sram_address > MX2_NF_LAST_BUFFER_ADDR) {
|
|
||||||
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
|
||||||
*value = 0;
|
|
||||||
sign_of_sequental_byte_read = 0;
|
|
||||||
even_byte = 0;
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
} else {
|
|
||||||
target_read_u16(target, in_sram_address, &temp);
|
|
||||||
if (even_byte) {
|
|
||||||
*value = temp >> 8;
|
|
||||||
even_byte = 0;
|
|
||||||
in_sram_address += 2;
|
|
||||||
} else {
|
|
||||||
*value = temp & 0xff;
|
|
||||||
even_byte = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sign_of_sequental_byte_read = 1;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_next_halfword_from_sram_buffer(struct target * target,
|
|
||||||
uint16_t * value)
|
|
||||||
{
|
|
||||||
if (in_sram_address > MX2_NF_LAST_BUFFER_ADDR) {
|
|
||||||
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
|
||||||
*value = 0;
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
} else {
|
|
||||||
target_read_u16(target, in_sram_address, value);
|
|
||||||
in_sram_address += 2;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int poll_for_complete_op(struct target * target, const char *text)
|
|
||||||
{
|
|
||||||
uint16_t poll_complete_status;
|
|
||||||
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) {
|
|
||||||
target_read_u16(target, MX2_NF_CFG2, &poll_complete_status);
|
|
||||||
if (poll_complete_status & MX2_NF_BIT_OP_DONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
usleep(10);
|
|
||||||
}
|
|
||||||
if (!(poll_complete_status & MX2_NF_BIT_OP_DONE)) {
|
|
||||||
LOG_ERROR("%s sending timeout", text);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int validate_target_state(struct nand_device *nand)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
|
||||||
LOG_ERROR(target_not_halted_err_msg);
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mx2_nf_info->flags.target_little_endian !=
|
|
||||||
(target->endianness == TARGET_LITTLE_ENDIAN)) {
|
|
||||||
/*
|
|
||||||
* endianness changed after NAND controller probed
|
|
||||||
*/
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_data_output(struct nand_device *nand)
|
|
||||||
{
|
|
||||||
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
|
||||||
struct target *target = nand->target;
|
|
||||||
int poll_result;
|
|
||||||
uint16_t ecc_status;
|
|
||||||
switch(mx2_nf_info->fin) {
|
|
||||||
case MX2_NF_FIN_DATAOUT:
|
|
||||||
/*
|
|
||||||
* start data output operation (set MX2_NF_BIT_OP_DONE==0)
|
|
||||||
*/
|
|
||||||
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_DATAOUT_TYPE(mx2_nf_info->optype));
|
|
||||||
poll_result = poll_for_complete_op(target, "data output");
|
|
||||||
if (poll_result != ERROR_OK)
|
|
||||||
return poll_result;
|
|
||||||
|
|
||||||
mx2_nf_info->fin = MX2_NF_FIN_NONE;
|
|
||||||
/*
|
|
||||||
* ECC stuff
|
|
||||||
*/
|
|
||||||
if ((mx2_nf_info->optype == MX2_NF_DATAOUT_PAGE) && mx2_nf_info->flags.hw_ecc_enabled) {
|
|
||||||
target_read_u16(target, MX2_NF_ECCSTATUS, &ecc_status);
|
|
||||||
switch(ecc_status & 0x000c) {
|
|
||||||
case 1 << 2:
|
|
||||||
LOG_INFO("main area readed with 1 (correctable) error");
|
|
||||||
break;
|
|
||||||
case 2 << 2:
|
|
||||||
LOG_INFO("main area readed with more than 1 (incorrectable) error");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch(ecc_status & 0x0003) {
|
|
||||||
case 1:
|
|
||||||
LOG_INFO("spare area readed with 1 (correctable) error");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
LOG_INFO("main area readed with more than 1 (incorrectable) error");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MX2_NF_FIN_NONE:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nand_flash_controller imx27_nand_flash_controller = {
|
|
||||||
.name = "imx27",
|
|
||||||
.nand_device_command = &imx27_nand_device_command,
|
|
||||||
.init = &imx27_init,
|
|
||||||
.reset = &imx27_reset,
|
|
||||||
.command = &imx27_command,
|
|
||||||
.address = &imx27_address,
|
|
||||||
.write_data = &imx27_write_data,
|
|
||||||
.read_data = &imx27_read_data,
|
|
||||||
.write_page = &imx27_write_page,
|
|
||||||
.read_page = &imx27_read_page,
|
|
||||||
.nand_ready = &imx27_nand_ready,
|
|
||||||
};
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Alexei Babich *
|
|
||||||
* Rezonans plc., Chelyabinsk, Russia *
|
|
||||||
* impatt@mail.ru *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Freescale iMX2* OpenOCD NAND Flash controller support.
|
|
||||||
* based on Freescale iMX3* OpenOCD NAND Flash controller support.
|
|
||||||
*
|
|
||||||
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MX2_NF_BASE_ADDR 0xd8000000
|
|
||||||
#define MX2_NF_BUFSIZ (MX2_NF_BASE_ADDR + 0xe00)
|
|
||||||
#define MX2_NF_BUFADDR (MX2_NF_BASE_ADDR + 0xe04)
|
|
||||||
#define MX2_NF_FADDR (MX2_NF_BASE_ADDR + 0xe06)
|
|
||||||
#define MX2_NF_FCMD (MX2_NF_BASE_ADDR + 0xe08)
|
|
||||||
#define MX2_NF_BUFCFG (MX2_NF_BASE_ADDR + 0xe0a)
|
|
||||||
#define MX2_NF_ECCSTATUS (MX2_NF_BASE_ADDR + 0xe0c)
|
|
||||||
#define MX2_NF_ECCMAINPOS (MX2_NF_BASE_ADDR + 0xe0e)
|
|
||||||
#define MX2_NF_ECCSPAREPOS (MX2_NF_BASE_ADDR + 0xe10)
|
|
||||||
#define MX2_NF_FWP (MX2_NF_BASE_ADDR + 0xe12)
|
|
||||||
#define MX2_NF_LOCKSTART (MX2_NF_BASE_ADDR + 0xe14)
|
|
||||||
#define MX2_NF_LOCKEND (MX2_NF_BASE_ADDR + 0xe16)
|
|
||||||
#define MX2_NF_FWPSTATUS (MX2_NF_BASE_ADDR + 0xe18)
|
|
||||||
/*
|
|
||||||
* all bits not marked as self-clearing bit
|
|
||||||
*/
|
|
||||||
#define MX2_NF_CFG1 (MX2_NF_BASE_ADDR + 0xe1a)
|
|
||||||
#define MX2_NF_CFG2 (MX2_NF_BASE_ADDR + 0xe1c)
|
|
||||||
|
|
||||||
#define MX2_NF_MAIN_BUFFER0 (MX2_NF_BASE_ADDR + 0x0000)
|
|
||||||
#define MX2_NF_MAIN_BUFFER1 (MX2_NF_BASE_ADDR + 0x0200)
|
|
||||||
#define MX2_NF_MAIN_BUFFER2 (MX2_NF_BASE_ADDR + 0x0400)
|
|
||||||
#define MX2_NF_MAIN_BUFFER3 (MX2_NF_BASE_ADDR + 0x0600)
|
|
||||||
#define MX2_NF_SPARE_BUFFER0 (MX2_NF_BASE_ADDR + 0x0800)
|
|
||||||
#define MX2_NF_SPARE_BUFFER1 (MX2_NF_BASE_ADDR + 0x0810)
|
|
||||||
#define MX2_NF_SPARE_BUFFER2 (MX2_NF_BASE_ADDR + 0x0820)
|
|
||||||
#define MX2_NF_SPARE_BUFFER3 (MX2_NF_BASE_ADDR + 0x0830)
|
|
||||||
#define MX2_NF_MAIN_BUFFER_LEN 512
|
|
||||||
#define MX2_NF_SPARE_BUFFER_LEN 16
|
|
||||||
#define MX2_NF_LAST_BUFFER_ADDR ((MX2_NF_SPARE_BUFFER3) + MX2_NF_SPARE_BUFFER_LEN - 2)
|
|
||||||
|
|
||||||
/* bits in MX2_NF_CFG1 register */
|
|
||||||
#define MX2_NF_BIT_SPARE_ONLY_EN (1<<2)
|
|
||||||
#define MX2_NF_BIT_ECC_EN (1<<3)
|
|
||||||
#define MX2_NF_BIT_INT_DIS (1<<4)
|
|
||||||
#define MX2_NF_BIT_BE_EN (1<<5)
|
|
||||||
#define MX2_NF_BIT_RESET_EN (1<<6)
|
|
||||||
#define MX2_NF_BIT_FORCE_CE (1<<7)
|
|
||||||
|
|
||||||
/* bits in MX2_NF_CFG2 register */
|
|
||||||
|
|
||||||
/*Flash Command Input*/
|
|
||||||
#define MX2_NF_BIT_OP_FCI (1<<0)
|
|
||||||
/*
|
|
||||||
* Flash Address Input
|
|
||||||
*/
|
|
||||||
#define MX2_NF_BIT_OP_FAI (1<<1)
|
|
||||||
/*
|
|
||||||
* Flash Data Input
|
|
||||||
*/
|
|
||||||
#define MX2_NF_BIT_OP_FDI (1<<2)
|
|
||||||
|
|
||||||
/* see "enum mx_dataout_type" below */
|
|
||||||
#define MX2_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
|
||||||
#define MX2_NF_BIT_OP_DONE (1<<15)
|
|
||||||
|
|
||||||
#define MX2_CCM_CGR2 0x53f80028
|
|
||||||
#define MX2_GPR 0x43fac008
|
|
||||||
//#define MX2_PCSR 0x53f8000c
|
|
||||||
#define MX2_FMCR 0x10027814
|
|
||||||
#define MX2_FMCR_NF_16BIT_SEL (1<<4)
|
|
||||||
#define MX2_FMCR_NF_FMS (1<<5)
|
|
||||||
|
|
||||||
enum mx_dataout_type
|
|
||||||
{
|
|
||||||
MX2_NF_DATAOUT_PAGE = 1,
|
|
||||||
MX2_NF_DATAOUT_NANDID = 2,
|
|
||||||
MX2_NF_DATAOUT_NANDSTATUS = 4,
|
|
||||||
};
|
|
||||||
enum mx_nf_finalize_action
|
|
||||||
{
|
|
||||||
MX2_NF_FIN_NONE,
|
|
||||||
MX2_NF_FIN_DATAOUT,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mx2_nf_flags
|
|
||||||
{
|
|
||||||
unsigned host_little_endian:1;
|
|
||||||
unsigned target_little_endian:1;
|
|
||||||
unsigned nand_readonly:1;
|
|
||||||
unsigned one_kb_sram:1;
|
|
||||||
unsigned hw_ecc_enabled:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mx2_nf_controller
|
|
||||||
{
|
|
||||||
enum mx_dataout_type optype;
|
|
||||||
enum mx_nf_finalize_action fin;
|
|
||||||
struct mx2_nf_flags flags;
|
|
||||||
};
|
|
||||||
@@ -66,8 +66,7 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info;
|
struct mx3_nf_controller *mx3_nf_info;
|
||||||
mx3_nf_info = malloc(sizeof(struct mx3_nf_controller));
|
mx3_nf_info = malloc(sizeof(struct mx3_nf_controller));
|
||||||
if (mx3_nf_info == NULL)
|
if (mx3_nf_info == NULL) {
|
||||||
{
|
|
||||||
LOG_ERROR("no memory for nand controller");
|
LOG_ERROR("no memory for nand controller");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -75,10 +74,7 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
nand->controller_priv = mx3_nf_info;
|
nand->controller_priv = mx3_nf_info;
|
||||||
|
|
||||||
if (CMD_ARGC < 3)
|
if (CMD_ARGC < 3)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* check hwecc requirements
|
* check hwecc requirements
|
||||||
*/
|
*/
|
||||||
@@ -86,14 +82,10 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
int hwecc_needed;
|
int hwecc_needed;
|
||||||
hwecc_needed = strcmp(CMD_ARGV[2], "hwecc");
|
hwecc_needed = strcmp(CMD_ARGV[2], "hwecc");
|
||||||
if (hwecc_needed == 0)
|
if (hwecc_needed == 0)
|
||||||
{
|
|
||||||
mx3_nf_info->flags.hw_ecc_enabled = 1;
|
mx3_nf_info->flags.hw_ecc_enabled = 1;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
mx3_nf_info->flags.hw_ecc_enabled = 0;
|
mx3_nf_info->flags.hw_ecc_enabled = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
||||||
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
||||||
@@ -105,14 +97,10 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
{
|
{
|
||||||
int x = 1;
|
int x = 1;
|
||||||
if (*(char *) &x == 1)
|
if (*(char *) &x == 1)
|
||||||
{
|
|
||||||
mx3_nf_info->flags.host_little_endian = 1;
|
mx3_nf_info->flags.host_little_endian = 1;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
mx3_nf_info->flags.host_little_endian = 0;
|
mx3_nf_info->flags.host_little_endian = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +116,8 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
uint16_t buffsize_register_content;
|
uint16_t buffsize_register_content;
|
||||||
@@ -142,41 +128,29 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
{
|
{
|
||||||
uint32_t pcsr_register_content;
|
uint32_t pcsr_register_content;
|
||||||
target_read_u32(target, MX3_PCSR, &pcsr_register_content);
|
target_read_u32(target, MX3_PCSR, &pcsr_register_content);
|
||||||
if (!nand->bus_width)
|
if (!nand->bus_width) {
|
||||||
{
|
nand->bus_width = (pcsr_register_content & 0x80000000) ? 16 : 8;
|
||||||
nand->bus_width =
|
} else {
|
||||||
(pcsr_register_content & 0x80000000) ? 16 : 8;
|
pcsr_register_content |= ((nand->bus_width == 16) ? 0x80000000 : 0x00000000);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pcsr_register_content |=
|
|
||||||
((nand->bus_width == 16) ? 0x80000000 : 0x00000000);
|
|
||||||
target_write_u32(target, MX3_PCSR, pcsr_register_content);
|
target_write_u32(target, MX3_PCSR, pcsr_register_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nand->page_size)
|
if (!nand->page_size) {
|
||||||
{
|
nand->page_size = (pcsr_register_content & 0x40000000) ? 2048 : 512;
|
||||||
nand->page_size =
|
} else {
|
||||||
(pcsr_register_content & 0x40000000) ? 2048 : 512;
|
pcsr_register_content |= ((nand->page_size == 2048) ? 0x40000000 : 0x00000000);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pcsr_register_content |=
|
|
||||||
((nand->page_size == 2048) ? 0x40000000 : 0x00000000);
|
|
||||||
target_write_u32(target, MX3_PCSR, pcsr_register_content);
|
target_write_u32(target, MX3_PCSR, pcsr_register_content);
|
||||||
}
|
}
|
||||||
if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048))
|
if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
|
||||||
{
|
LOG_ERROR("NAND controller have only 1 kb SRAM, "
|
||||||
LOG_ERROR
|
"so pagesize 2048 is incompatible with it");
|
||||||
("NAND controller have only 1 kb SRAM, so pagesize 2048 is incompatible with it");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32_t cgr_register_content;
|
uint32_t cgr_register_content;
|
||||||
target_read_u32(target, MX3_CCM_CGR2, &cgr_register_content);
|
target_read_u32(target, MX3_CCM_CGR2, &cgr_register_content);
|
||||||
if (!(cgr_register_content & 0x00000300))
|
if (!(cgr_register_content & 0x00000300)) {
|
||||||
{
|
|
||||||
LOG_ERROR("clock gating to EMI disabled");
|
LOG_ERROR("clock gating to EMI disabled");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -185,8 +159,7 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
{
|
{
|
||||||
uint32_t gpr_register_content;
|
uint32_t gpr_register_content;
|
||||||
target_read_u32(target, MX3_GPR, &gpr_register_content);
|
target_read_u32(target, MX3_GPR, &gpr_register_content);
|
||||||
if (gpr_register_content & 0x00000060)
|
if (gpr_register_content & 0x00000060) {
|
||||||
{
|
|
||||||
LOG_ERROR("pins mode overrided by GPR");
|
LOG_ERROR("pins mode overrided by GPR");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -199,34 +172,20 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
*/
|
*/
|
||||||
int test_iomux;
|
int test_iomux;
|
||||||
test_iomux = ERROR_OK;
|
test_iomux = ERROR_OK;
|
||||||
test_iomux |=
|
test_iomux |= test_iomux_settings(target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2");
|
||||||
test_iomux_settings (target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2");
|
test_iomux |= test_iomux_settings(target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6");
|
||||||
test_iomux |=
|
test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x0000007f, "d7");
|
||||||
test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6");
|
if (nand->bus_width == 16) {
|
||||||
test_iomux |=
|
test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x7f7f7f00, "d8,d9,d10");
|
||||||
test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7");
|
test_iomux |= test_iomux_settings(target, 0x43fac0cc, 0x7f7f7f7f, "d11,d12,d13,d14");
|
||||||
if (nand->bus_width == 16)
|
test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x0000007f, "d15");
|
||||||
{
|
|
||||||
test_iomux |=
|
|
||||||
test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00,
|
|
||||||
"d8,d9,d10");
|
|
||||||
test_iomux |=
|
|
||||||
test_iomux_settings (target, 0x43fac0cc, 0x7f7f7f7f,
|
|
||||||
"d11,d12,d13,d14");
|
|
||||||
test_iomux |=
|
|
||||||
test_iomux_settings (target, 0x43fac0d0, 0x0000007f, "d15");
|
|
||||||
}
|
}
|
||||||
test_iomux |=
|
test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x7f7f7f00, "nfwp,nfce,nfrb");
|
||||||
test_iomux_settings (target, 0x43fac0d0, 0x7f7f7f00,
|
test_iomux |= test_iomux_settings(target, 0x43fac0d4, 0x7f7f7f7f,
|
||||||
"nfwp,nfce,nfrb");
|
|
||||||
test_iomux |=
|
|
||||||
test_iomux_settings (target, 0x43fac0d4, 0x7f7f7f7f,
|
|
||||||
"nfwe,nfre,nfale,nfcle");
|
"nfwe,nfre,nfale,nfcle");
|
||||||
if (test_iomux != ERROR_OK)
|
if (test_iomux != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
initialize_nf_controller(nand);
|
initialize_nf_controller(nand);
|
||||||
|
|
||||||
@@ -237,25 +196,20 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
retval |= imx31_command(nand, NAND_CMD_STATUS);
|
retval |= imx31_command(nand, NAND_CMD_STATUS);
|
||||||
retval |= imx31_address(nand, 0x00);
|
retval |= imx31_address(nand, 0x00);
|
||||||
retval |= do_data_output(nand);
|
retval |= do_data_output(nand);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR(get_status_register_err_msg);
|
LOG_ERROR(get_status_register_err_msg);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
if (!(nand_status_content & 0x0080))
|
if (!(nand_status_content & 0x0080)) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* is host-big-endian correctly ??
|
* is host-big-endian correctly ??
|
||||||
*/
|
*/
|
||||||
LOG_INFO("NAND read-only");
|
LOG_INFO("NAND read-only");
|
||||||
mx3_nf_info->flags.nand_readonly = 1;
|
mx3_nf_info->flags.nand_readonly = 1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
mx3_nf_info->flags.nand_readonly = 0;
|
mx3_nf_info->flags.nand_readonly = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,10 +223,8 @@ static int imx31_read_data (struct nand_device *nand, void *data)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -281,19 +233,13 @@ static int imx31_read_data (struct nand_device *nand, void *data)
|
|||||||
int try_data_output_from_nand_chip;
|
int try_data_output_from_nand_chip;
|
||||||
try_data_output_from_nand_chip = do_data_output(nand);
|
try_data_output_from_nand_chip = do_data_output(nand);
|
||||||
if (try_data_output_from_nand_chip != ERROR_OK)
|
if (try_data_output_from_nand_chip != ERROR_OK)
|
||||||
{
|
|
||||||
return try_data_output_from_nand_chip;
|
return try_data_output_from_nand_chip;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (nand->bus_width == 16)
|
if (nand->bus_width == 16)
|
||||||
{
|
|
||||||
get_next_halfword_from_sram_buffer(target, data);
|
get_next_halfword_from_sram_buffer(target, data);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
get_next_byte_from_sram_buffer(target, data);
|
get_next_byte_from_sram_buffer(target, data);
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -312,9 +258,7 @@ static int imx31_reset (struct nand_device *nand)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
|
||||||
initialize_nf_controller(nand);
|
initialize_nf_controller(nand);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -330,13 +274,10 @@ static int imx31_command (struct nand_device *nand, uint8_t command)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch (command)
|
switch (command) {
|
||||||
{
|
|
||||||
case NAND_CMD_READOOB:
|
case NAND_CMD_READOOB:
|
||||||
command = NAND_CMD_READ0;
|
command = NAND_CMD_READ0;
|
||||||
in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for
|
in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for
|
||||||
@@ -350,8 +291,7 @@ static int imx31_command (struct nand_device *nand, uint8_t command)
|
|||||||
/*
|
/*
|
||||||
* offset == one half of page size
|
* offset == one half of page size
|
||||||
*/
|
*/
|
||||||
in_sram_address =
|
in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
||||||
MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
|
||||||
default:
|
default:
|
||||||
in_sram_address = MX3_NF_MAIN_BUFFER0;
|
in_sram_address = MX3_NF_MAIN_BUFFER0;
|
||||||
}
|
}
|
||||||
@@ -365,16 +305,13 @@ static int imx31_command (struct nand_device *nand, uint8_t command)
|
|||||||
int poll_result;
|
int poll_result;
|
||||||
poll_result = poll_for_complete_op(target, "command");
|
poll_result = poll_for_complete_op(target, "command");
|
||||||
if (poll_result != ERROR_OK)
|
if (poll_result != ERROR_OK)
|
||||||
{
|
|
||||||
return poll_result;
|
return poll_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* reset cursor to begin of the buffer
|
* reset cursor to begin of the buffer
|
||||||
*/
|
*/
|
||||||
sign_of_sequental_byte_read = 0;
|
sign_of_sequental_byte_read = 0;
|
||||||
switch (command)
|
switch (command) {
|
||||||
{
|
|
||||||
case NAND_CMD_READID:
|
case NAND_CMD_READID:
|
||||||
mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID;
|
mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID;
|
||||||
mx3_nf_info->fin = MX3_NF_FIN_DATAOUT;
|
mx3_nf_info->fin = MX3_NF_FIN_DATAOUT;
|
||||||
@@ -403,10 +340,8 @@ static int imx31_address (struct nand_device *nand, uint8_t address)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
target_write_u16(target, MX3_NF_FADDR, address);
|
target_write_u16(target, MX3_NF_FADDR, address);
|
||||||
/*
|
/*
|
||||||
@@ -417,10 +352,8 @@ static int imx31_address (struct nand_device *nand, uint8_t address)
|
|||||||
int poll_result;
|
int poll_result;
|
||||||
poll_result = poll_for_complete_op(target, "address");
|
poll_result = poll_for_complete_op(target, "address");
|
||||||
if (poll_result != ERROR_OK)
|
if (poll_result != ERROR_OK)
|
||||||
{
|
|
||||||
return poll_result;
|
return poll_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,21 +369,15 @@ static int imx31_nand_ready (struct nand_device *nand, int tout)
|
|||||||
int validate_target_result;
|
int validate_target_result;
|
||||||
validate_target_result = validate_target_state(nand);
|
validate_target_result = validate_target_state(nand);
|
||||||
if (validate_target_result != ERROR_OK)
|
if (validate_target_result != ERROR_OK)
|
||||||
{
|
|
||||||
return validate_target_result;
|
return validate_target_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
target_read_u16(target, MX3_NF_CFG2, &poll_complete_status);
|
target_read_u16(target, MX3_NF_CFG2, &poll_complete_status);
|
||||||
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
||||||
{
|
|
||||||
return tout;
|
return tout;
|
||||||
}
|
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
}
|
} while (tout-- > 0);
|
||||||
while (tout-- > 0);
|
|
||||||
return tout;
|
return tout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,18 +388,15 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
|||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (data_size % 2)
|
if (data_size % 2) {
|
||||||
{
|
|
||||||
LOG_ERROR(data_block_size_err_msg, data_size);
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
if (oob_size % 2)
|
if (oob_size % 2) {
|
||||||
{
|
|
||||||
LOG_ERROR(data_block_size_err_msg, oob_size);
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
if (!data)
|
if (!data) {
|
||||||
{
|
|
||||||
LOG_ERROR("nothing to program");
|
LOG_ERROR("nothing to program");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -483,38 +407,29 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
|||||||
int retval;
|
int retval;
|
||||||
retval = validate_target_state(nand);
|
retval = validate_target_state(nand);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
{
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
retval |= imx31_command(nand, NAND_CMD_SEQIN);
|
retval |= imx31_command(nand, NAND_CMD_SEQIN);
|
||||||
retval |= imx31_address(nand, 0x00);
|
retval |= imx31_address(nand, 0x00);
|
||||||
retval |= imx31_address(nand, page & 0xff);
|
retval |= imx31_address(nand, page & 0xff);
|
||||||
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
||||||
if (nand->address_cycles >= 4)
|
if (nand->address_cycles >= 4) {
|
||||||
{
|
|
||||||
retval |= imx31_address(nand, (page >> 16) & 0xff);
|
retval |= imx31_address(nand, (page >> 16) & 0xff);
|
||||||
if (nand->address_cycles >= 5)
|
if (nand->address_cycles >= 5)
|
||||||
{
|
|
||||||
retval |= imx31_address(nand, (page >> 24) & 0xff);
|
retval |= imx31_address(nand, (page >> 24) & 0xff);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
target_write_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data);
|
target_write_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data);
|
||||||
if (oob)
|
if (oob) {
|
||||||
{
|
if (mx3_nf_info->flags.hw_ecc_enabled) {
|
||||||
if (mx3_nf_info->flags.hw_ecc_enabled)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* part of spare block will be overrided by hardware
|
* part of spare block will be overrided by hardware
|
||||||
* ECC generator
|
* ECC generator
|
||||||
*/
|
*/
|
||||||
LOG_DEBUG
|
LOG_DEBUG("part of spare block will be overrided by hardware ECC generator");
|
||||||
("part of spare block will be overrided by hardware ECC generator");
|
|
||||||
}
|
}
|
||||||
target_write_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size,
|
target_write_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size, oob);
|
||||||
oob);
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* start data input operation (set MX3_NF_BIT_OP_DONE==0)
|
* start data input operation (set MX3_NF_BIT_OP_DONE==0)
|
||||||
@@ -524,15 +439,11 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
|||||||
int poll_result;
|
int poll_result;
|
||||||
poll_result = poll_for_complete_op(target, "data input");
|
poll_result = poll_for_complete_op(target, "data input");
|
||||||
if (poll_result != ERROR_OK)
|
if (poll_result != ERROR_OK)
|
||||||
{
|
|
||||||
return poll_result;
|
return poll_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
retval |= imx31_command(nand, NAND_CMD_PAGEPROG);
|
retval |= imx31_command(nand, NAND_CMD_PAGEPROG);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check status register
|
* check status register
|
||||||
@@ -543,14 +454,12 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
|||||||
retval |= imx31_command(nand, NAND_CMD_STATUS);
|
retval |= imx31_command(nand, NAND_CMD_STATUS);
|
||||||
retval |= imx31_address(nand, 0x00);
|
retval |= imx31_address(nand, 0x00);
|
||||||
retval |= do_data_output(nand);
|
retval |= do_data_output(nand);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR(get_status_register_err_msg);
|
LOG_ERROR(get_status_register_err_msg);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
if (nand_status_content & 0x0001)
|
if (nand_status_content & 0x0001) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* is host-big-endian correctly ??
|
* is host-big-endian correctly ??
|
||||||
*/
|
*/
|
||||||
@@ -567,13 +476,11 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
|
|||||||
{
|
{
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (data_size % 2)
|
if (data_size % 2) {
|
||||||
{
|
|
||||||
LOG_ERROR(data_block_size_err_msg, data_size);
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
if (oob_size % 2)
|
if (oob_size % 2) {
|
||||||
{
|
|
||||||
LOG_ERROR(data_block_size_err_msg, oob_size);
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -585,38 +492,30 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
|
|||||||
int retval;
|
int retval;
|
||||||
retval = validate_target_state(nand);
|
retval = validate_target_state(nand);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
{
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
retval |= imx31_command(nand, NAND_CMD_READ0);
|
retval |= imx31_command(nand, NAND_CMD_READ0);
|
||||||
retval |= imx31_address(nand, 0x00);
|
retval |= imx31_address(nand, 0x00);
|
||||||
retval |= imx31_address(nand, page & 0xff);
|
retval |= imx31_address(nand, page & 0xff);
|
||||||
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
||||||
if (nand->address_cycles >= 4)
|
if (nand->address_cycles >= 4) {
|
||||||
{
|
|
||||||
retval |= imx31_address(nand, (page >> 16) & 0xff);
|
retval |= imx31_address(nand, (page >> 16) & 0xff);
|
||||||
if (nand->address_cycles >= 5)
|
if (nand->address_cycles >= 5) {
|
||||||
{
|
|
||||||
retval |= imx31_address(nand, (page >> 24) & 0xff);
|
retval |= imx31_address(nand, (page >> 24) & 0xff);
|
||||||
retval |= imx31_command(nand, NAND_CMD_READSTART);
|
retval |= imx31_command(nand, NAND_CMD_READSTART);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval |= do_data_output(nand);
|
retval |= do_data_output(nand);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
if (data)
|
if (data) {
|
||||||
{
|
|
||||||
target_read_buffer(target, MX3_NF_MAIN_BUFFER0, data_size,
|
target_read_buffer(target, MX3_NF_MAIN_BUFFER0, data_size,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
if (oob)
|
if (oob) {
|
||||||
{
|
|
||||||
target_read_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size,
|
target_read_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size,
|
||||||
oob);
|
oob);
|
||||||
}
|
}
|
||||||
@@ -629,8 +528,7 @@ static int test_iomux_settings (struct target * target, uint32_t address,
|
|||||||
{
|
{
|
||||||
uint32_t register_content;
|
uint32_t register_content;
|
||||||
target_read_u32(target, address, ®ister_content);
|
target_read_u32(target, address, ®ister_content);
|
||||||
if ((register_content & mask) != (0x12121212 & mask))
|
if ((register_content & mask) != (0x12121212 & mask)) {
|
||||||
{
|
|
||||||
LOG_ERROR("IOMUX for {%s} is bad", text);
|
LOG_ERROR("IOMUX for {%s} is bad", text);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -649,13 +547,9 @@ static int initialize_nf_controller (struct nand_device *nand)
|
|||||||
uint16_t work_mode;
|
uint16_t work_mode;
|
||||||
work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */
|
work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */
|
||||||
if (target->endianness == TARGET_BIG_ENDIAN)
|
if (target->endianness == TARGET_BIG_ENDIAN)
|
||||||
{
|
|
||||||
work_mode |= MX3_NF_BIT_BE_EN;
|
work_mode |= MX3_NF_BIT_BE_EN;
|
||||||
}
|
|
||||||
if (mx3_nf_info->flags.hw_ecc_enabled)
|
if (mx3_nf_info->flags.hw_ecc_enabled)
|
||||||
{
|
|
||||||
work_mode |= MX3_NF_BIT_ECC_EN;
|
work_mode |= MX3_NF_BIT_ECC_EN;
|
||||||
}
|
|
||||||
target_write_u16(target, MX3_NF_CFG1, work_mode);
|
target_write_u16(target, MX3_NF_CFG1, work_mode);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -665,8 +559,7 @@ static int initialize_nf_controller (struct nand_device *nand)
|
|||||||
{
|
{
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
target_read_u16(target, MX3_NF_FWP, &temp);
|
target_read_u16(target, MX3_NF_FWP, &temp);
|
||||||
if ((temp & 0x0007) == 1)
|
if ((temp & 0x0007) == 1) {
|
||||||
{
|
|
||||||
LOG_ERROR("NAND flash is tight-locked, reset needed");
|
LOG_ERROR("NAND flash is tight-locked, reset needed");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -692,34 +585,26 @@ static int initialize_nf_controller (struct nand_device *nand)
|
|||||||
|
|
||||||
static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value)
|
static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value)
|
||||||
{
|
{
|
||||||
static uint8_t even_byte = 0;
|
static uint8_t even_byte;
|
||||||
/*
|
/*
|
||||||
* host-big_endian ??
|
* host-big_endian ??
|
||||||
*/
|
*/
|
||||||
if (sign_of_sequental_byte_read == 0)
|
if (sign_of_sequental_byte_read == 0)
|
||||||
{
|
|
||||||
even_byte = 0;
|
even_byte = 0;
|
||||||
}
|
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) {
|
||||||
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR)
|
|
||||||
{
|
|
||||||
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
*value = 0;
|
*value = 0;
|
||||||
sign_of_sequental_byte_read = 0;
|
sign_of_sequental_byte_read = 0;
|
||||||
even_byte = 0;
|
even_byte = 0;
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
target_read_u16(target, in_sram_address, &temp);
|
target_read_u16(target, in_sram_address, &temp);
|
||||||
if (even_byte)
|
if (even_byte) {
|
||||||
{
|
|
||||||
*value = temp >> 8;
|
*value = temp >> 8;
|
||||||
even_byte = 0;
|
even_byte = 0;
|
||||||
in_sram_address += 2;
|
in_sram_address += 2;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
*value = temp & 0xff;
|
*value = temp & 0xff;
|
||||||
even_byte = 1;
|
even_byte = 1;
|
||||||
}
|
}
|
||||||
@@ -731,14 +616,11 @@ static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * val
|
|||||||
static int get_next_halfword_from_sram_buffer(struct target *target,
|
static int get_next_halfword_from_sram_buffer(struct target *target,
|
||||||
uint16_t *value)
|
uint16_t *value)
|
||||||
{
|
{
|
||||||
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR)
|
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) {
|
||||||
{
|
|
||||||
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
*value = 0;
|
*value = 0;
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
target_read_u16(target, in_sram_address, value);
|
target_read_u16(target, in_sram_address, value);
|
||||||
in_sram_address += 2;
|
in_sram_address += 2;
|
||||||
}
|
}
|
||||||
@@ -748,17 +630,13 @@ static int get_next_halfword_from_sram_buffer (struct target * target,
|
|||||||
static int poll_for_complete_op(struct target *target, const char *text)
|
static int poll_for_complete_op(struct target *target, const char *text)
|
||||||
{
|
{
|
||||||
uint16_t poll_complete_status;
|
uint16_t poll_complete_status;
|
||||||
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++)
|
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) {
|
||||||
{
|
|
||||||
usleep(25);
|
usleep(25);
|
||||||
target_read_u16(target, MX3_NF_CFG2, &poll_complete_status);
|
target_read_u16(target, MX3_NF_CFG2, &poll_complete_status);
|
||||||
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
if (!(poll_complete_status & MX3_NF_BIT_OP_DONE)) {
|
||||||
if (!(poll_complete_status & MX3_NF_BIT_OP_DONE))
|
|
||||||
{
|
|
||||||
LOG_ERROR("%s sending timeout", text);
|
LOG_ERROR("%s sending timeout", text);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -770,15 +648,13 @@ static int validate_target_state (struct nand_device *nand)
|
|||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR(target_not_halted_err_msg);
|
LOG_ERROR(target_not_halted_err_msg);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mx3_nf_info->flags.target_little_endian !=
|
if (mx3_nf_info->flags.target_little_endian !=
|
||||||
(target->endianness == TARGET_LITTLE_ENDIAN))
|
(target->endianness == TARGET_LITTLE_ENDIAN)) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* endianness changed after NAND controller probed
|
* endianness changed after NAND controller probed
|
||||||
*/
|
*/
|
||||||
@@ -791,53 +667,42 @@ static int do_data_output (struct nand_device *nand)
|
|||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
switch (mx3_nf_info->fin)
|
switch (mx3_nf_info->fin) {
|
||||||
{
|
|
||||||
case MX3_NF_FIN_DATAOUT:
|
case MX3_NF_FIN_DATAOUT:
|
||||||
/*
|
/*
|
||||||
* start data output operation (set MX3_NF_BIT_OP_DONE==0)
|
* start data output operation (set MX3_NF_BIT_OP_DONE==0)
|
||||||
*/
|
*/
|
||||||
target_write_u16 (target, MX3_NF_CFG2,
|
target_write_u16 (target, MX3_NF_CFG2,
|
||||||
MX3_NF_BIT_DATAOUT_TYPE (mx3_nf_info->
|
MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype));
|
||||||
optype));
|
|
||||||
{
|
{
|
||||||
int poll_result;
|
int poll_result;
|
||||||
poll_result = poll_for_complete_op(target, "data output");
|
poll_result = poll_for_complete_op(target, "data output");
|
||||||
if (poll_result != ERROR_OK)
|
if (poll_result != ERROR_OK)
|
||||||
{
|
|
||||||
return poll_result;
|
return poll_result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
||||||
/*
|
/*
|
||||||
* ECC stuff
|
* ECC stuff
|
||||||
*/
|
*/
|
||||||
if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE)
|
if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE)
|
||||||
&& mx3_nf_info->flags.hw_ecc_enabled)
|
&& mx3_nf_info->flags.hw_ecc_enabled) {
|
||||||
{
|
|
||||||
uint16_t ecc_status;
|
uint16_t ecc_status;
|
||||||
target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status);
|
target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status);
|
||||||
switch (ecc_status & 0x000c)
|
switch (ecc_status & 0x000c) {
|
||||||
{
|
|
||||||
case 1 << 2:
|
case 1 << 2:
|
||||||
LOG_DEBUG
|
LOG_DEBUG("main area readed with 1 (correctable) error");
|
||||||
("main area readed with 1 (correctable) error");
|
|
||||||
break;
|
break;
|
||||||
case 2 << 2:
|
case 2 << 2:
|
||||||
LOG_DEBUG
|
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
|
||||||
("main area readed with more than 1 (incorrectable) error");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (ecc_status & 0x0003)
|
switch (ecc_status & 0x0003) {
|
||||||
{
|
|
||||||
case 1:
|
case 1:
|
||||||
LOG_DEBUG
|
LOG_DEBUG("spare area readed with 1 (correctable) error");
|
||||||
("spare area readed with 1 (correctable) error");
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
LOG_DEBUG
|
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
|
||||||
("main area readed with more than 1 (incorrectable) error");
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -851,6 +716,7 @@ static int do_data_output (struct nand_device *nand)
|
|||||||
|
|
||||||
struct nand_flash_controller imx31_nand_flash_controller = {
|
struct nand_flash_controller imx31_nand_flash_controller = {
|
||||||
.name = "imx31",
|
.name = "imx31",
|
||||||
|
.usage = "nand device imx31 target noecc|hwecc",
|
||||||
.nand_device_command = &imx31_nand_device_command,
|
.nand_device_command = &imx31_nand_device_command,
|
||||||
.init = &imx31_init,
|
.init = &imx31_init,
|
||||||
.reset = &imx31_reset,
|
.reset = &imx31_reset,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2009 by Alexei Babich *
|
* Copyright (C) 2009 by Alexei Babich *
|
||||||
* Rezonans plc., Chelyabinsk, Russia *
|
* Rezonans plc., Chelyabinsk, Russia *
|
||||||
@@ -86,20 +85,17 @@
|
|||||||
#define MX3_GPR 0x43fac008
|
#define MX3_GPR 0x43fac008
|
||||||
#define MX3_PCSR 0x53f8000c
|
#define MX3_PCSR 0x53f8000c
|
||||||
|
|
||||||
enum mx_dataout_type
|
enum mx_dataout_type {
|
||||||
{
|
|
||||||
MX3_NF_DATAOUT_PAGE = 1,
|
MX3_NF_DATAOUT_PAGE = 1,
|
||||||
MX3_NF_DATAOUT_NANDID = 2,
|
MX3_NF_DATAOUT_NANDID = 2,
|
||||||
MX3_NF_DATAOUT_NANDSTATUS = 4,
|
MX3_NF_DATAOUT_NANDSTATUS = 4,
|
||||||
};
|
};
|
||||||
enum mx_nf_finalize_action
|
enum mx_nf_finalize_action {
|
||||||
{
|
|
||||||
MX3_NF_FIN_NONE,
|
MX3_NF_FIN_NONE,
|
||||||
MX3_NF_FIN_DATAOUT,
|
MX3_NF_FIN_DATAOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mx3_nf_flags
|
struct mx3_nf_flags {
|
||||||
{
|
|
||||||
unsigned host_little_endian:1;
|
unsigned host_little_endian:1;
|
||||||
unsigned target_little_endian:1;
|
unsigned target_little_endian:1;
|
||||||
unsigned nand_readonly:1;
|
unsigned nand_readonly:1;
|
||||||
@@ -107,8 +103,7 @@ struct mx3_nf_flags
|
|||||||
unsigned hw_ecc_enabled:1;
|
unsigned hw_ecc_enabled:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mx3_nf_controller
|
struct mx3_nf_controller {
|
||||||
{
|
|
||||||
enum mx_dataout_type optype;
|
enum mx_dataout_type optype;
|
||||||
enum mx_nf_finalize_action fin;
|
enum mx_nf_finalize_action fin;
|
||||||
struct mx3_nf_flags flags;
|
struct mx3_nf_flags flags;
|
||||||
|
|||||||
971
src/flash/nand/mxc.c
Normal file
971
src/flash/nand/mxc.c
Normal file
@@ -0,0 +1,971 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2009 by Alexei Babich *
|
||||||
|
* Rezonans plc., Chelyabinsk, Russia *
|
||||||
|
* impatt@mail.ru *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2010 by Gaetan CARLIER *
|
||||||
|
* Trump s.a., Belgium *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2011 by Erik Ahlen *
|
||||||
|
* Avalon Innovation, Sweden *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Freescale iMX OpenOCD NAND Flash controller support.
|
||||||
|
* based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @mxc
|
||||||
|
* tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #",
|
||||||
|
* "nand write # file 0", "nand verify"
|
||||||
|
*
|
||||||
|
* get_next_halfword_from_sram_buffer() not tested
|
||||||
|
* !! all function only tested with 2k page nand device; mxc_write_page
|
||||||
|
* writes the 4 MAIN_BUFFER's and is not compatible with < 2k page
|
||||||
|
* !! oob must be be used due to NFS bug
|
||||||
|
* !! oob must be 64 bytes per 2KiB page
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include "mxc.h"
|
||||||
|
#include <target/target.h>
|
||||||
|
|
||||||
|
#define OOB_SIZE 64
|
||||||
|
|
||||||
|
#define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \
|
||||||
|
mxc_nf_info->mxc_version == MXC_VERSION_MX31)
|
||||||
|
#define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX25 || \
|
||||||
|
mxc_nf_info->mxc_version == MXC_VERSION_MX35)
|
||||||
|
|
||||||
|
/* This permits to print (in LOG_INFO) how much bytes
|
||||||
|
* has been written after a page read or write.
|
||||||
|
* This is useful when OpenOCD is used with a graphical
|
||||||
|
* front-end to estimate progression of the global read/write
|
||||||
|
*/
|
||||||
|
#undef _MXC_PRINT_STAT
|
||||||
|
/* #define _MXC_PRINT_STAT */
|
||||||
|
|
||||||
|
static const char target_not_halted_err_msg[] =
|
||||||
|
"target must be halted to use mxc NAND flash controller";
|
||||||
|
static const char data_block_size_err_msg[] =
|
||||||
|
"minimal granularity is one half-word, %" PRId32 " is incorrect";
|
||||||
|
static const char sram_buffer_bounds_err_msg[] =
|
||||||
|
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
|
||||||
|
static const char get_status_register_err_msg[] = "can't get NAND status";
|
||||||
|
static uint32_t in_sram_address;
|
||||||
|
static unsigned char sign_of_sequental_byte_read;
|
||||||
|
|
||||||
|
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr);
|
||||||
|
static int initialize_nf_controller(struct nand_device *nand);
|
||||||
|
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value);
|
||||||
|
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value);
|
||||||
|
static int poll_for_complete_op(struct nand_device *nand, const char *text);
|
||||||
|
static int validate_target_state(struct nand_device *nand);
|
||||||
|
static int do_data_output(struct nand_device *nand);
|
||||||
|
|
||||||
|
static int mxc_command(struct nand_device *nand, uint8_t command);
|
||||||
|
static int mxc_address(struct nand_device *nand, uint8_t address);
|
||||||
|
|
||||||
|
NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info;
|
||||||
|
int hwecc_needed;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
mxc_nf_info = malloc(sizeof(struct mxc_nf_controller));
|
||||||
|
if (mxc_nf_info == NULL) {
|
||||||
|
LOG_ERROR("no memory for nand controller");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
nand->controller_priv = mxc_nf_info;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 4) {
|
||||||
|
LOG_ERROR("use \"nand device mxc target mx25|mx27|mx31|mx35 noecc|hwecc [biswap]\"");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check board type
|
||||||
|
*/
|
||||||
|
if (strcmp(CMD_ARGV[2], "mx25") == 0) {
|
||||||
|
mxc_nf_info->mxc_version = MXC_VERSION_MX25;
|
||||||
|
mxc_nf_info->mxc_base_addr = 0xBB000000;
|
||||||
|
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
|
||||||
|
} else if (strcmp(CMD_ARGV[2], "mx27") == 0) {
|
||||||
|
mxc_nf_info->mxc_version = MXC_VERSION_MX27;
|
||||||
|
mxc_nf_info->mxc_base_addr = 0xD8000000;
|
||||||
|
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
|
||||||
|
} else if (strcmp(CMD_ARGV[2], "mx31") == 0) {
|
||||||
|
mxc_nf_info->mxc_version = MXC_VERSION_MX31;
|
||||||
|
mxc_nf_info->mxc_base_addr = 0xB8000000;
|
||||||
|
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
|
||||||
|
} else if (strcmp(CMD_ARGV[2], "mx35") == 0) {
|
||||||
|
mxc_nf_info->mxc_version = MXC_VERSION_MX35;
|
||||||
|
mxc_nf_info->mxc_base_addr = 0xBB000000;
|
||||||
|
mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check hwecc requirements
|
||||||
|
*/
|
||||||
|
hwecc_needed = strcmp(CMD_ARGV[3], "hwecc");
|
||||||
|
if (hwecc_needed == 0)
|
||||||
|
mxc_nf_info->flags.hw_ecc_enabled = 1;
|
||||||
|
else
|
||||||
|
mxc_nf_info->flags.hw_ecc_enabled = 0;
|
||||||
|
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_NONE;
|
||||||
|
mxc_nf_info->flags.target_little_endian =
|
||||||
|
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* should factory bad block indicator be swaped
|
||||||
|
* as a workaround for how the nfc handles pages.
|
||||||
|
*/
|
||||||
|
if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) {
|
||||||
|
LOG_DEBUG("BI-swap enabled");
|
||||||
|
mxc_nf_info->flags.biswap_enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* testing host endianness
|
||||||
|
*/
|
||||||
|
x = 1;
|
||||||
|
if (*(char *) &x == 1)
|
||||||
|
mxc_nf_info->flags.host_little_endian = 1;
|
||||||
|
else
|
||||||
|
mxc_nf_info->flags.host_little_endian = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(handle_mxc_biswap_command)
|
||||||
|
{
|
||||||
|
struct nand_device *nand = NULL;
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = NULL;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 1 || CMD_ARGC > 2)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD_CTX, "invalid nand device number or name: %s", CMD_ARGV[0]);
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
mxc_nf_info = nand->controller_priv;
|
||||||
|
if (CMD_ARGC == 2) {
|
||||||
|
if (strcmp(CMD_ARGV[1], "enable") == 0)
|
||||||
|
mxc_nf_info->flags.biswap_enabled = true;
|
||||||
|
else
|
||||||
|
mxc_nf_info->flags.biswap_enabled = false;
|
||||||
|
}
|
||||||
|
if (mxc_nf_info->flags.biswap_enabled)
|
||||||
|
command_print(CMD_CTX, "BI-swapping enabled on %s", nand->name);
|
||||||
|
else
|
||||||
|
command_print(CMD_CTX, "BI-swapping disabled on %s", nand->name);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct command_registration mxc_sub_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "biswap",
|
||||||
|
.handler = handle_mxc_biswap_command,
|
||||||
|
.help = "Turns on/off bad block information swaping from main area, "
|
||||||
|
"without parameter query status.",
|
||||||
|
.usage = "bank_id ['enable'|'disable']",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration mxc_nand_command_handler[] = {
|
||||||
|
{
|
||||||
|
.name = "mxc",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "MXC NAND flash controller commands",
|
||||||
|
.chain = mxc_sub_command_handlers
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mxc_init(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
int validate_target_result;
|
||||||
|
uint16_t buffsize_register_content;
|
||||||
|
uint32_t sreg_content;
|
||||||
|
uint32_t SREG = MX2_FMCR;
|
||||||
|
uint32_t SEL_16BIT = MX2_FMCR_NF_16BIT_SEL;
|
||||||
|
uint32_t SEL_FMS = MX2_FMCR_NF_FMS;
|
||||||
|
int retval;
|
||||||
|
uint16_t nand_status_content;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
if (nfc_is_v1()) {
|
||||||
|
target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content);
|
||||||
|
mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
|
||||||
|
} else
|
||||||
|
mxc_nf_info->flags.one_kb_sram = 0;
|
||||||
|
|
||||||
|
if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) {
|
||||||
|
SREG = MX3_PCSR;
|
||||||
|
SEL_16BIT = MX3_PCSR_NF_16BIT_SEL;
|
||||||
|
SEL_FMS = MX3_PCSR_NF_FMS;
|
||||||
|
} else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) {
|
||||||
|
SREG = MX25_RCSR;
|
||||||
|
SEL_16BIT = MX25_RCSR_NF_16BIT_SEL;
|
||||||
|
SEL_FMS = MX25_RCSR_NF_FMS;
|
||||||
|
} else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) {
|
||||||
|
SREG = MX35_RCSR;
|
||||||
|
SEL_16BIT = MX35_RCSR_NF_16BIT_SEL;
|
||||||
|
SEL_FMS = MX35_RCSR_NF_FMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_read_u32(target, SREG, &sreg_content);
|
||||||
|
if (!nand->bus_width) {
|
||||||
|
/* bus_width not yet defined. Read it from MXC_FMCR */
|
||||||
|
nand->bus_width = (sreg_content & SEL_16BIT) ? 16 : 8;
|
||||||
|
} else {
|
||||||
|
/* bus_width forced in soft. Sync it to MXC_FMCR */
|
||||||
|
sreg_content |= ((nand->bus_width == 16) ? SEL_16BIT : 0x00000000);
|
||||||
|
target_write_u32(target, SREG, sreg_content);
|
||||||
|
}
|
||||||
|
if (nand->bus_width == 16)
|
||||||
|
LOG_DEBUG("MXC_NF : bus is 16-bit width");
|
||||||
|
else
|
||||||
|
LOG_DEBUG("MXC_NF : bus is 8-bit width");
|
||||||
|
|
||||||
|
if (!nand->page_size)
|
||||||
|
nand->page_size = (sreg_content & SEL_FMS) ? 2048 : 512;
|
||||||
|
else {
|
||||||
|
sreg_content |= ((nand->page_size == 2048) ? SEL_FMS : 0x00000000);
|
||||||
|
target_write_u32(target, SREG, sreg_content);
|
||||||
|
}
|
||||||
|
if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
|
||||||
|
LOG_ERROR("NAND controller have only 1 kb SRAM, so "
|
||||||
|
"pagesize 2048 is incompatible with it");
|
||||||
|
} else
|
||||||
|
LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048");
|
||||||
|
|
||||||
|
if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K)
|
||||||
|
LOG_ERROR("MXC driver does not have support for 4k pagesize.");
|
||||||
|
|
||||||
|
initialize_nf_controller(nand);
|
||||||
|
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= mxc_command(nand, NAND_CMD_STATUS);
|
||||||
|
retval |= mxc_address(nand, 0x00);
|
||||||
|
retval |= do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR(get_status_register_err_msg);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
|
if (!(nand_status_content & 0x0080)) {
|
||||||
|
LOG_INFO("NAND read-only");
|
||||||
|
mxc_nf_info->flags.nand_readonly = 1;
|
||||||
|
} else
|
||||||
|
mxc_nf_info->flags.nand_readonly = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_read_data(struct nand_device *nand, void *data)
|
||||||
|
{
|
||||||
|
int validate_target_result;
|
||||||
|
int try_data_output_from_nand_chip;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get data from nand chip
|
||||||
|
*/
|
||||||
|
try_data_output_from_nand_chip = do_data_output(nand);
|
||||||
|
if (try_data_output_from_nand_chip != ERROR_OK) {
|
||||||
|
LOG_ERROR("mxc_read_data : read data failed : '%x'",
|
||||||
|
try_data_output_from_nand_chip);
|
||||||
|
return try_data_output_from_nand_chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand->bus_width == 16)
|
||||||
|
get_next_halfword_from_sram_buffer(nand, data);
|
||||||
|
else
|
||||||
|
get_next_byte_from_sram_buffer(nand, data);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_write_data(struct nand_device *nand, uint16_t data)
|
||||||
|
{
|
||||||
|
LOG_ERROR("write_data() not implemented");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_reset(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
int validate_target_result;
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
initialize_nf_controller(nand);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_command(struct nand_device *nand, uint8_t command)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
int poll_result;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case NAND_CMD_READOOB:
|
||||||
|
command = NAND_CMD_READ0;
|
||||||
|
/* set read point for data_read() and read_block_data() to
|
||||||
|
* spare area in SRAM buffer
|
||||||
|
*/
|
||||||
|
if (nfc_is_v1())
|
||||||
|
in_sram_address = MXC_NF_V1_SPARE_BUFFER0;
|
||||||
|
else
|
||||||
|
in_sram_address = MXC_NF_V2_SPARE_BUFFER0;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_READ1:
|
||||||
|
command = NAND_CMD_READ0;
|
||||||
|
/*
|
||||||
|
* offset == one half of page size
|
||||||
|
*/
|
||||||
|
in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
in_sram_address = MXC_NF_MAIN_BUFFER0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_write_u16(target, MXC_NF_FCMD, command);
|
||||||
|
/*
|
||||||
|
* start command input operation (set MXC_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FCI);
|
||||||
|
poll_result = poll_for_complete_op(nand, "command");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
/*
|
||||||
|
* reset cursor to begin of the buffer
|
||||||
|
*/
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
/* Handle special read command and adjust NF_CFG2(FDO) */
|
||||||
|
switch (command) {
|
||||||
|
case NAND_CMD_READID:
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID;
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_STATUS:
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
|
||||||
|
target_write_u16 (target, MXC_NF_BUFADDR, 0);
|
||||||
|
in_sram_address = 0;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_READ0:
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ohter command use the default 'One page data out' FDO */
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_address(struct nand_device *nand, uint8_t address)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
int poll_result;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
target_write_u16(target, MXC_NF_FADDR, address);
|
||||||
|
/*
|
||||||
|
* start address input operation (set MXC_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FAI);
|
||||||
|
poll_result = poll_for_complete_op(nand, "address");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_nand_ready(struct nand_device *nand, int tout)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint16_t poll_complete_status;
|
||||||
|
int validate_target_result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
do {
|
||||||
|
target_read_u16(target, MXC_NF_CFG2, &poll_complete_status);
|
||||||
|
if (poll_complete_status & MXC_NF_BIT_OP_DONE)
|
||||||
|
return tout;
|
||||||
|
|
||||||
|
alive_sleep(1);
|
||||||
|
} while (tout-- > 0);
|
||||||
|
return tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_write_page(struct nand_device *nand, uint32_t page,
|
||||||
|
uint8_t *data, uint32_t data_size,
|
||||||
|
uint8_t *oob, uint32_t oob_size)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int retval;
|
||||||
|
uint16_t nand_status_content;
|
||||||
|
uint16_t swap1, swap2, new_swap1;
|
||||||
|
uint8_t bufs;
|
||||||
|
int poll_result;
|
||||||
|
|
||||||
|
if (data_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (oob_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (!data) {
|
||||||
|
LOG_ERROR("nothing to program");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
retval = validate_target_state(nand);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
in_sram_address = MXC_NF_MAIN_BUFFER0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= mxc_command(nand, NAND_CMD_SEQIN);
|
||||||
|
retval |= mxc_address(nand, 0); /* col */
|
||||||
|
retval |= mxc_address(nand, 0); /* col */
|
||||||
|
retval |= mxc_address(nand, page & 0xff); /* page address */
|
||||||
|
retval |= mxc_address(nand, (page >> 8) & 0xff);/* page address */
|
||||||
|
retval |= mxc_address(nand, (page >> 16) & 0xff); /* page address */
|
||||||
|
|
||||||
|
target_write_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
|
||||||
|
if (oob) {
|
||||||
|
if (mxc_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
/*
|
||||||
|
* part of spare block will be overrided by hardware
|
||||||
|
* ECC generator
|
||||||
|
*/
|
||||||
|
LOG_DEBUG("part of spare block will be overrided "
|
||||||
|
"by hardware ECC generator");
|
||||||
|
}
|
||||||
|
if (nfc_is_v1())
|
||||||
|
target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
|
||||||
|
else {
|
||||||
|
uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
|
||||||
|
while (oob_size > 0) {
|
||||||
|
uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
|
||||||
|
target_write_buffer(target, addr, len, oob);
|
||||||
|
addr = align_address_v2(nand, addr + len);
|
||||||
|
oob += len;
|
||||||
|
oob_size -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
|
||||||
|
/* BI-swap - work-around of i.MX NFC for NAND device with page == 2kb*/
|
||||||
|
target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
|
||||||
|
if (oob) {
|
||||||
|
LOG_ERROR("Due to NFC Bug, oob is not correctly implemented in mxc driver");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
swap2 = 0xffff; /* Spare buffer unused forced to 0xffff */
|
||||||
|
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
||||||
|
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
||||||
|
target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
|
||||||
|
if (nfc_is_v1())
|
||||||
|
target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3, swap2);
|
||||||
|
else
|
||||||
|
target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* start data input operation (set MXC_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
if (nfc_is_v1() && nand->page_size > 512)
|
||||||
|
bufs = 4;
|
||||||
|
else
|
||||||
|
bufs = 1;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < bufs; ++i) {
|
||||||
|
target_write_u16(target, MXC_NF_BUFADDR, i);
|
||||||
|
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
|
||||||
|
poll_result = poll_for_complete_op(nand, "data input");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval |= mxc_command(nand, NAND_CMD_PAGEPROG);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check status register
|
||||||
|
*/
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= mxc_command(nand, NAND_CMD_STATUS);
|
||||||
|
target_write_u16 (target, MXC_NF_BUFADDR, 0);
|
||||||
|
mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
|
||||||
|
retval |= do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR(get_status_register_err_msg);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
|
if (nand_status_content & 0x0001) {
|
||||||
|
/*
|
||||||
|
* page not correctly written
|
||||||
|
*/
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
#ifdef _MXC_PRINT_STAT
|
||||||
|
LOG_INFO("%d bytes newly written", data_size);
|
||||||
|
#endif
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc_read_page(struct nand_device *nand, uint32_t page,
|
||||||
|
uint8_t *data, uint32_t data_size,
|
||||||
|
uint8_t *oob, uint32_t oob_size)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int retval;
|
||||||
|
uint8_t bufs;
|
||||||
|
uint16_t swap1, swap2, new_swap1;
|
||||||
|
|
||||||
|
if (data_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (oob_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
retval = validate_target_state(nand);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
/* Reset address_cycles before mxc_command ?? */
|
||||||
|
retval = mxc_command(nand, NAND_CMD_READ0);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_address(nand, 0); /* col */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_address(nand, 0); /* col */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_address(nand, page & 0xff);/* page address */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_address(nand, (page >> 8) & 0xff); /* page address */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_address(nand, (page >> 16) & 0xff);/* page address */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = mxc_command(nand, NAND_CMD_READSTART);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (nfc_is_v1() && nand->page_size > 512)
|
||||||
|
bufs = 4;
|
||||||
|
else
|
||||||
|
bufs = 1;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < bufs; ++i) {
|
||||||
|
target_write_u16(target, MXC_NF_BUFADDR, i);
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
|
||||||
|
retval = do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("MXC_NF : Error reading page %d", i);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
|
||||||
|
uint32_t SPARE_BUFFER3;
|
||||||
|
/* BI-swap - work-around of mxc NFC for NAND device with page == 2k */
|
||||||
|
target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
|
||||||
|
if (nfc_is_v1())
|
||||||
|
SPARE_BUFFER3 = MXC_NF_V1_SPARE_BUFFER3;
|
||||||
|
else
|
||||||
|
SPARE_BUFFER3 = MXC_NF_V2_SPARE_BUFFER3;
|
||||||
|
target_read_u16(target, SPARE_BUFFER3, &swap2);
|
||||||
|
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
||||||
|
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
||||||
|
target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
|
||||||
|
target_write_u16(target, SPARE_BUFFER3, swap2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
|
||||||
|
if (oob) {
|
||||||
|
if (nfc_is_v1())
|
||||||
|
target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
|
||||||
|
else {
|
||||||
|
uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
|
||||||
|
while (oob_size > 0) {
|
||||||
|
uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
|
||||||
|
target_read_buffer(target, addr, len, oob);
|
||||||
|
addr = align_address_v2(nand, addr + len);
|
||||||
|
oob += len;
|
||||||
|
oob_size -= len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MXC_PRINT_STAT
|
||||||
|
if (data_size > 0) {
|
||||||
|
/* When Operation Status is read (when page is erased),
|
||||||
|
* this function is used but data_size is null.
|
||||||
|
*/
|
||||||
|
LOG_INFO("%d bytes newly read", data_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
uint32_t ret = addr;
|
||||||
|
if (addr > MXC_NF_V2_SPARE_BUFFER0 &&
|
||||||
|
(addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN)
|
||||||
|
ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN;
|
||||||
|
else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size))
|
||||||
|
ret = MXC_NF_V2_SPARE_BUFFER0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int initialize_nf_controller(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint16_t work_mode = 0;
|
||||||
|
uint16_t temp;
|
||||||
|
/*
|
||||||
|
* resets NAND flash controller in zero time ? I dont know.
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN);
|
||||||
|
if (mxc_nf_info->mxc_version == MXC_VERSION_MX27)
|
||||||
|
work_mode = MXC_NF_BIT_INT_DIS; /* disable interrupt */
|
||||||
|
|
||||||
|
if (target->endianness == TARGET_BIG_ENDIAN) {
|
||||||
|
LOG_DEBUG("MXC_NF : work in Big Endian mode");
|
||||||
|
work_mode |= MXC_NF_BIT_BE_EN;
|
||||||
|
} else
|
||||||
|
LOG_DEBUG("MXC_NF : work in Little Endian mode");
|
||||||
|
if (mxc_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
LOG_DEBUG("MXC_NF : work with ECC mode");
|
||||||
|
work_mode |= MXC_NF_BIT_ECC_EN;
|
||||||
|
} else
|
||||||
|
LOG_DEBUG("MXC_NF : work without ECC mode");
|
||||||
|
if (nfc_is_v2()) {
|
||||||
|
target_write_u16(target, MXC_NF_V2_SPAS, OOB_SIZE / 2);
|
||||||
|
if (nand->page_size) {
|
||||||
|
uint16_t pages_per_block = nand->erase_size / nand->page_size;
|
||||||
|
work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6);
|
||||||
|
}
|
||||||
|
work_mode |= MXC_NF_BIT_ECC_4BIT;
|
||||||
|
}
|
||||||
|
target_write_u16(target, MXC_NF_CFG1, work_mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_BUFCFG, 2);
|
||||||
|
target_read_u16(target, MXC_NF_FWP, &temp);
|
||||||
|
if ((temp & 0x0007) == 1) {
|
||||||
|
LOG_ERROR("NAND flash is tight-locked, reset needed");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unlock NAND flash for write
|
||||||
|
*/
|
||||||
|
if (nfc_is_v1()) {
|
||||||
|
target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000);
|
||||||
|
target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF);
|
||||||
|
} else {
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF);
|
||||||
|
target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF);
|
||||||
|
}
|
||||||
|
target_write_u16(target, MXC_NF_FWP, 4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0x0000 means that first SRAM buffer @base_addr will be used
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_BUFADDR, 0x0000);
|
||||||
|
/*
|
||||||
|
* address of SRAM buffer
|
||||||
|
*/
|
||||||
|
in_sram_address = MXC_NF_MAIN_BUFFER0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
static uint8_t even_byte;
|
||||||
|
uint16_t temp;
|
||||||
|
/*
|
||||||
|
* host-big_endian ??
|
||||||
|
*/
|
||||||
|
if (sign_of_sequental_byte_read == 0)
|
||||||
|
even_byte = 0;
|
||||||
|
|
||||||
|
if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
|
||||||
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
|
*value = 0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
even_byte = 0;
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
} else {
|
||||||
|
if (nfc_is_v2())
|
||||||
|
in_sram_address = align_address_v2(nand, in_sram_address);
|
||||||
|
|
||||||
|
target_read_u16(target, in_sram_address, &temp);
|
||||||
|
if (even_byte) {
|
||||||
|
*value = temp >> 8;
|
||||||
|
even_byte = 0;
|
||||||
|
in_sram_address += 2;
|
||||||
|
} else {
|
||||||
|
*value = temp & 0xff;
|
||||||
|
even_byte = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sign_of_sequental_byte_read = 1;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
|
||||||
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
|
*value = 0;
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
} else {
|
||||||
|
if (nfc_is_v2())
|
||||||
|
in_sram_address = align_address_v2(nand, in_sram_address);
|
||||||
|
|
||||||
|
target_read_u16(target, in_sram_address, value);
|
||||||
|
in_sram_address += 2;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int poll_for_complete_op(struct nand_device *nand, const char *text)
|
||||||
|
{
|
||||||
|
if (mxc_nand_ready(nand, 1000) == -1) {
|
||||||
|
LOG_ERROR("%s sending timeout", text);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int validate_target_state(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR(target_not_halted_err_msg);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mxc_nf_info->flags.target_little_endian !=
|
||||||
|
(target->endianness == TARGET_LITTLE_ENDIAN)) {
|
||||||
|
/*
|
||||||
|
* endianness changed after NAND controller probed
|
||||||
|
*/
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecc_status_v1(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint16_t ecc_status;
|
||||||
|
|
||||||
|
target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
|
||||||
|
switch (ecc_status & 0x000c) {
|
||||||
|
case 1 << 2:
|
||||||
|
LOG_INFO("main area read with 1 (correctable) error");
|
||||||
|
break;
|
||||||
|
case 2 << 2:
|
||||||
|
LOG_INFO("main area read with more than 1 (incorrectable) error");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (ecc_status & 0x0003) {
|
||||||
|
case 1:
|
||||||
|
LOG_INFO("spare area read with 1 (correctable) error");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
LOG_INFO("main area read with more than 1 (incorrectable) error");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecc_status_v2(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint16_t ecc_status;
|
||||||
|
uint8_t no_subpages;
|
||||||
|
uint8_t err;
|
||||||
|
|
||||||
|
no_subpages = nand->page_size >> 9;
|
||||||
|
|
||||||
|
target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
|
||||||
|
do {
|
||||||
|
err = ecc_status & 0xF;
|
||||||
|
if (err > 4) {
|
||||||
|
LOG_INFO("UnCorrectable RS-ECC Error");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
} else if (err > 0)
|
||||||
|
LOG_INFO("%d Symbol Correctable RS-ECC Error", err);
|
||||||
|
ecc_status >>= 4;
|
||||||
|
} while (--no_subpages);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_data_output(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int poll_result;
|
||||||
|
switch (mxc_nf_info->fin) {
|
||||||
|
case MXC_NF_FIN_DATAOUT:
|
||||||
|
/*
|
||||||
|
* start data output operation (set MXC_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype));
|
||||||
|
poll_result = poll_for_complete_op(nand, "data output");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
mxc_nf_info->fin = MXC_NF_FIN_NONE;
|
||||||
|
/*
|
||||||
|
* ECC stuff
|
||||||
|
*/
|
||||||
|
if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
int ecc_status;
|
||||||
|
if (nfc_is_v1())
|
||||||
|
ecc_status = ecc_status_v1(nand);
|
||||||
|
else
|
||||||
|
ecc_status = ecc_status_v2(nand);
|
||||||
|
if (ecc_status != ERROR_OK)
|
||||||
|
return ecc_status;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MXC_NF_FIN_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nand_flash_controller mxc_nand_flash_controller = {
|
||||||
|
.name = "mxc",
|
||||||
|
.nand_device_command = &mxc_nand_device_command,
|
||||||
|
.commands = mxc_nand_command_handler,
|
||||||
|
.init = &mxc_init,
|
||||||
|
.reset = &mxc_reset,
|
||||||
|
.command = &mxc_command,
|
||||||
|
.address = &mxc_address,
|
||||||
|
.write_data = &mxc_write_data,
|
||||||
|
.read_data = &mxc_read_data,
|
||||||
|
.write_page = &mxc_write_page,
|
||||||
|
.read_page = &mxc_read_page,
|
||||||
|
.nand_ready = &mxc_nand_ready,
|
||||||
|
};
|
||||||
167
src/flash/nand/mxc.h
Normal file
167
src/flash/nand/mxc.h
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2009 by Alexei Babich *
|
||||||
|
* Rezonans plc., Chelyabinsk, Russia *
|
||||||
|
* impatt@mail.ru *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2011 by Erik Ahlen *
|
||||||
|
* Avalon Innovation, Sweden *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Freescale iMX OpenOCD NAND Flash controller support.
|
||||||
|
* based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support.
|
||||||
|
*
|
||||||
|
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MXC_NF_BUFSIZ (mxc_nf_info->mxc_regs_addr + 0x00)
|
||||||
|
#define MXC_NF_BUFADDR (mxc_nf_info->mxc_regs_addr + 0x04)
|
||||||
|
#define MXC_NF_FADDR (mxc_nf_info->mxc_regs_addr + 0x06)
|
||||||
|
#define MXC_NF_FCMD (mxc_nf_info->mxc_regs_addr + 0x08)
|
||||||
|
#define MXC_NF_BUFCFG (mxc_nf_info->mxc_regs_addr + 0x0a)
|
||||||
|
#define MXC_NF_ECCSTATUS (mxc_nf_info->mxc_regs_addr + 0x0c)
|
||||||
|
#define MXC_NF_ECCMAINPOS (mxc_nf_info->mxc_regs_addr + 0x0e)
|
||||||
|
#define MXC_NF_V1_ECCSPAREPOS (mxc_nf_info->mxc_regs_addr + 0x10)
|
||||||
|
#define MXC_NF_V2_SPAS (mxc_nf_info->mxc_regs_addr + 0x10)
|
||||||
|
#define MXC_NF_FWP (mxc_nf_info->mxc_regs_addr + 0x12)
|
||||||
|
#define MXC_NF_V1_UNLOCKSTART (mxc_nf_info->mxc_regs_addr + 0x14)
|
||||||
|
#define MXC_NF_V1_UNLOCKEND (mxc_nf_info->mxc_regs_addr + 0x16)
|
||||||
|
#define MXC_NF_V2_UNLOCKSTART0 (mxc_nf_info->mxc_regs_addr + 0x20)
|
||||||
|
#define MXC_NF_V2_UNLOCKSTART1 (mxc_nf_info->mxc_regs_addr + 0x24)
|
||||||
|
#define MXC_NF_V2_UNLOCKSTART2 (mxc_nf_info->mxc_regs_addr + 0x28)
|
||||||
|
#define MXC_NF_V2_UNLOCKSTART3 (mxc_nf_info->mxc_regs_addr + 0x2c)
|
||||||
|
#define MXC_NF_V2_UNLOCKEND0 (mxc_nf_info->mxc_regs_addr + 0x22)
|
||||||
|
#define MXC_NF_V2_UNLOCKEND1 (mxc_nf_info->mxc_regs_addr + 0x26)
|
||||||
|
#define MXC_NF_V2_UNLOCKEND2 (mxc_nf_info->mxc_regs_addr + 0x2a)
|
||||||
|
#define MXC_NF_V2_UNLOCKEND3 (mxc_nf_info->mxc_regs_addr + 0x2e)
|
||||||
|
#define MXC_NF_FWPSTATUS (mxc_nf_info->mxc_regs_addr + 0x18)
|
||||||
|
/*
|
||||||
|
* all bits not marked as self-clearing bit
|
||||||
|
*/
|
||||||
|
#define MXC_NF_CFG1 (mxc_nf_info->mxc_regs_addr + 0x1a)
|
||||||
|
#define MXC_NF_CFG2 (mxc_nf_info->mxc_regs_addr + 0x1c)
|
||||||
|
|
||||||
|
#define MXC_NF_MAIN_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0000)
|
||||||
|
#define MXC_NF_MAIN_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0200)
|
||||||
|
#define MXC_NF_MAIN_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0400)
|
||||||
|
#define MXC_NF_MAIN_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0600)
|
||||||
|
#define MXC_NF_V1_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0800)
|
||||||
|
#define MXC_NF_V1_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0810)
|
||||||
|
#define MXC_NF_V1_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0820)
|
||||||
|
#define MXC_NF_V1_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0830)
|
||||||
|
#define MXC_NF_V2_MAIN_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x0800)
|
||||||
|
#define MXC_NF_V2_MAIN_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x0a00)
|
||||||
|
#define MXC_NF_V2_MAIN_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x0c00)
|
||||||
|
#define MXC_NF_V2_MAIN_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x0e00)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x1000)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x1040)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x1080)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x10c0)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x1100)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x1140)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x1180)
|
||||||
|
#define MXC_NF_V2_SPARE_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x11c0)
|
||||||
|
#define MXC_NF_MAIN_BUFFER_LEN 512
|
||||||
|
#define MXC_NF_SPARE_BUFFER_LEN 16
|
||||||
|
#define MXC_NF_SPARE_BUFFER_MAX 64
|
||||||
|
#define MXC_NF_V1_LAST_BUFFADDR ((MXC_NF_V1_SPARE_BUFFER3) + \
|
||||||
|
MXC_NF_SPARE_BUFFER_LEN - 2)
|
||||||
|
#define MXC_NF_V2_LAST_BUFFADDR ((MXC_NF_V2_SPARE_BUFFER7) + \
|
||||||
|
MXC_NF_SPARE_BUFFER_LEN - 2)
|
||||||
|
|
||||||
|
/* bits in MXC_NF_CFG1 register */
|
||||||
|
#define MXC_NF_BIT_ECC_4BIT (1<<0)
|
||||||
|
#define MXC_NF_BIT_SPARE_ONLY_EN (1<<2)
|
||||||
|
#define MXC_NF_BIT_ECC_EN (1<<3)
|
||||||
|
#define MXC_NF_BIT_INT_DIS (1<<4)
|
||||||
|
#define MXC_NF_BIT_BE_EN (1<<5)
|
||||||
|
#define MXC_NF_BIT_RESET_EN (1<<6)
|
||||||
|
#define MXC_NF_BIT_FORCE_CE (1<<7)
|
||||||
|
#define MXC_NF_V2_CFG1_PPB(x) (((x) & 0x3) << 9)
|
||||||
|
|
||||||
|
/* bits in MXC_NF_CFG2 register */
|
||||||
|
|
||||||
|
/*Flash Command Input*/
|
||||||
|
#define MXC_NF_BIT_OP_FCI (1<<0)
|
||||||
|
/*
|
||||||
|
* Flash Address Input
|
||||||
|
*/
|
||||||
|
#define MXC_NF_BIT_OP_FAI (1<<1)
|
||||||
|
/*
|
||||||
|
* Flash Data Input
|
||||||
|
*/
|
||||||
|
#define MXC_NF_BIT_OP_FDI (1<<2)
|
||||||
|
|
||||||
|
/* see "enum mx_dataout_type" below */
|
||||||
|
#define MXC_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
||||||
|
#define MXC_NF_BIT_OP_DONE (1<<15)
|
||||||
|
|
||||||
|
#define MXC_CCM_CGR2 0x53f80028
|
||||||
|
#define MXC_GPR 0x43fac008
|
||||||
|
#define MX2_FMCR 0x10027814
|
||||||
|
#define MX2_FMCR_NF_16BIT_SEL (1<<4)
|
||||||
|
#define MX2_FMCR_NF_FMS (1<<5)
|
||||||
|
#define MX25_RCSR 0x53f80018
|
||||||
|
#define MX25_RCSR_NF_16BIT_SEL (1<<14)
|
||||||
|
#define MX25_RCSR_NF_FMS (1<<8)
|
||||||
|
#define MX25_RCSR_NF_4K (1<<9)
|
||||||
|
#define MX3_PCSR 0x53f8000c
|
||||||
|
#define MX3_PCSR_NF_16BIT_SEL (1<<31)
|
||||||
|
#define MX3_PCSR_NF_FMS (1<<30)
|
||||||
|
#define MX35_RCSR 0x53f80018
|
||||||
|
#define MX35_RCSR_NF_16BIT_SEL (1<<14)
|
||||||
|
#define MX35_RCSR_NF_FMS (1<<8)
|
||||||
|
#define MX35_RCSR_NF_4K (1<<9)
|
||||||
|
|
||||||
|
enum mxc_version {
|
||||||
|
MXC_VERSION_UKWN = 0,
|
||||||
|
MXC_VERSION_MX25 = 1,
|
||||||
|
MXC_VERSION_MX27 = 2,
|
||||||
|
MXC_VERSION_MX31 = 3,
|
||||||
|
MXC_VERSION_MX35 = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mxc_dataout_type {
|
||||||
|
MXC_NF_DATAOUT_PAGE = 1,
|
||||||
|
MXC_NF_DATAOUT_NANDID = 2,
|
||||||
|
MXC_NF_DATAOUT_NANDSTATUS = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mxc_nf_finalize_action {
|
||||||
|
MXC_NF_FIN_NONE,
|
||||||
|
MXC_NF_FIN_DATAOUT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mxc_nf_flags {
|
||||||
|
unsigned host_little_endian:1;
|
||||||
|
unsigned target_little_endian:1;
|
||||||
|
unsigned nand_readonly:1;
|
||||||
|
unsigned one_kb_sram:1;
|
||||||
|
unsigned hw_ecc_enabled:1;
|
||||||
|
unsigned biswap_enabled:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mxc_nf_controller {
|
||||||
|
enum mxc_version mxc_version;
|
||||||
|
uint32_t mxc_base_addr;
|
||||||
|
uint32_t mxc_regs_addr;
|
||||||
|
enum mxc_dataout_type optype;
|
||||||
|
enum mxc_nf_finalize_action fin;
|
||||||
|
struct mxc_nf_flags flags;
|
||||||
|
};
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "hello.h"
|
#include "hello.h"
|
||||||
|
|
||||||
|
|
||||||
static int nonce_nand_command(struct nand_device *nand, uint8_t command)
|
static int nonce_nand_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -62,8 +61,7 @@ static int nonce_nand_init(struct nand_device *nand)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nand_flash_controller nonce_nand_controller =
|
struct nand_flash_controller nonce_nand_controller = {
|
||||||
{
|
|
||||||
.name = "nonce",
|
.name = "nonce",
|
||||||
.commands = hello_command_handlers,
|
.commands = hello_command_handlers,
|
||||||
.nand_device_command = &nonce_nand_device_command,
|
.nand_device_command = &nonce_nand_device_command,
|
||||||
|
|||||||
@@ -31,8 +31,7 @@
|
|||||||
#include "arm_io.h"
|
#include "arm_io.h"
|
||||||
#include <target/arm.h>
|
#include <target/arm.h>
|
||||||
|
|
||||||
struct nuc910_nand_controller
|
struct nuc910_nand_controller {
|
||||||
{
|
|
||||||
struct arm_nand_data io;
|
struct arm_nand_data io;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,7 +52,8 @@ static int nuc910_nand_command(struct nand_device *nand, uint8_t command)
|
|||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
target_write_u8(target, NUC910_SMCMD, command);
|
target_write_u8(target, NUC910_SMCMD, command);
|
||||||
@@ -65,7 +65,8 @@ static int nuc910_nand_address(struct nand_device *nand, uint8_t address)
|
|||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
|
target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
|
||||||
@@ -77,7 +78,8 @@ static int nuc910_nand_read(struct nand_device *nand, void *data)
|
|||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
target_read_u8(target, NUC910_SMDATA, data);
|
target_read_u8(target, NUC910_SMDATA, data);
|
||||||
@@ -89,7 +91,8 @@ static int nuc910_nand_write(struct nand_device *nand, uint16_t data)
|
|||||||
struct target *target = nand->target;
|
struct target *target = nand->target;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
target_write_u8(target, NUC910_SMDATA, data);
|
target_write_u8(target, NUC910_SMDATA, data);
|
||||||
@@ -102,7 +105,8 @@ static int nuc910_nand_read_block_data(struct nand_device *nand,
|
|||||||
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
nuc910_nand->io.chunk_size = nand->page_size;
|
nuc910_nand->io.chunk_size = nand->page_size;
|
||||||
@@ -125,7 +129,8 @@ static int nuc910_nand_write_block_data(struct nand_device *nand,
|
|||||||
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
nuc910_nand->io.chunk_size = nand->page_size;
|
nuc910_nand->io.chunk_size = nand->page_size;
|
||||||
@@ -154,9 +159,8 @@ static int nuc910_nand_ready(struct nand_device *nand, int timeout)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
target_read_u32(target, NUC910_SMISR, &status);
|
target_read_u32(target, NUC910_SMISR, &status);
|
||||||
if (status & NUC910_SMISR_RB_) {
|
if (status & NUC910_SMISR_RB_)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
} while (timeout-- > 0);
|
} while (timeout-- > 0);
|
||||||
|
|
||||||
@@ -184,12 +188,12 @@ static int nuc910_nand_init(struct nand_device *nand)
|
|||||||
int bus_width = nand->bus_width ? : 8;
|
int bus_width = nand->bus_width ? : 8;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
result = validate_target_state(nand);
|
||||||
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* nuc910 only supports 8bit */
|
/* nuc910 only supports 8bit */
|
||||||
if (bus_width != 8)
|
if (bus_width != 8) {
|
||||||
{
|
|
||||||
LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
|
LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
|
||||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
@@ -210,8 +214,7 @@ static int nuc910_nand_init(struct nand_device *nand)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nand_flash_controller nuc910_nand_controller =
|
struct nand_flash_controller nuc910_nand_controller = {
|
||||||
{
|
|
||||||
.name = "nuc910",
|
.name = "nuc910",
|
||||||
.command = nuc910_nand_command,
|
.command = nuc910_nand_command,
|
||||||
.address = nuc910_nand_address,
|
.address = nuc910_nand_address,
|
||||||
|
|||||||
@@ -30,9 +30,7 @@
|
|||||||
#include "arm_io.h"
|
#include "arm_io.h"
|
||||||
#include <target/arm.h>
|
#include <target/arm.h>
|
||||||
|
|
||||||
|
struct orion_nand_controller {
|
||||||
struct orion_nand_controller
|
|
||||||
{
|
|
||||||
struct arm_nand_data io;
|
struct arm_nand_data io;
|
||||||
|
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
@@ -120,10 +118,8 @@ NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
|||||||
uint32_t base;
|
uint32_t base;
|
||||||
uint8_t ale, cle;
|
uint8_t ale, cle;
|
||||||
|
|
||||||
if (CMD_ARGC != 3) {
|
if (CMD_ARGC != 3)
|
||||||
LOG_ERROR("arguments must be: <target_id> <NAND_address>");
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
return ERROR_NAND_DEVICE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
hw = calloc(1, sizeof(*hw));
|
hw = calloc(1, sizeof(*hw));
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
@@ -153,9 +149,9 @@ static int orion_nand_init(struct nand_device *nand)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nand_flash_controller orion_nand_controller =
|
struct nand_flash_controller orion_nand_controller = {
|
||||||
{
|
|
||||||
.name = "orion",
|
.name = "orion",
|
||||||
|
.usage = "<target_id> <NAND_address>",
|
||||||
.command = orion_nand_command,
|
.command = orion_nand_command,
|
||||||
.address = orion_nand_address,
|
.address = orion_nand_address,
|
||||||
.read_data = orion_nand_read,
|
.read_data = orion_nand_read,
|
||||||
@@ -165,4 +161,3 @@ struct nand_flash_controller orion_nand_controller =
|
|||||||
.nand_device_command = orion_nand_device_command,
|
.nand_device_command = orion_nand_device_command,
|
||||||
.init = orion_nand_init,
|
.init = orion_nand_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include "s3c24xx.h"
|
#include "s3c24xx.h"
|
||||||
|
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *info;
|
struct s3c24xx_nand_controller *info;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include "s3c24xx.h"
|
#include "s3c24xx.h"
|
||||||
|
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *info;
|
struct s3c24xx_nand_controller *info;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include "s3c24xx.h"
|
#include "s3c24xx.h"
|
||||||
|
|
||||||
|
|
||||||
S3C24XX_DEVICE_COMMAND()
|
S3C24XX_DEVICE_COMMAND()
|
||||||
{
|
{
|
||||||
*info = NULL;
|
*info = NULL;
|
||||||
@@ -77,7 +76,6 @@ int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
|
|||||||
@@ -31,8 +31,7 @@
|
|||||||
#include "s3c24xx_regs.h"
|
#include "s3c24xx_regs.h"
|
||||||
#include <target/target.h>
|
#include <target/target.h>
|
||||||
|
|
||||||
struct s3c24xx_nand_controller
|
struct s3c24xx_nand_controller {
|
||||||
{
|
|
||||||
/* register addresses */
|
/* register addresses */
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
@@ -78,4 +77,4 @@ int s3c2440_read_block_data(struct nand_device *nand,
|
|||||||
int s3c2440_write_block_data(struct nand_device *nand,
|
int s3c2440_write_block_data(struct nand_device *nand,
|
||||||
uint8_t *data, int data_size);
|
uint8_t *data, int data_size);
|
||||||
|
|
||||||
#endif // S3C24xx_NAND_H
|
#endif /* S3C24xx_NAND_H */
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ASM_ARM_REGS_NAND
|
#ifndef __ASM_ARM_REGS_NAND
|
||||||
#define __ASM_ARM_REGS_NAND "$Id: nand.h,v 1.3 2003/12/09 11:36:29 ben Exp $"
|
#define __ASM_ARM_REGS_NAND
|
||||||
|
|
||||||
#define S3C2410_NFREG(x) (x)
|
#define S3C2410_NFREG(x) (x)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include <target/target.h>
|
#include <target/target.h>
|
||||||
|
|
||||||
// to be removed
|
/* to be removed */
|
||||||
extern struct nand_device *nand_devices;
|
extern struct nand_device *nand_devices;
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_list_command)
|
COMMAND_HANDLER(handle_nand_list_command)
|
||||||
@@ -37,14 +38,12 @@ COMMAND_HANDLER(handle_nand_list_command)
|
|||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!nand_devices)
|
if (!nand_devices) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "no NAND flash devices configured");
|
command_print(CMD_CTX, "no NAND flash devices configured");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = nand_devices, i = 0; p; p = p->next, i++)
|
for (p = nand_devices, i = 0; p; p = p->next, i++) {
|
||||||
{
|
|
||||||
if (p->device)
|
if (p->device)
|
||||||
command_print(CMD_CTX, "#%i: %s (%s) "
|
command_print(CMD_CTX, "#%i: %s (%s) "
|
||||||
"pagesize: %i, buswidth: %i,\n\t"
|
"pagesize: %i, buswidth: %i,\n\t"
|
||||||
@@ -89,8 +88,7 @@ COMMAND_HANDLER(handle_nand_info_command)
|
|||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (NULL == p->device)
|
if (NULL == p->device) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -101,11 +99,16 @@ COMMAND_HANDLER(handle_nand_info_command)
|
|||||||
if (last >= p->num_blocks)
|
if (last >= p->num_blocks)
|
||||||
last = p->num_blocks - 1;
|
last = p->num_blocks - 1;
|
||||||
|
|
||||||
command_print(CMD_CTX, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
|
command_print(CMD_CTX,
|
||||||
i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
|
"#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
|
||||||
|
i++,
|
||||||
|
p->device->name,
|
||||||
|
p->manufacturer->name,
|
||||||
|
p->page_size,
|
||||||
|
p->bus_width,
|
||||||
|
p->erase_size);
|
||||||
|
|
||||||
for (j = first; j <= last; j++)
|
for (j = first; j <= last; j++) {
|
||||||
{
|
|
||||||
char *erase_state, *bad_state;
|
char *erase_state, *bad_state;
|
||||||
|
|
||||||
if (p->blocks[j].is_erased == 0)
|
if (p->blocks[j].is_erased == 0)
|
||||||
@@ -137,17 +140,15 @@ COMMAND_HANDLER(handle_nand_info_command)
|
|||||||
COMMAND_HANDLER(handle_nand_probe_command)
|
COMMAND_HANDLER(handle_nand_probe_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC != 1)
|
if (CMD_ARGC != 1)
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if ((retval = nand_probe(p)) == ERROR_OK)
|
retval = nand_probe(p);
|
||||||
{
|
if (retval == ERROR_OK) {
|
||||||
command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
|
command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
|
||||||
p->device->name, p->manufacturer->name);
|
p->device->name, p->manufacturer->name);
|
||||||
}
|
}
|
||||||
@@ -158,11 +159,8 @@ COMMAND_HANDLER(handle_nand_probe_command)
|
|||||||
COMMAND_HANDLER(handle_nand_erase_command)
|
COMMAND_HANDLER(handle_nand_erase_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC != 1 && CMD_ARGC != 3)
|
if (CMD_ARGC != 1 && CMD_ARGC != 3)
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
@@ -177,12 +175,12 @@ COMMAND_HANDLER(handle_nand_erase_command)
|
|||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||||
if ((offset % p->erase_size) != 0 || offset >= size)
|
if ((offset % p->erase_size) != 0 || offset >= size)
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
||||||
if ((length == 0) || (length % p->erase_size) != 0
|
if ((length == 0) || (length % p->erase_size) != 0
|
||||||
|| (length + offset) > size)
|
|| (length + offset) > size)
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
offset /= p->erase_size;
|
offset /= p->erase_size;
|
||||||
length /= p->erase_size;
|
length /= p->erase_size;
|
||||||
@@ -192,11 +190,10 @@ COMMAND_HANDLER(handle_nand_erase_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
retval = nand_erase(p, offset, offset + length - 1);
|
retval = nand_erase(p, offset, offset + length - 1);
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "erased blocks %lu to %lu "
|
command_print(CMD_CTX, "erased blocks %lu to %lu "
|
||||||
"on NAND flash device #%s '%s'",
|
"on NAND flash device #%s '%s'",
|
||||||
offset, offset + length,
|
offset, offset + length - 1,
|
||||||
CMD_ARGV[0], p->device->name);
|
CMD_ARGV[0], p->device->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,29 +206,25 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
|||||||
int last = -1;
|
int last = -1;
|
||||||
|
|
||||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
|
if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (CMD_ARGC == 3)
|
if (CMD_ARGC == 3) {
|
||||||
{
|
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||||
if (offset % p->erase_size)
|
if (offset % p->erase_size)
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
offset /= p->erase_size;
|
offset /= p->erase_size;
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
||||||
if (length % p->erase_size)
|
if (length % p->erase_size)
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
length -= 1;
|
length -= 1;
|
||||||
length /= p->erase_size;
|
length /= p->erase_size;
|
||||||
@@ -241,8 +234,7 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
retval = nand_build_bbt(p, first, last);
|
retval = nand_build_bbt(p, first, last);
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
|
command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
|
||||||
"use \"nand info\" command to list blocks");
|
"use \"nand info\" command to list blocks");
|
||||||
}
|
}
|
||||||
@@ -260,11 +252,9 @@ COMMAND_HANDLER(handle_nand_write_command)
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
uint32_t total_bytes = s.size;
|
uint32_t total_bytes = s.size;
|
||||||
while (s.size > 0)
|
while (s.size > 0) {
|
||||||
{
|
|
||||||
int bytes_read = nand_fileio_read(nand, &s);
|
int bytes_read = nand_fileio_read(nand, &s);
|
||||||
if (bytes_read <= 0)
|
if (bytes_read <= 0) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "error while reading file");
|
command_print(CMD_CTX, "error while reading file");
|
||||||
return nand_fileio_cleanup(&s);
|
return nand_fileio_cleanup(&s);
|
||||||
}
|
}
|
||||||
@@ -272,8 +262,7 @@ COMMAND_HANDLER(handle_nand_write_command)
|
|||||||
|
|
||||||
retval = nand_write_page(nand, s.address / nand->page_size,
|
retval = nand_write_page(nand, s.address / nand->page_size,
|
||||||
s.page, s.page_size, s.oob, s.oob_size);
|
s.page, s.page_size, s.oob, s.oob_size);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "failed writing file %s "
|
command_print(CMD_CTX, "failed writing file %s "
|
||||||
"to NAND flash %s at offset 0x%8.8" PRIx32,
|
"to NAND flash %s at offset 0x%8.8" PRIx32,
|
||||||
CMD_ARGV[1], CMD_ARGV[0], s.address);
|
CMD_ARGV[1], CMD_ARGV[0], s.address);
|
||||||
@@ -282,8 +271,7 @@ COMMAND_HANDLER(handle_nand_write_command)
|
|||||||
s.address += s.page_size;
|
s.address += s.page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nand_fileio_finish(&s))
|
if (nand_fileio_finish(&s) == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
|
command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
|
||||||
"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||||
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
||||||
@@ -310,12 +298,10 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
while (file.size > 0)
|
while (file.size > 0) {
|
||||||
{
|
|
||||||
retval = nand_read_page(nand, dev.address / dev.page_size,
|
retval = nand_read_page(nand, dev.address / dev.page_size,
|
||||||
dev.page, dev.page_size, dev.oob, dev.oob_size);
|
dev.page, dev.page_size, dev.oob, dev.oob_size);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
nand_fileio_cleanup(&file);
|
nand_fileio_cleanup(&file);
|
||||||
@@ -323,8 +309,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bytes_read = nand_fileio_read(nand, &file);
|
int bytes_read = nand_fileio_read(nand, &file);
|
||||||
if (bytes_read <= 0)
|
if (bytes_read <= 0) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "error while reading file");
|
command_print(CMD_CTX, "error while reading file");
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
nand_fileio_cleanup(&file);
|
nand_fileio_cleanup(&file);
|
||||||
@@ -332,8 +317,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
|
if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
|
||||||
(dev.oob && memcmp(dev.oob, file.oob, dev.oob_size)) )
|
(dev.oob && memcmp(dev.oob, file.oob, dev.oob_size))) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "NAND flash contents differ "
|
command_print(CMD_CTX, "NAND flash contents differ "
|
||||||
"at 0x%8.8" PRIx32, dev.address);
|
"at 0x%8.8" PRIx32, dev.address);
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
@@ -345,8 +329,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
dev.address += nand->page_size;
|
dev.address += nand->page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nand_fileio_finish(&file) == ERROR_OK)
|
if (nand_fileio_finish(&file) == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "verified file %s in NAND flash %s "
|
command_print(CMD_CTX, "verified file %s in NAND flash %s "
|
||||||
"up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
"up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||||
CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
|
CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
|
||||||
@@ -366,13 +349,11 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
|||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
while (s.size > 0)
|
while (s.size > 0) {
|
||||||
{
|
|
||||||
size_t size_written;
|
size_t size_written;
|
||||||
retval = nand_read_page(nand, s.address / nand->page_size,
|
retval = nand_read_page(nand, s.address / nand->page_size,
|
||||||
s.page, s.page_size, s.oob, s.oob_size);
|
s.page, s.page_size, s.oob, s.oob_size);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||||
nand_fileio_cleanup(&s);
|
nand_fileio_cleanup(&s);
|
||||||
return retval;
|
return retval;
|
||||||
@@ -392,8 +373,7 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
|||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (nand_fileio_finish(&s) == ERROR_OK)
|
if (nand_fileio_finish(&s) == ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)",
|
command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)",
|
||||||
(long)filesize, duration_elapsed(&s.bench),
|
(long)filesize, duration_elapsed(&s.bench),
|
||||||
duration_kbps(&s.bench, filesize));
|
duration_kbps(&s.bench, filesize));
|
||||||
@@ -404,17 +384,14 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
|||||||
COMMAND_HANDLER(handle_nand_raw_access_command)
|
COMMAND_HANDLER(handle_nand_raw_access_command)
|
||||||
{
|
{
|
||||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
|
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (NULL == p->device)
|
if (NULL == p->device) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -510,9 +487,8 @@ COMMAND_HANDLER(handle_nand_init_command)
|
|||||||
if (CMD_ARGC != 0)
|
if (CMD_ARGC != 0)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
static bool nand_initialized = false;
|
static bool nand_initialized;
|
||||||
if (nand_initialized)
|
if (nand_initialized) {
|
||||||
{
|
|
||||||
LOG_INFO("'nand init' has already been called");
|
LOG_INFO("'nand init' has already been called");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -543,26 +519,21 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (CMD_ARGC < 2)
|
if (CMD_ARGC < 2)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_ERROR("missing target");
|
|
||||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
|
||||||
}
|
|
||||||
target = get_target(CMD_ARGV[1]);
|
target = get_target(CMD_ARGV[1]);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
||||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != controller->commands)
|
if (NULL != controller->commands) {
|
||||||
{
|
|
||||||
retval = register_commands(CMD_CTX, NULL,
|
retval = register_commands(CMD_CTX, NULL,
|
||||||
controller->commands);
|
controller->commands);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
c = malloc(sizeof(struct nand_device));
|
c = malloc(sizeof(struct nand_device));
|
||||||
if (c == NULL)
|
if (c == NULL) {
|
||||||
{
|
|
||||||
LOG_ERROR("End of memory");
|
LOG_ERROR("End of memory");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -580,13 +551,17 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||||||
c->next = NULL;
|
c->next = NULL;
|
||||||
|
|
||||||
retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval) {
|
||||||
{
|
LOG_ERROR("'%s' driver rejected nand flash. Usage: %s",
|
||||||
LOG_ERROR("'%s' driver rejected nand flash", controller->name);
|
controller->name,
|
||||||
|
controller->usage);
|
||||||
free(c);
|
free(c);
|
||||||
return ERROR_OK;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (controller->usage == NULL)
|
||||||
|
LOG_DEBUG("'%s' driver usage field missing", controller->name);
|
||||||
|
|
||||||
nand_device_add(c);
|
nand_device_add(c);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -595,20 +570,16 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||||||
COMMAND_HANDLER(handle_nand_device_command)
|
COMMAND_HANDLER(handle_nand_device_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC < 2)
|
if (CMD_ARGC < 2)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_ERROR("incomplete nand device configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save name and increment (for compatibility) with drivers
|
/* save name and increment (for compatibility) with drivers */
|
||||||
const char *bank_name = *CMD_ARGV++;
|
const char *bank_name = *CMD_ARGV++;
|
||||||
CMD_ARGC--;
|
CMD_ARGC--;
|
||||||
|
|
||||||
const char *driver_name = CMD_ARGV[0];
|
const char *driver_name = CMD_ARGV[0];
|
||||||
struct nand_flash_controller *controller;
|
struct nand_flash_controller *controller;
|
||||||
controller = nand_driver_find_by_name(CMD_ARGV[0]);
|
controller = nand_driver_find_by_name(CMD_ARGV[0]);
|
||||||
if (NULL == controller)
|
if (NULL == controller) {
|
||||||
{
|
|
||||||
LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
|
LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
|
||||||
return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
|
return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
|
||||||
}
|
}
|
||||||
@@ -628,20 +599,24 @@ static const struct command_registration nand_config_command_handlers[] = {
|
|||||||
.handler = &handle_nand_list_drivers,
|
.handler = &handle_nand_list_drivers,
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "lists available NAND drivers",
|
.help = "lists available NAND drivers",
|
||||||
|
.usage = ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "init",
|
.name = "init",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.handler = &handle_nand_init_command,
|
.handler = &handle_nand_init_command,
|
||||||
.help = "initialize NAND devices",
|
.help = "initialize NAND devices",
|
||||||
|
.usage = ""
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct command_registration nand_command_handlers[] = {
|
static const struct command_registration nand_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "nand",
|
.name = "nand",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "NAND flash command group",
|
.help = "NAND flash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = nand_config_command_handlers,
|
.chain = nand_config_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
@@ -651,5 +626,3 @@ int nand_register_commands(struct command_context *cmd_ctx)
|
|||||||
{
|
{
|
||||||
return register_commands(cmd_ctx, NULL, nand_command_handlers);
|
return register_commands(cmd_ctx, NULL, nand_command_handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,32 +9,35 @@ libocdflashnor_la_SOURCES = \
|
|||||||
|
|
||||||
NOR_DRIVERS = \
|
NOR_DRIVERS = \
|
||||||
aduc702x.c \
|
aduc702x.c \
|
||||||
|
at91sam4.c \
|
||||||
at91sam3.c \
|
at91sam3.c \
|
||||||
at91sam7.c \
|
at91sam7.c \
|
||||||
avrf.c \
|
avrf.c \
|
||||||
cfi.c \
|
cfi.c \
|
||||||
ecos.c \
|
efm32.c \
|
||||||
em357.c \
|
em357.c \
|
||||||
faux.c \
|
faux.c \
|
||||||
lpc2000.c \
|
lpc2000.c \
|
||||||
lpc288x.c \
|
lpc288x.c \
|
||||||
lpc2900.c \
|
lpc2900.c \
|
||||||
|
lpcspifi.c \
|
||||||
non_cfi.c \
|
non_cfi.c \
|
||||||
ocl.c \
|
ocl.c \
|
||||||
pic32mx.c \
|
pic32mx.c \
|
||||||
|
spi.c \
|
||||||
stmsmi.c \
|
stmsmi.c \
|
||||||
stellaris.c \
|
stellaris.c \
|
||||||
stm32f1x.c \
|
stm32f1x.c \
|
||||||
stm32f2x.c \
|
stm32f2x.c \
|
||||||
|
stm32lx.c \
|
||||||
str7x.c \
|
str7x.c \
|
||||||
str9x.c \
|
str9x.c \
|
||||||
str9xpec.c \
|
str9xpec.c \
|
||||||
tms470.c \
|
tms470.c \
|
||||||
virtual.c \
|
virtual.c \
|
||||||
fm3.c
|
fm3.c \
|
||||||
|
dsp5680xx_flash.c \
|
||||||
# Disabled for now, it generates warnings
|
kinetis.c
|
||||||
# dsp5680xx_flash.c
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
core.h \
|
core.h \
|
||||||
@@ -42,6 +45,7 @@ noinst_HEADERS = \
|
|||||||
driver.h \
|
driver.h \
|
||||||
imp.h \
|
imp.h \
|
||||||
non_cfi.h \
|
non_cfi.h \
|
||||||
ocl.h
|
ocl.h \
|
||||||
|
spi.h
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include <target/algorithm.h>
|
#include <target/algorithm.h>
|
||||||
#include <target/arm.h>
|
#include <target/arm.h>
|
||||||
|
|
||||||
|
|
||||||
static int aduc702x_build_sector_list(struct flash_bank *bank);
|
static int aduc702x_build_sector_list(struct flash_bank *bank);
|
||||||
static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms);
|
static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms);
|
||||||
static int aduc702x_set_write_enable(struct target *target, int enable);
|
static int aduc702x_set_write_enable(struct target *target, int enable);
|
||||||
@@ -44,21 +43,12 @@ static int aduc702x_set_write_enable(struct target *target, int enable);
|
|||||||
#define ADUC702x_FLASH_FEEPRO (6*4)
|
#define ADUC702x_FLASH_FEEPRO (6*4)
|
||||||
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
||||||
|
|
||||||
struct aduc702x_flash_bank {
|
|
||||||
struct working_area *write_algorithm;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* flash bank aduc702x 0 0 0 0 <target#>
|
/* flash bank aduc702x 0 0 0 0 <target#>
|
||||||
* The ADC7019-28 devices all have the same flash layout */
|
* The ADC7019-28 devices all have the same flash layout */
|
||||||
FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
||||||
{
|
{
|
||||||
struct aduc702x_flash_bank *nbank;
|
|
||||||
|
|
||||||
nbank = malloc(sizeof(struct aduc702x_flash_bank));
|
|
||||||
|
|
||||||
bank->base = 0x80000;
|
bank->base = 0x80000;
|
||||||
bank->size = 0xF800; // top 4k not accessible
|
bank->size = 0xF800; /* top 4k not accessible */
|
||||||
bank->driver_priv = nbank;
|
|
||||||
|
|
||||||
aduc702x_build_sector_list(bank);
|
aduc702x_build_sector_list(bank);
|
||||||
|
|
||||||
@@ -67,16 +57,15 @@ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
|||||||
|
|
||||||
static int aduc702x_build_sector_list(struct flash_bank *bank)
|
static int aduc702x_build_sector_list(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
//aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv;
|
/* aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv; */
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
|
|
||||||
// sector size is 512
|
/* sector size is 512 */
|
||||||
bank->num_sectors = bank->size / 512;
|
bank->num_sectors = bank->size / 512;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||||
for (i = 0; i < bank->num_sectors; ++i)
|
for (i = 0; i < bank->num_sectors; ++i) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 512;
|
bank->sectors[i].size = 512;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
@@ -95,10 +84,10 @@ static int aduc702x_protect_check(struct flash_bank *bank)
|
|||||||
|
|
||||||
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
||||||
{
|
{
|
||||||
//int res;
|
/* int res; */
|
||||||
int x;
|
int x;
|
||||||
int count;
|
int count;
|
||||||
//uint32_t v;
|
/* uint32_t v; */
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
|
|
||||||
aduc702x_set_write_enable(target, 1);
|
aduc702x_set_write_enable(target, 1);
|
||||||
@@ -110,8 +99,7 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
|
||||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
|
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
|
||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR("mass erase failed");
|
LOG_ERROR("mass erase failed");
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
@@ -123,15 +111,13 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
unsigned long adr;
|
unsigned long adr;
|
||||||
|
|
||||||
count = last - first + 1;
|
count = last - first + 1;
|
||||||
for (x = 0; x < count; ++x)
|
for (x = 0; x < count; ++x) {
|
||||||
{
|
|
||||||
adr = bank->base + ((first + x) * 512);
|
adr = bank->base + ((first + x) * 512);
|
||||||
|
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
|
||||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
|
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
|
||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
|
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||||
@@ -157,19 +143,21 @@ static int aduc702x_protect(struct flash_bank *bank, int set, int first, int las
|
|||||||
*
|
*
|
||||||
* Caller should not check for other return values specifically
|
* Caller should not check for other return values specifically
|
||||||
*/
|
*/
|
||||||
static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
static int aduc702x_write_block(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t count)
|
||||||
{
|
{
|
||||||
struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
|
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
uint32_t buffer_size = 7000;
|
uint32_t buffer_size = 7000;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
struct working_area *source;
|
struct working_area *source;
|
||||||
uint32_t address = bank->base + offset;
|
uint32_t address = bank->base + offset;
|
||||||
struct reg_param reg_params[6];
|
struct reg_param reg_params[6];
|
||||||
struct arm_algorithm armv4_5_info;
|
struct arm_algorithm arm_algo;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
if (((count%2)!=0)||((offset%2)!=0))
|
if (((count%2) != 0) || ((offset%2) != 0)) {
|
||||||
{
|
|
||||||
LOG_ERROR("write block must be multiple of two bytes in offset & length");
|
LOG_ERROR("write block must be multiple of two bytes in offset & length");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -189,61 +177,56 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
static const uint32_t aduc702x_flash_write_code[] = {
|
static const uint32_t aduc702x_flash_write_code[] = {
|
||||||
//<_start>:
|
/* <_start>: */
|
||||||
0xe3a05008, // mov r5, #8 ; 0x8
|
0xe3a05008, /* mov r5, #8 ; 0x8 */
|
||||||
0xe5845004, // str r5, [r4, #4]
|
0xe5845004, /* str r5, [r4, #4] */
|
||||||
0xe3a06002, // mov r6, #2 ; 0x2
|
0xe3a06002, /* mov r6, #2 ; 0x2 */
|
||||||
//<next>:
|
/* <next>: */
|
||||||
0xe1c421b0, // strh r2, [r4, #16]
|
0xe1c421b0, /* strh r2, [r4, #16] */
|
||||||
0xe0d050b2, // ldrh r5, [r0], #2
|
0xe0d050b2, /* ldrh r5, [r0], #2 */
|
||||||
0xe1c450bc, // strh r5, [r4, #12]
|
0xe1c450bc, /* strh r5, [r4, #12] */
|
||||||
0xe5c46008, // strb r6, [r4, #8]
|
0xe5c46008, /* strb r6, [r4, #8] */
|
||||||
//<wait_complete>:
|
/* <wait_complete>: */
|
||||||
0xe1d430b0, // ldrh r3, [r4]
|
0xe1d430b0, /* ldrh r3, [r4] */
|
||||||
0xe3130004, // tst r3, #4 ; 0x4
|
0xe3130004, /* tst r3, #4 ; 0x4 */
|
||||||
0x1afffffc, // bne 1001c <wait_complete>
|
0x1afffffc, /* bne 1001c <wait_complete> */
|
||||||
0xe2822002, // add r2, r2, #2 ; 0x2
|
0xe2822002, /* add r2, r2, #2 ; 0x2 */
|
||||||
0xe2511001, // subs r1, r1, #1 ; 0x1
|
0xe2511001, /* subs r1, r1, #1 ; 0x1 */
|
||||||
0x0a000001, // beq 1003c <done>
|
0x0a000001, /* beq 1003c <done> */
|
||||||
0xe3130001, // tst r3, #1 ; 0x1
|
0xe3130001, /* tst r3, #1 ; 0x1 */
|
||||||
0x1afffff3, // bne 1000c <next>
|
0x1afffff3, /* bne 1000c <next> */
|
||||||
//<done>:
|
/* <done>: */
|
||||||
0xeafffffe // b 1003c <done>
|
0xeafffffe /* b 1003c <done> */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* flash write code */
|
/* flash write code */
|
||||||
if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
|
if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
|
||||||
&aduc702x_info->write_algorithm) != ERROR_OK)
|
&write_algorithm) != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_WARNING("no working area available, can't do block memory writes");
|
LOG_WARNING("no working area available, can't do block memory writes");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
};
|
|
||||||
|
|
||||||
retval=target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
|
||||||
sizeof(aduc702x_flash_write_code), (uint8_t*)aduc702x_flash_write_code);
|
|
||||||
if (retval!=ERROR_OK)
|
|
||||||
{
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retval = target_write_buffer(target, write_algorithm->address,
|
||||||
|
sizeof(aduc702x_flash_write_code), (uint8_t *)aduc702x_flash_write_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
/* memory buffer */
|
/* memory buffer */
|
||||||
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
|
||||||
{
|
|
||||||
buffer_size /= 2;
|
buffer_size /= 2;
|
||||||
if (buffer_size <= 256)
|
if (buffer_size <= 256) {
|
||||||
{
|
/* we already allocated the writing code, but failed to get a buffer,
|
||||||
/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
|
*free the algorithm */
|
||||||
if (aduc702x_info->write_algorithm)
|
target_free_working_area(target, write_algorithm);
|
||||||
target_free_working_area(target, aduc702x_info->write_algorithm);
|
|
||||||
|
|
||||||
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
arm_algo.common_magic = ARM_COMMON_MAGIC;
|
||||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
arm_algo.core_mode = ARM_MODE_SVC;
|
||||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
arm_algo.core_state = ARM_STATE_ARM;
|
||||||
|
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||||
@@ -251,32 +234,29 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
init_reg_param(®_params[3], "r3", 32, PARAM_IN);
|
init_reg_param(®_params[3], "r3", 32, PARAM_IN);
|
||||||
init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
|
init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
|
||||||
|
|
||||||
while (count > 0)
|
while (count > 0) {
|
||||||
{
|
|
||||||
uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
|
uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
|
||||||
|
|
||||||
retval = target_write_buffer(target, source->address, thisrun_count, buffer);
|
retval = target_write_buffer(target, source->address, thisrun_count, buffer);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2);
|
buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2);
|
||||||
buf_set_u32(reg_params[2].value, 0, 32, address);
|
buf_set_u32(reg_params[2].value, 0, 32, address);
|
||||||
buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);
|
buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);
|
||||||
|
|
||||||
if ((retval = target_run_algorithm(target, 0, NULL, 5,
|
retval = target_run_algorithm(target, 0, NULL, 5,
|
||||||
reg_params, aduc702x_info->write_algorithm->address,
|
reg_params, write_algorithm->address,
|
||||||
aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
|
write_algorithm->address +
|
||||||
10000, &armv4_5_info)) != ERROR_OK)
|
sizeof(aduc702x_flash_write_code) - 4,
|
||||||
{
|
10000, &arm_algo);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("error executing aduc702x flash write algorithm");
|
LOG_ERROR("error executing aduc702x flash write algorithm");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1)
|
if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) {
|
||||||
{
|
|
||||||
/* FIX!!!! what does this mean??? replace w/sensible error message */
|
/* FIX!!!! what does this mean??? replace w/sensible error message */
|
||||||
LOG_ERROR("aduc702x detected error writing flash");
|
LOG_ERROR("aduc702x detected error writing flash");
|
||||||
retval = ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
@@ -289,7 +269,7 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
target_free_working_area(target, source);
|
target_free_working_area(target, source);
|
||||||
target_free_working_area(target, aduc702x_info->write_algorithm);
|
target_free_working_area(target, write_algorithm);
|
||||||
|
|
||||||
destroy_reg_param(®_params[0]);
|
destroy_reg_param(®_params[0]);
|
||||||
destroy_reg_param(®_params[1]);
|
destroy_reg_param(®_params[1]);
|
||||||
@@ -302,7 +282,10 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
|
|
||||||
/* All-JTAG, single-access method. Very slow. Used only if there is no
|
/* All-JTAG, single-access method. Very slow. Used only if there is no
|
||||||
* working area available. */
|
* working area available. */
|
||||||
static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
static int aduc702x_write_single(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer,
|
||||||
|
uint32_t offset,
|
||||||
|
uint32_t count)
|
||||||
{
|
{
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
@@ -311,26 +294,24 @@ static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint3
|
|||||||
aduc702x_set_write_enable(target, 1);
|
aduc702x_set_write_enable(target, 1);
|
||||||
|
|
||||||
for (x = 0; x < count; x += 2) {
|
for (x = 0; x < count; x += 2) {
|
||||||
// FEEADR = address
|
/* FEEADR = address */
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x);
|
||||||
|
|
||||||
// set up data
|
/* set up data */
|
||||||
if ((x + 1) == count)
|
if ((x + 1) == count) {
|
||||||
{
|
/* last byte */
|
||||||
// last byte
|
|
||||||
target_read_u8(target, offset + x + 1, &b);
|
target_read_u8(target, offset + x + 1, &b);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
b = buffer[x + 1];
|
b = buffer[x + 1];
|
||||||
|
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8));
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8));
|
||||||
|
|
||||||
// do single-write command
|
/* do single-write command */
|
||||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02);
|
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02);
|
||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) {
|
||||||
{
|
LOG_ERROR("single write failed for address 0x%08lX",
|
||||||
LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x));
|
(unsigned long)(offset + x));
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -348,16 +329,15 @@ static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* try using a block write */
|
/* try using a block write */
|
||||||
if ((retval = aduc702x_write_block(bank, buffer, offset, count)) != ERROR_OK)
|
retval = aduc702x_write_block(bank, buffer, offset, count);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
|
||||||
{
|
|
||||||
/* if block write failed (no sufficient working area),
|
/* if block write failed (no sufficient working area),
|
||||||
* use normal (slow) JTAG method */
|
* use normal (slow) JTAG method */
|
||||||
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
||||||
|
|
||||||
if ((retval = aduc702x_write_single(bank, buffer, offset, count)) != ERROR_OK)
|
retval = aduc702x_write_single(bank, buffer, offset, count);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
LOG_ERROR("slow write failed");
|
LOG_ERROR("slow write failed");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -382,7 +362,7 @@ static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
* enable = 1 enables writes & erases, 0 disables them */
|
* enable = 1 enables writes & erases, 0 disables them */
|
||||||
static int aduc702x_set_write_enable(struct target *target, int enable)
|
static int aduc702x_set_write_enable(struct target *target, int enable)
|
||||||
{
|
{
|
||||||
// don't bother to preserve int enable bit here
|
/* don't bother to preserve int enable bit here */
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -400,15 +380,20 @@ static int aduc702x_check_flash_completion(struct target* target, unsigned int t
|
|||||||
long long endtime = timeval_ms() + timeout_ms;
|
long long endtime = timeval_ms() + timeout_ms;
|
||||||
while (1) {
|
while (1) {
|
||||||
target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v);
|
target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v);
|
||||||
if ((v & 4) == 0) break;
|
if ((v & 4) == 0)
|
||||||
|
break;
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
if (timeval_ms() >= endtime) break;
|
if (timeval_ms() >= endtime)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v & 2) return ERROR_FAIL;
|
if (v & 2)
|
||||||
// if a command is ignored, both the success and fail bits may be 0
|
return ERROR_FAIL;
|
||||||
else if ((v & 3) == 0) return ERROR_FAIL;
|
/* if a command is ignored, both the success and fail bits may be 0 */
|
||||||
else return ERROR_OK;
|
else if ((v & 3) == 0)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
else
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct flash_driver aduc702x_flash = {
|
struct flash_driver aduc702x_flash = {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
2380
src/flash/nor/at91sam4.c
Normal file
2380
src/flash/nor/at91sam4.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,6 @@
|
|||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
|
|
||||||
|
|
||||||
/* AT91SAM7 control registers */
|
/* AT91SAM7 control registers */
|
||||||
#define DBGU_CIDR 0xFFFFF240
|
#define DBGU_CIDR 0xFFFFF240
|
||||||
#define CKGR_MCFR 0xFFFFFC24
|
#define CKGR_MCFR 0xFFFFFC24
|
||||||
@@ -98,9 +97,9 @@
|
|||||||
#define FLASH_SIZE_1024KB 12
|
#define FLASH_SIZE_1024KB 12
|
||||||
#define FLASH_SIZE_2048KB 14
|
#define FLASH_SIZE_2048KB 14
|
||||||
|
|
||||||
|
|
||||||
static int at91sam7_protect_check(struct flash_bank *bank);
|
static int at91sam7_protect_check(struct flash_bank *bank);
|
||||||
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
||||||
|
uint32_t count);
|
||||||
|
|
||||||
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
|
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
|
||||||
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
|
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
|
||||||
@@ -111,10 +110,11 @@ static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
|
|||||||
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
||||||
static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
||||||
|
|
||||||
static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
|
static char *EPROC[8] = {
|
||||||
|
"Unknown", "ARM946-E", "ARM7TDMI", "Unknown", "ARM920T", "ARM926EJ-S", "Unknown", "Unknown"
|
||||||
|
};
|
||||||
|
|
||||||
struct at91sam7_flash_bank
|
struct at91sam7_flash_bank {
|
||||||
{
|
|
||||||
/* chip id register */
|
/* chip id register */
|
||||||
uint32_t cidr;
|
uint32_t cidr;
|
||||||
uint16_t cidr_ext;
|
uint16_t cidr_ext;
|
||||||
@@ -178,7 +178,6 @@ static long SRAMSIZ[16] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
|
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
|
||||||
{
|
{
|
||||||
uint32_t fsr;
|
uint32_t fsr;
|
||||||
@@ -206,8 +205,7 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
|
|||||||
|
|
||||||
at91sam7_info->mck_valid = 0;
|
at91sam7_info->mck_valid = 0;
|
||||||
at91sam7_info->mck_freq = 0;
|
at91sam7_info->mck_freq = 0;
|
||||||
switch (mckr & PMC_MCKR_CSS)
|
switch (mckr & PMC_MCKR_CSS) {
|
||||||
{
|
|
||||||
case 0: /* Slow Clock */
|
case 0: /* Slow Clock */
|
||||||
at91sam7_info->mck_valid = 1;
|
at91sam7_info->mck_valid = 1;
|
||||||
tmp = RC_FREQ;
|
tmp = RC_FREQ;
|
||||||
@@ -215,13 +213,10 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
|
|||||||
|
|
||||||
case 1: /* Main Clock */
|
case 1: /* Main Clock */
|
||||||
if ((mcfr & CKGR_MCFR_MAINRDY) &&
|
if ((mcfr & CKGR_MCFR_MAINRDY) &&
|
||||||
(at91sam7_info->ext_freq == 0))
|
(at91sam7_info->ext_freq == 0)) {
|
||||||
{
|
|
||||||
at91sam7_info->mck_valid = 1;
|
at91sam7_info->mck_valid = 1;
|
||||||
tmp = RC_FREQ / 16ul * (mcfr & 0xffff);
|
tmp = RC_FREQ / 16ul * (mcfr & 0xffff);
|
||||||
}
|
} else if (at91sam7_info->ext_freq != 0) {
|
||||||
else if (at91sam7_info->ext_freq != 0)
|
|
||||||
{
|
|
||||||
at91sam7_info->mck_valid = 1;
|
at91sam7_info->mck_valid = 1;
|
||||||
tmp = at91sam7_info->ext_freq;
|
tmp = at91sam7_info->ext_freq;
|
||||||
}
|
}
|
||||||
@@ -232,8 +227,7 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
|
|||||||
|
|
||||||
case 3: /* PLL Clock */
|
case 3: /* PLL Clock */
|
||||||
if ((mcfr & CKGR_MCFR_MAINRDY) &&
|
if ((mcfr & CKGR_MCFR_MAINRDY) &&
|
||||||
(at91sam7_info->ext_freq == 0))
|
(at91sam7_info->ext_freq == 0)) {
|
||||||
{
|
|
||||||
target_read_u32(target, CKGR_PLLR, &pllr);
|
target_read_u32(target, CKGR_PLLR, &pllr);
|
||||||
if (!(pllr & CKGR_PLLR_DIV))
|
if (!(pllr & CKGR_PLLR_DIV))
|
||||||
break; /* 0 Hz */
|
break; /* 0 Hz */
|
||||||
@@ -243,10 +237,8 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
|
|||||||
* as long as PLL is properly configured. */
|
* as long as PLL is properly configured. */
|
||||||
tmp = mainfreq / (pllr & CKGR_PLLR_DIV)*
|
tmp = mainfreq / (pllr & CKGR_PLLR_DIV)*
|
||||||
(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
|
(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
|
||||||
}
|
} else if ((at91sam7_info->ext_freq != 0) &&
|
||||||
else if ((at91sam7_info->ext_freq != 0) &&
|
((pllr&CKGR_PLLR_DIV) != 0)) {
|
||||||
((pllr&CKGR_PLLR_DIV) != 0))
|
|
||||||
{
|
|
||||||
at91sam7_info->mck_valid = 1;
|
at91sam7_info->mck_valid = 1;
|
||||||
tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)*
|
tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)*
|
||||||
(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
|
(((pllr & CKGR_PLLR_MUL) >> 16) + 1);
|
||||||
@@ -255,12 +247,10 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Prescaler adjust */
|
/* Prescaler adjust */
|
||||||
if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0))
|
if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0)) {
|
||||||
{
|
|
||||||
at91sam7_info->mck_valid = 0;
|
at91sam7_info->mck_valid = 0;
|
||||||
at91sam7_info->mck_freq = 0;
|
at91sam7_info->mck_freq = 0;
|
||||||
}
|
} else if (((mckr & PMC_MCKR_PRES) >> 2) != 0)
|
||||||
else if (((mckr & PMC_MCKR_PRES) >> 2) != 0)
|
|
||||||
at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
|
at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2);
|
||||||
else
|
else
|
||||||
at91sam7_info->mck_freq = tmp;
|
at91sam7_info->mck_freq = tmp;
|
||||||
@@ -273,24 +263,17 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
|
|||||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
|
|
||||||
if (mode && (mode != at91sam7_info->flashmode))
|
if (mode && (mode != at91sam7_info->flashmode)) {
|
||||||
{
|
|
||||||
/* Always round up (ceil) */
|
/* Always round up (ceil) */
|
||||||
if (mode == FMR_TIMING_NVBITS)
|
if (mode == FMR_TIMING_NVBITS) {
|
||||||
{
|
if (at91sam7_info->cidr_arch == 0x60) {
|
||||||
if (at91sam7_info->cidr_arch == 0x60)
|
|
||||||
{
|
|
||||||
/* AT91SAM7A3 uses master clocks in 100 ns */
|
/* AT91SAM7A3 uses master clocks in 100 ns */
|
||||||
fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
|
fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* master clocks in 1uS for ARCH 0x7 types */
|
/* master clocks in 1uS for ARCH 0x7 types */
|
||||||
fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
|
fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
|
||||||
}
|
}
|
||||||
}
|
} else if (mode == FMR_TIMING_FLASH) {
|
||||||
else if (mode == FMR_TIMING_FLASH)
|
|
||||||
{
|
|
||||||
/* main clocks in 1.5uS */
|
/* main clocks in 1.5uS */
|
||||||
fmcn = (at91sam7_info->mck_freq/1000000ul)+
|
fmcn = (at91sam7_info->mck_freq/1000000ul)+
|
||||||
(at91sam7_info->mck_freq/2000000ul) + 1;
|
(at91sam7_info->mck_freq/2000000ul) + 1;
|
||||||
@@ -319,16 +302,15 @@ static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t wait
|
|||||||
{
|
{
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0))
|
while ((!((status = at91sam7_get_flash_status(bank->target,
|
||||||
{
|
bank->bank_number)) & waitbits)) && (timeout-- > 0)) {
|
||||||
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
|
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
|
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
|
||||||
|
|
||||||
if (status & 0x0C)
|
if (status & 0x0C) {
|
||||||
{
|
|
||||||
LOG_ERROR("status register: 0x%" PRIx32 "", status);
|
LOG_ERROR("status register: 0x%" PRIx32 "", status);
|
||||||
if (status & 0x4)
|
if (status & 0x4)
|
||||||
LOG_ERROR("Lock Error Bit Detected, Operation Abort");
|
LOG_ERROR("Lock Error Bit Detected, Operation Abort");
|
||||||
@@ -350,22 +332,20 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t
|
|||||||
|
|
||||||
fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
|
fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
|
||||||
target_write_u32(target, MC_FCR[bank->bank_number], fcr);
|
target_write_u32(target, MC_FCR[bank->bank_number], fcr);
|
||||||
LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen);
|
LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u",
|
||||||
|
fcr,
|
||||||
|
bank->bank_number + 1,
|
||||||
|
pagen);
|
||||||
|
|
||||||
if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB)))
|
if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB))) {
|
||||||
{
|
|
||||||
/* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
|
/* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
|
||||||
if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
|
if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C)
|
if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -373,9 +353,8 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t
|
|||||||
/* Read device id register, main clock frequency register and fill in driver info structure */
|
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||||
static int at91sam7_read_part_info(struct flash_bank *bank)
|
static int at91sam7_read_part_info(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct flash_bank *t_bank = bank;
|
|
||||||
struct at91sam7_flash_bank *at91sam7_info;
|
struct at91sam7_flash_bank *at91sam7_info;
|
||||||
struct target *target = t_bank->target;
|
struct target *target = bank->target;
|
||||||
|
|
||||||
uint16_t bnk, sec;
|
uint16_t bnk, sec;
|
||||||
uint16_t arch;
|
uint16_t arch;
|
||||||
@@ -390,16 +369,14 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
uint32_t base_address = 0;
|
uint32_t base_address = 0;
|
||||||
char *target_name_t = "Unknown";
|
char *target_name_t = "Unknown";
|
||||||
|
|
||||||
at91sam7_info = t_bank->driver_priv;
|
at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
if (at91sam7_info->cidr != 0)
|
if (at91sam7_info->cidr != 0) {
|
||||||
{
|
|
||||||
/* flash already configured, update clock and check for protected sectors */
|
/* flash already configured, update clock and check for protected sectors */
|
||||||
struct flash_bank *fb = bank;
|
struct flash_bank *fb = bank;
|
||||||
t_bank = fb;
|
struct flash_bank *t_bank = bank;
|
||||||
|
|
||||||
while (t_bank)
|
while (t_bank) {
|
||||||
{
|
|
||||||
/* re-calculate master clock frequency */
|
/* re-calculate master clock frequency */
|
||||||
at91sam7_read_clock_info(t_bank);
|
at91sam7_read_clock_info(t_bank);
|
||||||
|
|
||||||
@@ -418,19 +395,16 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
|
|
||||||
/* Read and parse chip identification register */
|
/* Read and parse chip identification register */
|
||||||
target_read_u32(target, DBGU_CIDR, &cidr);
|
target_read_u32(target, DBGU_CIDR, &cidr);
|
||||||
if (cidr == 0)
|
if (cidr == 0) {
|
||||||
{
|
|
||||||
LOG_WARNING("Cannot identify target as an AT91SAM");
|
LOG_WARNING("Cannot identify target as an AT91SAM");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (at91sam7_info->flash_autodetection == 0)
|
if (at91sam7_info->flash_autodetection == 0) {
|
||||||
{
|
|
||||||
/* banks and sectors are already created, based on data from input file */
|
/* banks and sectors are already created, based on data from input file */
|
||||||
struct flash_bank *fb = bank;
|
struct flash_bank *fb = bank;
|
||||||
t_bank = fb;
|
struct flash_bank *t_bank = bank;
|
||||||
while (t_bank)
|
while (t_bank) {
|
||||||
{
|
|
||||||
at91sam7_info = t_bank->driver_priv;
|
at91sam7_info = t_bank->driver_priv;
|
||||||
|
|
||||||
at91sam7_info->cidr = cidr;
|
at91sam7_info->cidr = cidr;
|
||||||
@@ -462,8 +436,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
arch = (cidr >> 20)&0x00FF;
|
arch = (cidr >> 20)&0x00FF;
|
||||||
|
|
||||||
/* check flash size */
|
/* check flash size */
|
||||||
switch ((cidr >> 8)&0x000F)
|
switch ((cidr >> 8)&0x000F) {
|
||||||
{
|
|
||||||
case FLASH_SIZE_8KB:
|
case FLASH_SIZE_8KB:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -473,8 +446,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 32;
|
pages_per_sector = 32;
|
||||||
page_size = 64;
|
page_size = 64;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S161/16";
|
target_name_t = "AT91SAM7S161/16";
|
||||||
}
|
}
|
||||||
@@ -486,13 +458,11 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 32;
|
pages_per_sector = 32;
|
||||||
page_size = 128;
|
page_size = 128;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S321/32";
|
target_name_t = "AT91SAM7S321/32";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7SE32";
|
target_name_t = "AT91SAM7SE32";
|
||||||
}
|
}
|
||||||
@@ -504,8 +474,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 32;
|
pages_per_sector = 32;
|
||||||
page_size = 128;
|
page_size = 128;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S64";
|
target_name_t = "AT91SAM7S64";
|
||||||
}
|
}
|
||||||
@@ -517,23 +486,19 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 64;
|
pages_per_sector = 64;
|
||||||
page_size = 256;
|
page_size = 256;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S128";
|
target_name_t = "AT91SAM7S128";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7XC128";
|
target_name_t = "AT91SAM7XC128";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7SE128";
|
target_name_t = "AT91SAM7SE128";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7X128";
|
target_name_t = "AT91SAM7X128";
|
||||||
}
|
}
|
||||||
@@ -545,28 +510,23 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 64;
|
pages_per_sector = 64;
|
||||||
page_size = 256;
|
page_size = 256;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x60)
|
if (arch == 0x60) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7A3";
|
target_name_t = "AT91SAM7A3";
|
||||||
}
|
}
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S256";
|
target_name_t = "AT91SAM7S256";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7XC256";
|
target_name_t = "AT91SAM7XC256";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7SE256";
|
target_name_t = "AT91SAM7SE256";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7X256";
|
target_name_t = "AT91SAM7X256";
|
||||||
}
|
}
|
||||||
@@ -578,23 +538,19 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
pages_per_sector = 64;
|
pages_per_sector = 64;
|
||||||
page_size = 256;
|
page_size = 256;
|
||||||
base_address = 0x00100000;
|
base_address = 0x00100000;
|
||||||
if (arch == 0x70)
|
if (arch == 0x70) {
|
||||||
{
|
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name_t = "AT91SAM7S512";
|
target_name_t = "AT91SAM7S512";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7XC512";
|
target_name_t = "AT91SAM7XC512";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7SE512";
|
target_name_t = "AT91SAM7SE512";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75) {
|
||||||
{
|
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name_t = "AT91SAM7X512";
|
target_name_t = "AT91SAM7X512";
|
||||||
}
|
}
|
||||||
@@ -607,9 +563,9 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_name_t, "Unknown") == 0)
|
if (strcmp(target_name_t, "Unknown") == 0) {
|
||||||
{
|
LOG_ERROR(
|
||||||
LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
|
"Target autodetection failed! Please specify target parameters in configuration file");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,20 +574,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
/* calculate bank size */
|
/* calculate bank size */
|
||||||
bank_size = sectors_num * pages_per_sector * page_size;
|
bank_size = sectors_num * pages_per_sector * page_size;
|
||||||
|
|
||||||
for (bnk = 0; bnk < banks_num; bnk++)
|
for (bnk = 0; bnk < banks_num; bnk++) {
|
||||||
{
|
struct flash_bank *t_bank = bank;
|
||||||
if (bnk > 0)
|
if (bnk > 0) {
|
||||||
{
|
if (!t_bank->next) {
|
||||||
/* create a new flash bank element */
|
/* create a new flash bank element */
|
||||||
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
||||||
fb->target = target;
|
fb->target = target;
|
||||||
fb->driver = bank->driver;
|
fb->driver = bank->driver;
|
||||||
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
||||||
|
fb->name = "sam7_probed";
|
||||||
fb->next = NULL;
|
fb->next = NULL;
|
||||||
|
|
||||||
/* link created bank in 'flash_banks' list and redirect t_bank */
|
/* link created bank in 'flash_banks' list */
|
||||||
t_bank->next = fb;
|
t_bank->next = fb;
|
||||||
t_bank = fb;
|
}
|
||||||
|
t_bank = t_bank->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bank->bank_number = bnk;
|
t_bank->bank_number = bnk;
|
||||||
@@ -643,8 +601,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
|
|
||||||
/* allocate sectors */
|
/* allocate sectors */
|
||||||
t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
|
t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
|
||||||
for (sec = 0; sec < sectors_num; sec++)
|
for (sec = 0; sec < sectors_num; sec++) {
|
||||||
{
|
|
||||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||||
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
||||||
t_bank->sectors[sec].is_erased = -1;
|
t_bank->sectors[sec].is_erased = -1;
|
||||||
@@ -681,7 +638,9 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
at91sam7_protect_check(t_bank);
|
at91sam7_protect_check(t_bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch);
|
LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x",
|
||||||
|
at91sam7_info->cidr_nvptyp,
|
||||||
|
at91sam7_info->cidr_arch);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -696,8 +655,7 @@ static int at91sam7_erase_check(struct flash_bank *bank)
|
|||||||
uint16_t nSector;
|
uint16_t nSector;
|
||||||
uint16_t nByte;
|
uint16_t nByte;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -707,12 +665,12 @@ static int at91sam7_erase_check(struct flash_bank *bank)
|
|||||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||||
|
|
||||||
fast_check = 1;
|
fast_check = 1;
|
||||||
for (nSector = 0; nSector < bank->num_sectors; nSector++)
|
for (nSector = 0; nSector < bank->num_sectors; nSector++) {
|
||||||
{
|
retval = target_blank_check_memory(target,
|
||||||
retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset,
|
bank->base + bank->sectors[nSector].offset,
|
||||||
bank->sectors[nSector].size, &blank);
|
bank->sectors[nSector].size,
|
||||||
if (retval != ERROR_OK)
|
&blank);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
fast_check = 0;
|
fast_check = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -723,25 +681,20 @@ static int at91sam7_erase_check(struct flash_bank *bank)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fast_check)
|
if (fast_check)
|
||||||
{
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
|
||||||
|
|
||||||
LOG_USER("Running slow fallback erase check - add working memory");
|
LOG_USER("Running slow fallback erase check - add working memory");
|
||||||
|
|
||||||
buffer = malloc(bank->sectors[0].size);
|
buffer = malloc(bank->sectors[0].size);
|
||||||
for (nSector = 0; nSector < bank->num_sectors; nSector++)
|
for (nSector = 0; nSector < bank->num_sectors; nSector++) {
|
||||||
{
|
|
||||||
bank->sectors[nSector].is_erased = 1;
|
bank->sectors[nSector].is_erased = 1;
|
||||||
retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
|
retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
|
||||||
bank->sectors[nSector].size/4, buffer);
|
bank->sectors[nSector].size/4, buffer);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++)
|
for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++) {
|
||||||
{
|
if (buffer[nByte] != 0xFF) {
|
||||||
if (buffer[nByte] != 0xFF)
|
|
||||||
{
|
|
||||||
bank->sectors[nSector].is_erased = 0;
|
bank->sectors[nSector].is_erased = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -760,11 +713,8 @@ static int at91sam7_protect_check(struct flash_bank *bank)
|
|||||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
if (bank->target->state != TARGET_HALTED)
|
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -773,14 +723,11 @@ static int at91sam7_protect_check(struct flash_bank *bank)
|
|||||||
at91sam7_info->lockbits = (status >> 16);
|
at91sam7_info->lockbits = (status >> 16);
|
||||||
|
|
||||||
at91sam7_info->num_lockbits_on = 0;
|
at91sam7_info->num_lockbits_on = 0;
|
||||||
for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++)
|
for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++) {
|
||||||
{
|
if (((status >> (16 + lock_pos))&(0x0001)) == 1) {
|
||||||
if (((status >> (16 + lock_pos))&(0x0001)) == 1)
|
|
||||||
{
|
|
||||||
at91sam7_info->num_lockbits_on++;
|
at91sam7_info->num_lockbits_on++;
|
||||||
bank->sectors[lock_pos].is_protected = 1;
|
bank->sectors[lock_pos].is_protected = 1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
bank->sectors[lock_pos].is_protected = 0;
|
bank->sectors[lock_pos].is_protected = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,13 +738,10 @@ static int at91sam7_protect_check(struct flash_bank *bank)
|
|||||||
at91sam7_info->nvmbits = (status >> 8)&0xFF;
|
at91sam7_info->nvmbits = (status >> 8)&0xFF;
|
||||||
|
|
||||||
at91sam7_info->num_nvmbits_on = 0;
|
at91sam7_info->num_nvmbits_on = 0;
|
||||||
for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++)
|
for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++) {
|
||||||
{
|
|
||||||
if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
|
if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
|
||||||
{
|
|
||||||
at91sam7_info->num_nvmbits_on++;
|
at91sam7_info->num_nvmbits_on++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -834,8 +778,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
at91sam7_info->ext_freq = 0;
|
at91sam7_info->ext_freq = 0;
|
||||||
at91sam7_info->flash_autodetection = 0;
|
at91sam7_info->flash_autodetection = 0;
|
||||||
|
|
||||||
if (CMD_ARGC < 13)
|
if (CMD_ARGC < 13) {
|
||||||
{
|
|
||||||
at91sam7_info->flash_autodetection = 1;
|
at91sam7_info->flash_autodetection = 1;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -859,8 +802,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
|
if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
|
||||||
(pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
|
(pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0)) {
|
||||||
{
|
|
||||||
at91sam7_info->flash_autodetection = 1;
|
at91sam7_info->flash_autodetection = 1;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -871,20 +813,21 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
/* calculate bank size */
|
/* calculate bank size */
|
||||||
bank_size = num_sectors * pages_per_sector * page_size;
|
bank_size = num_sectors * pages_per_sector * page_size;
|
||||||
|
|
||||||
for (bnk = 0; bnk < banks_num; bnk++)
|
for (bnk = 0; bnk < banks_num; bnk++) {
|
||||||
{
|
if (bnk > 0) {
|
||||||
if (bnk > 0)
|
if (!t_bank->next) {
|
||||||
{
|
|
||||||
/* create a new bank element */
|
/* create a new bank element */
|
||||||
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
||||||
fb->target = target;
|
fb->target = target;
|
||||||
fb->driver = bank->driver;
|
fb->driver = bank->driver;
|
||||||
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
||||||
|
fb->name = "sam7_probed";
|
||||||
fb->next = NULL;
|
fb->next = NULL;
|
||||||
|
|
||||||
/* link created bank in 'flash_banks' list and redirect t_bank */
|
/* link created bank in 'flash_banks' list */
|
||||||
t_bank->next = fb;
|
t_bank->next = fb;
|
||||||
t_bank = fb;
|
}
|
||||||
|
t_bank = t_bank->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_bank->bank_number = bnk;
|
t_bank->bank_number = bnk;
|
||||||
@@ -896,8 +839,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
|
|
||||||
/* allocate sectors */
|
/* allocate sectors */
|
||||||
t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
|
t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
|
||||||
for (sec = 0; sec < num_sectors; sec++)
|
for (sec = 0; sec < num_sectors; sec++) {
|
||||||
{
|
|
||||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||||
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
||||||
t_bank->sectors[sec].is_erased = -1;
|
t_bank->sectors[sec].is_erased = -1;
|
||||||
@@ -927,50 +869,36 @@ static int at91sam7_erase(struct flash_bank *bank, int first, int last)
|
|||||||
uint8_t erase_all;
|
uint8_t erase_all;
|
||||||
|
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
||||||
{
|
|
||||||
return ERROR_FLASH_SECTOR_INVALID;
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
}
|
|
||||||
|
|
||||||
erase_all = 0;
|
erase_all = 0;
|
||||||
if ((first == 0) && (last == (bank->num_sectors-1)))
|
if ((first == 0) && (last == (bank->num_sectors-1)))
|
||||||
{
|
|
||||||
erase_all = 1;
|
erase_all = 1;
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the flash controller timing */
|
/* Configure the flash controller timing */
|
||||||
at91sam7_read_clock_info(bank);
|
at91sam7_read_clock_info(bank);
|
||||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||||
|
|
||||||
if (erase_all)
|
if (erase_all) {
|
||||||
{
|
|
||||||
if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
|
if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* allocate and clean buffer */
|
/* allocate and clean buffer */
|
||||||
nbytes = (last - first + 1) * bank->sectors[first].size;
|
nbytes = (last - first + 1) * bank->sectors[first].size;
|
||||||
buffer = malloc(nbytes * sizeof(uint8_t));
|
buffer = malloc(nbytes * sizeof(uint8_t));
|
||||||
for (pos = 0; pos < nbytes; pos++)
|
for (pos = 0; pos < nbytes; pos++)
|
||||||
{
|
|
||||||
buffer[pos] = 0xFF;
|
buffer[pos] = 0xFF;
|
||||||
}
|
|
||||||
|
|
||||||
if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
|
if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK) {
|
||||||
{
|
free(buffer);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,9 +907,7 @@ static int at91sam7_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
/* mark erased sectors */
|
/* mark erased sectors */
|
||||||
for (sec = first; sec <= last; sec++)
|
for (sec = first; sec <= last; sec++)
|
||||||
{
|
|
||||||
bank->sectors[sec].is_erased = 1;
|
bank->sectors[sec].is_erased = 1;
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -995,27 +921,21 @@ static int at91sam7_protect(struct flash_bank *bank, int set, int first, int las
|
|||||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
||||||
{
|
|
||||||
return ERROR_FLASH_SECTOR_INVALID;
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the flash controller timing */
|
/* Configure the flash controller timing */
|
||||||
at91sam7_read_clock_info(bank);
|
at91sam7_read_clock_info(bank);
|
||||||
at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
|
at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
|
||||||
|
|
||||||
for (sector = first; sector <= last; sector++)
|
for (sector = first; sector <= last; sector++) {
|
||||||
{
|
|
||||||
if (set)
|
if (set)
|
||||||
cmd = SLB;
|
cmd = SLB;
|
||||||
else
|
else
|
||||||
@@ -1026,10 +946,8 @@ static int at91sam7_protect(struct flash_bank *bank, int set, int first, int las
|
|||||||
pagen = sector * at91sam7_info->pages_per_sector;
|
pagen = sector * at91sam7_info->pages_per_sector;
|
||||||
|
|
||||||
if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
|
if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
at91sam7_protect_check(bank);
|
at91sam7_protect_check(bank);
|
||||||
|
|
||||||
@@ -1045,12 +963,9 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
|||||||
uint32_t first_page, last_page, pagen, buffer_pos;
|
uint32_t first_page, last_page, pagen, buffer_pos;
|
||||||
|
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -1060,9 +975,10 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
|||||||
|
|
||||||
dst_min_alignment = at91sam7_info->pagesize;
|
dst_min_alignment = at91sam7_info->pagesize;
|
||||||
|
|
||||||
if (offset % dst_min_alignment)
|
if (offset % dst_min_alignment) {
|
||||||
{
|
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "",
|
||||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment);
|
offset,
|
||||||
|
dst_min_alignment);
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1072,14 +988,16 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
|||||||
first_page = offset/dst_min_alignment;
|
first_page = offset/dst_min_alignment;
|
||||||
last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
|
last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
|
||||||
|
|
||||||
LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
|
LOG_DEBUG("first_page: %i, last_page: %i, count %i",
|
||||||
|
(int)first_page,
|
||||||
|
(int)last_page,
|
||||||
|
(int)count);
|
||||||
|
|
||||||
/* Configure the flash controller timing */
|
/* Configure the flash controller timing */
|
||||||
at91sam7_read_clock_info(bank);
|
at91sam7_read_clock_info(bank);
|
||||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||||
|
|
||||||
for (pagen = first_page; pagen < last_page; pagen++)
|
for (pagen = first_page; pagen < last_page; pagen++) {
|
||||||
{
|
|
||||||
if (bytes_remaining < dst_min_alignment)
|
if (bytes_remaining < dst_min_alignment)
|
||||||
count = bytes_remaining;
|
count = bytes_remaining;
|
||||||
else
|
else
|
||||||
@@ -1089,16 +1007,14 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
|||||||
/* Write one block to the PageWriteBuffer */
|
/* Write one block to the PageWriteBuffer */
|
||||||
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
||||||
wcount = DIV_ROUND_UP(count, 4);
|
wcount = DIV_ROUND_UP(count, 4);
|
||||||
if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
|
retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4,
|
||||||
{
|
wcount, buffer + buffer_pos);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
/* Send Write Page command to Flash Controller */
|
/* Send Write Page command to Flash Controller */
|
||||||
if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
|
if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen);
|
LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,8 +1027,7 @@ static int at91sam7_probe(struct flash_bank *bank)
|
|||||||
* if this is an at91sam7, it has the configured flash */
|
* if this is an at91sam7, it has the configured flash */
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -1130,9 +1045,7 @@ static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||||
|
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
|
||||||
|
|
||||||
printed = snprintf(buf, buf_size,
|
printed = snprintf(buf, buf_size,
|
||||||
"\n at91sam7 driver information: Chip is %s\n",
|
"\n at91sam7 driver information: Chip is %s\n",
|
||||||
@@ -1143,7 +1056,8 @@ static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
|
|
||||||
printed = snprintf(buf,
|
printed = snprintf(buf,
|
||||||
buf_size,
|
buf_size,
|
||||||
" Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | Flashsize: 0x%8.8" PRIx32 "\n",
|
" Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | "
|
||||||
|
"Flashsize: 0x%8.8" PRIx32 "\n",
|
||||||
at91sam7_info->cidr,
|
at91sam7_info->cidr,
|
||||||
at91sam7_info->cidr_arch,
|
at91sam7_info->cidr_arch,
|
||||||
EPROC[at91sam7_info->cidr_eproc],
|
EPROC[at91sam7_info->cidr_eproc],
|
||||||
@@ -1155,27 +1069,29 @@ static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
|
|
||||||
printed = snprintf(buf, buf_size,
|
printed = snprintf(buf, buf_size,
|
||||||
" Master clock (estimated): %u KHz | External clock: %u KHz\n",
|
" Master clock (estimated): %u KHz | External clock: %u KHz\n",
|
||||||
(unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000));
|
(unsigned)(at91sam7_info->mck_freq / 1000),
|
||||||
|
(unsigned)(at91sam7_info->ext_freq / 1000));
|
||||||
|
|
||||||
buf += printed;
|
buf += printed;
|
||||||
buf_size -= printed;
|
buf_size -= printed;
|
||||||
|
|
||||||
printed = snprintf(buf, buf_size,
|
printed = snprintf(buf,
|
||||||
|
buf_size,
|
||||||
" Pagesize: %i bytes | Lockbits(%i): %i 0x%4.4x | Pages in lock region: %i\n",
|
" Pagesize: %i bytes | Lockbits(%i): %i 0x%4.4x | Pages in lock region: %i\n",
|
||||||
at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on,
|
at91sam7_info->pagesize,
|
||||||
at91sam7_info->lockbits, at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on);
|
bank->num_sectors,
|
||||||
|
at91sam7_info->num_lockbits_on,
|
||||||
|
at91sam7_info->lockbits,
|
||||||
|
at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on);
|
||||||
|
|
||||||
buf += printed;
|
buf += printed;
|
||||||
buf_size -= printed;
|
buf_size -= printed;
|
||||||
|
|
||||||
printed = snprintf(buf, buf_size,
|
snprintf(buf, buf_size,
|
||||||
" Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n",
|
" Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n",
|
||||||
at91sam7_info->securitybit, at91sam7_info->num_nvmbits,
|
at91sam7_info->securitybit, at91sam7_info->num_nvmbits,
|
||||||
at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits);
|
at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits);
|
||||||
|
|
||||||
buf += printed;
|
|
||||||
buf_size -= printed;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1199,54 +1115,40 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (CMD_ARGC != 2)
|
if (CMD_ARGC != 2)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
command_print(CMD_CTX, "at91sam7 gpnvm <bit> <set | clear>");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bank = get_flash_bank_by_num_noprobe(0);
|
bank = get_flash_bank_by_num_noprobe(0);
|
||||||
if (bank == NULL)
|
if (bank == NULL)
|
||||||
{
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
if (strcmp(bank->driver->name, "at91sam7")) {
|
||||||
if (strcmp(bank->driver->name, "at91sam7"))
|
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
|
command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("target has to be halted to perform flash operation");
|
LOG_ERROR("target has to be halted to perform flash operation");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(CMD_ARGV[1], "set") == 0)
|
if (strcmp(CMD_ARGV[1], "set") == 0)
|
||||||
{
|
|
||||||
flashcmd = SGPB;
|
flashcmd = SGPB;
|
||||||
}
|
|
||||||
else if (strcmp(CMD_ARGV[1], "clear") == 0)
|
else if (strcmp(CMD_ARGV[1], "clear") == 0)
|
||||||
{
|
|
||||||
flashcmd = CGPB;
|
flashcmd = CGPB;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
at91sam7_info = bank->driver_priv;
|
at91sam7_info = bank->driver_priv;
|
||||||
if (at91sam7_info->cidr == 0)
|
if (at91sam7_info->cidr == 0) {
|
||||||
{
|
|
||||||
retval = at91sam7_read_part_info(bank);
|
retval = at91sam7_read_part_info(bank);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
|
||||||
if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits))
|
if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits)) {
|
||||||
{
|
command_print(CMD_CTX,
|
||||||
command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name);
|
"gpnvm bit '#%s' is out of bounds for target %s",
|
||||||
|
CMD_ARGV[0],
|
||||||
|
at91sam7_info->target_name);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,13 +1157,14 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
|
|||||||
at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
|
at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
|
||||||
|
|
||||||
if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK)
|
if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
||||||
status = at91sam7_get_flash_status(bank->target, 0);
|
status = at91sam7_get_flash_status(bank->target, 0);
|
||||||
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32, flashcmd, bit, status);
|
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32,
|
||||||
|
flashcmd,
|
||||||
|
bit,
|
||||||
|
status);
|
||||||
|
|
||||||
/* check protect state */
|
/* check protect state */
|
||||||
at91sam7_protect_check(bank);
|
at91sam7_protect_check(bank);
|
||||||
@@ -1285,6 +1188,7 @@ static const struct command_registration at91sam7_command_handlers[] = {
|
|||||||
.name = "at91sam7",
|
.name = "at91sam7",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "at91sam7 flash command group",
|
.help = "at91sam7 flash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = at91sam7_exec_command_handlers,
|
.chain = at91sam7_exec_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
@@ -1292,6 +1196,7 @@ static const struct command_registration at91sam7_command_handlers[] = {
|
|||||||
|
|
||||||
struct flash_driver at91sam7_flash = {
|
struct flash_driver at91sam7_flash = {
|
||||||
.name = "at91sam7",
|
.name = "at91sam7",
|
||||||
|
.usage = "gpnvm <bit> <set | clear>",
|
||||||
.commands = at91sam7_command_handlers,
|
.commands = at91sam7_command_handlers,
|
||||||
.flash_bank_command = at91sam7_flash_bank_command,
|
.flash_bank_command = at91sam7_flash_bank_command,
|
||||||
.erase = at91sam7_erase,
|
.erase = at91sam7_erase,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -24,22 +25,21 @@
|
|||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include <target/avrt.h>
|
#include <target/avrt.h>
|
||||||
|
|
||||||
|
|
||||||
/* AVR_JTAG_Instructions */
|
/* AVR_JTAG_Instructions */
|
||||||
#define AVR_JTAG_INS_LEN 4
|
#define AVR_JTAG_INS_LEN 4
|
||||||
// Public Instructions:
|
/* Public Instructions: */
|
||||||
#define AVR_JTAG_INS_EXTEST 0x00
|
#define AVR_JTAG_INS_EXTEST 0x00
|
||||||
#define AVR_JTAG_INS_IDCODE 0x01
|
#define AVR_JTAG_INS_IDCODE 0x01
|
||||||
#define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02
|
#define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02
|
||||||
#define AVR_JTAG_INS_BYPASS 0x0F
|
#define AVR_JTAG_INS_BYPASS 0x0F
|
||||||
// AVR Specified Public Instructions:
|
/* AVR Specified Public Instructions: */
|
||||||
#define AVR_JTAG_INS_AVR_RESET 0x0C
|
#define AVR_JTAG_INS_AVR_RESET 0x0C
|
||||||
#define AVR_JTAG_INS_PROG_ENABLE 0x04
|
#define AVR_JTAG_INS_PROG_ENABLE 0x04
|
||||||
#define AVR_JTAG_INS_PROG_COMMANDS 0x05
|
#define AVR_JTAG_INS_PROG_COMMANDS 0x05
|
||||||
#define AVR_JTAG_INS_PROG_PAGELOAD 0x06
|
#define AVR_JTAG_INS_PROG_PAGELOAD 0x06
|
||||||
#define AVR_JTAG_INS_PROG_PAGEREAD 0x07
|
#define AVR_JTAG_INS_PROG_PAGEREAD 0x07
|
||||||
|
|
||||||
// Data Registers:
|
/* Data Registers: */
|
||||||
#define AVR_JTAG_REG_Bypass_Len 1
|
#define AVR_JTAG_REG_Bypass_Len 1
|
||||||
#define AVR_JTAG_REG_DeviceID_Len 32
|
#define AVR_JTAG_REG_DeviceID_Len 32
|
||||||
|
|
||||||
@@ -49,8 +49,7 @@
|
|||||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||||
|
|
||||||
struct avrf_type
|
struct avrf_type {
|
||||||
{
|
|
||||||
char name[15];
|
char name[15];
|
||||||
uint16_t chip_id;
|
uint16_t chip_id;
|
||||||
int flash_page_size;
|
int flash_page_size;
|
||||||
@@ -59,14 +58,12 @@ struct avrf_type
|
|||||||
int eeprom_page_num;
|
int eeprom_page_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct avrf_flash_bank
|
struct avrf_flash_bank {
|
||||||
{
|
|
||||||
int ppage_size;
|
int ppage_size;
|
||||||
int probed;
|
int probed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct avrf_type avft_chips_info[] =
|
static struct avrf_type avft_chips_info[] = {
|
||||||
{
|
|
||||||
/* name, chip_id, flash_page_size, flash_page_num,
|
/* name, chip_id, flash_page_size, flash_page_num,
|
||||||
* eeprom_page_size, eeprom_page_num
|
* eeprom_page_size, eeprom_page_num
|
||||||
*/
|
*/
|
||||||
@@ -127,43 +124,49 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
poll_value = 0;
|
poll_value = 0;
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
|
avr_jtag_senddat(avr->jtag_info.tap,
|
||||||
|
&poll_value,
|
||||||
|
0x3380,
|
||||||
|
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||||
if (ERROR_OK != mcu_execute_queue())
|
if (ERROR_OK != mcu_execute_queue())
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||||
} while (!(poll_value & 0x0200));
|
} while (!(poll_value & 0x0200));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
|
static int avr_jtagprg_writeflashpage(struct avr_common *avr,
|
||||||
|
uint8_t *page_buf,
|
||||||
|
uint32_t buf_size,
|
||||||
|
uint32_t addr,
|
||||||
|
uint32_t page_size)
|
||||||
{
|
{
|
||||||
uint32_t i, poll_value;
|
uint32_t i, poll_value;
|
||||||
|
|
||||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
|
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||||
|
|
||||||
// load addr high byte
|
/* load addr high byte */
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
avr_jtag_senddat(avr->jtag_info.tap,
|
||||||
|
NULL,
|
||||||
|
0x0700 | ((addr >> 9) & 0xFF),
|
||||||
|
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||||
|
|
||||||
// load addr low byte
|
/* load addr low byte */
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
avr_jtag_senddat(avr->jtag_info.tap,
|
||||||
|
NULL,
|
||||||
|
0x0300 | ((addr >> 1) & 0xFF),
|
||||||
|
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||||
|
|
||||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
|
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
|
||||||
|
|
||||||
for (i = 0; i < page_size; i++)
|
for (i = 0; i < page_size; i++) {
|
||||||
{
|
|
||||||
if (i < buf_size)
|
if (i < buf_size)
|
||||||
{
|
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
|
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
|
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||||
|
|
||||||
@@ -174,11 +177,12 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf,
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
poll_value = 0;
|
poll_value = 0;
|
||||||
avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
|
avr_jtag_senddat(avr->jtag_info.tap,
|
||||||
|
&poll_value,
|
||||||
|
0x3700,
|
||||||
|
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||||
if (ERROR_OK != mcu_execute_queue())
|
if (ERROR_OK != mcu_execute_queue())
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||||
} while (!(poll_value & 0x0200));
|
} while (!(poll_value & 0x0200));
|
||||||
|
|
||||||
@@ -190,10 +194,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
|
|||||||
struct avrf_flash_bank *avrf_info;
|
struct avrf_flash_bank *avrf_info;
|
||||||
|
|
||||||
if (CMD_ARGC < 6)
|
if (CMD_ARGC < 6)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank avr configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
avrf_info = malloc(sizeof(struct avrf_flash_bank));
|
avrf_info = malloc(sizeof(struct avrf_flash_bank));
|
||||||
bank->driver_priv = avrf_info;
|
bank->driver_priv = avrf_info;
|
||||||
@@ -209,10 +210,9 @@ static int avrf_erase(struct flash_bank *bank, int first, int last)
|
|||||||
struct avr_common *avr = target->arch_info;
|
struct avr_common *avr = target->arch_info;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
LOG_DEBUG("%s", __FUNCTION__);
|
LOG_DEBUG("%s", __func__);
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ static int avrf_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
|
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
|
||||||
{
|
{
|
||||||
LOG_INFO("%s", __FUNCTION__);
|
LOG_INFO("%s", __func__);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,16 +240,16 @@ static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
struct avr_common *avr = target->arch_info;
|
struct avr_common *avr = target->arch_info;
|
||||||
uint32_t cur_size, cur_buffer_size, page_size;
|
uint32_t cur_size, cur_buffer_size, page_size;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_size = bank->sectors[0].size;
|
page_size = bank->sectors[0].size;
|
||||||
if ((offset % page_size) != 0)
|
if ((offset % page_size) != 0) {
|
||||||
{
|
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
|
||||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size);
|
offset,
|
||||||
|
page_size);
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,22 +257,19 @@ static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
LOG_DEBUG("count is %" PRId32 "", count);
|
LOG_DEBUG("count is %" PRId32 "", count);
|
||||||
|
|
||||||
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
cur_size = 0;
|
cur_size = 0;
|
||||||
while (count > 0)
|
while (count > 0) {
|
||||||
{
|
|
||||||
if (count > page_size)
|
if (count > page_size)
|
||||||
{
|
|
||||||
cur_buffer_size = page_size;
|
cur_buffer_size = page_size;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
cur_buffer_size = count;
|
cur_buffer_size = count;
|
||||||
}
|
avr_jtagprg_writeflashpage(avr,
|
||||||
avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size);
|
buffer + cur_size,
|
||||||
|
cur_buffer_size,
|
||||||
|
offset + cur_size,
|
||||||
|
page_size);
|
||||||
count -= cur_buffer_size;
|
count -= cur_buffer_size;
|
||||||
cur_size += cur_buffer_size;
|
cur_size += cur_buffer_size;
|
||||||
|
|
||||||
@@ -285,6 +282,7 @@ static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
|
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
|
||||||
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
|
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
|
||||||
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
|
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
|
||||||
|
|
||||||
static int avrf_probe(struct flash_bank *bank)
|
static int avrf_probe(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
@@ -294,8 +292,7 @@ static int avrf_probe(struct flash_bank *bank)
|
|||||||
int i;
|
int i;
|
||||||
uint32_t device_id;
|
uint32_t device_id;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -304,42 +301,35 @@ static int avrf_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
avr_jtag_read_jtagid(avr, &device_id);
|
avr_jtag_read_jtagid(avr, &device_id);
|
||||||
if (ERROR_OK != mcu_execute_queue())
|
if (ERROR_OK != mcu_execute_queue())
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||||
{
|
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected",
|
||||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
EXTRACT_MFG(device_id),
|
||||||
}
|
0x1F);
|
||||||
|
|
||||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||||
{
|
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
|
||||||
{
|
|
||||||
avr_info = &avft_chips_info[i];
|
avr_info = &avft_chips_info[i];
|
||||||
LOG_INFO("target device is %s", avr_info->name);
|
LOG_INFO("target device is %s", avr_info->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avr_info != NULL)
|
if (avr_info != NULL) {
|
||||||
{
|
if (bank->sectors) {
|
||||||
if (bank->sectors)
|
|
||||||
{
|
|
||||||
free(bank->sectors);
|
free(bank->sectors);
|
||||||
bank->sectors = NULL;
|
bank->sectors = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// chip found
|
/* chip found */
|
||||||
bank->base = 0x00000000;
|
bank->base = 0x00000000;
|
||||||
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
|
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
|
||||||
bank->num_sectors = avr_info->flash_page_num;
|
bank->num_sectors = avr_info->flash_page_num;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
|
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
|
||||||
|
|
||||||
for (i = 0; i < avr_info->flash_page_num; i++)
|
for (i = 0; i < avr_info->flash_page_num; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = i * avr_info->flash_page_size;
|
bank->sectors[i].offset = i * avr_info->flash_page_size;
|
||||||
bank->sectors[i].size = avr_info->flash_page_size;
|
bank->sectors[i].size = avr_info->flash_page_size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
@@ -348,10 +338,8 @@ static int avrf_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
avrf_info->probed = 1;
|
avrf_info->probed = 1;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
} else {
|
||||||
else
|
/* chip not supported */
|
||||||
{
|
|
||||||
// chip not supported
|
|
||||||
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
|
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
|
||||||
|
|
||||||
avrf_info->probed = 1;
|
avrf_info->probed = 1;
|
||||||
@@ -369,7 +357,7 @@ static int avrf_auto_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
static int avrf_protect_check(struct flash_bank *bank)
|
static int avrf_protect_check(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
LOG_INFO("%s", __FUNCTION__);
|
LOG_INFO("%s", __func__);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,28 +369,23 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
int i;
|
int i;
|
||||||
uint32_t device_id;
|
uint32_t device_id;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
avr_jtag_read_jtagid(avr, &device_id);
|
avr_jtag_read_jtagid(avr, &device_id);
|
||||||
if (ERROR_OK != mcu_execute_queue())
|
if (ERROR_OK != mcu_execute_queue())
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||||
{
|
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected",
|
||||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
EXTRACT_MFG(device_id),
|
||||||
}
|
0x1F);
|
||||||
|
|
||||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||||
{
|
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
|
||||||
{
|
|
||||||
avr_info = &avft_chips_info[i];
|
avr_info = &avft_chips_info[i];
|
||||||
LOG_INFO("target device is %s", avr_info->name);
|
LOG_INFO("target device is %s", avr_info->name);
|
||||||
|
|
||||||
@@ -410,15 +393,13 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avr_info != NULL)
|
if (avr_info != NULL) {
|
||||||
{
|
/* chip found */
|
||||||
// chip found
|
snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name,
|
||||||
snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id));
|
EXTRACT_VER(device_id));
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
} else {
|
||||||
else
|
/* chip not supported */
|
||||||
{
|
|
||||||
// chip not supported
|
|
||||||
snprintf(buf, buf_size, "Cannot identify target as a avr\n");
|
snprintf(buf, buf_size, "Cannot identify target as a avr\n");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -429,8 +410,7 @@ static int avrf_mass_erase(struct flash_bank *bank)
|
|||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
struct avr_common *avr = target->arch_info;
|
struct avr_common *avr = target->arch_info;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -438,9 +418,7 @@ static int avrf_mass_erase(struct flash_bank *bank)
|
|||||||
if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||||
|| (ERROR_OK != avr_jtagprg_chiperase(avr))
|
|| (ERROR_OK != avr_jtagprg_chiperase(avr))
|
||||||
|| (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
|
|| (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -450,38 +428,30 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 1)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
command_print(CMD_CTX, "avr mass_erase <bank>");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (avrf_mass_erase(bank) == ERROR_OK)
|
if (avrf_mass_erase(bank) == ERROR_OK) {
|
||||||
{
|
|
||||||
/* set all sectors as erased */
|
/* set all sectors as erased */
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
{
|
|
||||||
bank->sectors[i].is_erased = 1;
|
bank->sectors[i].is_erased = 1;
|
||||||
}
|
|
||||||
|
|
||||||
command_print(CMD_CTX, "avr mass erase complete");
|
command_print(CMD_CTX, "avr mass erase complete");
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "avr mass erase failed");
|
command_print(CMD_CTX, "avr mass erase failed");
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("%s", __FUNCTION__);
|
LOG_DEBUG("%s", __func__);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct command_registration avrf_exec_command_handlers[] = {
|
static const struct command_registration avrf_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "mass_erase",
|
.name = "mass_erase",
|
||||||
|
.usage = "<bank>",
|
||||||
.handler = avrf_handle_mass_erase_command,
|
.handler = avrf_handle_mass_erase_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.help = "erase entire device",
|
.help = "erase entire device",
|
||||||
@@ -493,6 +463,7 @@ static const struct command_registration avrf_command_handlers[] = {
|
|||||||
.name = "avrf",
|
.name = "avrf",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "AVR flash command group",
|
.help = "AVR flash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = avrf_exec_command_handlers,
|
.chain = avrf_exec_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
@@ -508,7 +479,7 @@ struct flash_driver avr_flash = {
|
|||||||
.read = default_flash_read,
|
.read = default_flash_read,
|
||||||
.probe = avrf_probe,
|
.probe = avrf_probe,
|
||||||
.auto_probe = avrf_auto_probe,
|
.auto_probe = avrf_auto_probe,
|
||||||
.erase_check = default_flash_mem_blank_check,
|
.erase_check = default_flash_blank_check,
|
||||||
.protect_check = avrf_protect_check,
|
.protect_check = avrf_protect_check,
|
||||||
.info = avrf_info,
|
.info = avrf_info,
|
||||||
};
|
};
|
||||||
|
|||||||
1296
src/flash/nor/cfi.c
1296
src/flash/nor/cfi.c
File diff suppressed because it is too large
Load Diff
@@ -17,16 +17,14 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef CFI_H
|
#ifndef CFI_H
|
||||||
#define CFI_H
|
#define CFI_H
|
||||||
|
|
||||||
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
|
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
|
||||||
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
|
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
|
||||||
|
|
||||||
struct cfi_flash_bank
|
struct cfi_flash_bank {
|
||||||
{
|
|
||||||
struct working_area *write_algorithm;
|
|
||||||
|
|
||||||
int x16_as_x8;
|
int x16_as_x8;
|
||||||
int jedec_probe;
|
int jedec_probe;
|
||||||
int not_cfi;
|
int not_cfi;
|
||||||
@@ -80,8 +78,7 @@ struct cfi_flash_bank
|
|||||||
* as defined for the Advanced+ Boot Block Flash Memory (C3)
|
* as defined for the Advanced+ Boot Block Flash Memory (C3)
|
||||||
* and used by the linux kernel cfi driver (as of 2.6.14)
|
* and used by the linux kernel cfi driver (as of 2.6.14)
|
||||||
*/
|
*/
|
||||||
struct cfi_intel_pri_ext
|
struct cfi_intel_pri_ext {
|
||||||
{
|
|
||||||
uint8_t pri[3];
|
uint8_t pri[3];
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
uint8_t minor_version;
|
uint8_t minor_version;
|
||||||
@@ -100,8 +97,7 @@ struct cfi_intel_pri_ext
|
|||||||
/* Spansion primary extended query table as defined for and used by
|
/* Spansion primary extended query table as defined for and used by
|
||||||
* the linux kernel cfi driver (as of 2.6.15)
|
* the linux kernel cfi driver (as of 2.6.15)
|
||||||
*/
|
*/
|
||||||
struct cfi_spansion_pri_ext
|
struct cfi_spansion_pri_ext {
|
||||||
{
|
|
||||||
uint8_t pri[3];
|
uint8_t pri[3];
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
uint8_t minor_version;
|
uint8_t minor_version;
|
||||||
@@ -124,8 +120,7 @@ struct cfi_spansion_pri_ext
|
|||||||
/* Atmel primary extended query table as defined for and used by
|
/* Atmel primary extended query table as defined for and used by
|
||||||
* the linux kernel cfi driver (as of 2.6.20+)
|
* the linux kernel cfi driver (as of 2.6.20+)
|
||||||
*/
|
*/
|
||||||
struct cfi_atmel_pri_ext
|
struct cfi_atmel_pri_ext {
|
||||||
{
|
|
||||||
uint8_t pri[3];
|
uint8_t pri[3];
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
uint8_t minor_version;
|
uint8_t minor_version;
|
||||||
@@ -140,14 +135,12 @@ enum {
|
|||||||
CFI_UNLOCK_5555_2AAA,
|
CFI_UNLOCK_5555_2AAA,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cfi_unlock_addresses
|
struct cfi_unlock_addresses {
|
||||||
{
|
|
||||||
uint32_t unlock1;
|
uint32_t unlock1;
|
||||||
uint32_t unlock2;
|
uint32_t unlock2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cfi_fixup
|
struct cfi_fixup {
|
||||||
{
|
|
||||||
uint16_t mfr;
|
uint16_t mfr;
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
void (*fixup)(struct flash_bank *bank, void *param);
|
void (*fixup)(struct flash_bank *bank, void *param);
|
||||||
@@ -161,6 +154,7 @@ struct cfi_fixup
|
|||||||
#define CFI_MFR_AMIC 0x0037
|
#define CFI_MFR_AMIC 0x0037
|
||||||
#define CFI_MFR_SST 0x00BF
|
#define CFI_MFR_SST 0x00BF
|
||||||
#define CFI_MFR_MX 0x00C2
|
#define CFI_MFR_MX 0x00C2
|
||||||
|
#define CFI_MFR_EON 0x007F
|
||||||
|
|
||||||
#define CFI_MFR_ANY 0xffff
|
#define CFI_MFR_ANY 0xffff
|
||||||
#define CFI_ID_ANY 0xffff
|
#define CFI_ID_ANY 0xffff
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include <flash/nor/imp.h>
|
#include <flash/nor/imp.h>
|
||||||
#include <target/image.h>
|
#include <target/image.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* Upper level of NOR flash framework.
|
* Upper level of NOR flash framework.
|
||||||
@@ -45,9 +44,7 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
retval = bank->driver->erase(bank, first, last);
|
retval = bank->driver->erase(bank, first, last);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
LOG_ERROR("failed erasing sectors %d to %d", first, last);
|
LOG_ERROR("failed erasing sectors %d to %d", first, last);
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -57,8 +54,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* callers may not supply illegal parameters ... */
|
/* callers may not supply illegal parameters ... */
|
||||||
if (first < 0 || first > last || last >= bank->num_sectors)
|
if (first < 0 || first > last || last >= bank->num_sectors) {
|
||||||
{
|
|
||||||
LOG_ERROR("illegal sector range");
|
LOG_ERROR("illegal sector range");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
@@ -79,9 +75,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
*/
|
*/
|
||||||
retval = bank->driver->protect(bank, set, first, last);
|
retval = bank->driver->protect(bank, set, first, last);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
LOG_ERROR("failed setting protection for areas %d to %d", first, last);
|
LOG_ERROR("failed setting protection for areas %d to %d", first, last);
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -92,10 +86,11 @@ int flash_driver_write(struct flash_bank *bank,
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = bank->driver->write(bank, buffer, offset, count);
|
retval = bank->driver->write(bank, buffer, offset, count);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
LOG_ERROR(
|
||||||
LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
"error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||||
bank->base, offset);
|
bank->base,
|
||||||
|
offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -109,10 +104,11 @@ int flash_driver_read(struct flash_bank *bank,
|
|||||||
LOG_DEBUG("call flash_driver_read()");
|
LOG_DEBUG("call flash_driver_read()");
|
||||||
|
|
||||||
retval = bank->driver->read(bank, buffer, offset, count);
|
retval = bank->driver->read(bank, buffer, offset, count);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
LOG_ERROR(
|
||||||
LOG_ERROR("error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
"error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||||
bank->base, offset);
|
bank->base,
|
||||||
|
offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -128,19 +124,16 @@ void flash_bank_add(struct flash_bank *bank)
|
|||||||
{
|
{
|
||||||
/* put flash bank in linked list */
|
/* put flash bank in linked list */
|
||||||
unsigned bank_num = 0;
|
unsigned bank_num = 0;
|
||||||
if (flash_banks)
|
if (flash_banks) {
|
||||||
{
|
|
||||||
/* find last flash bank */
|
/* find last flash bank */
|
||||||
struct flash_bank *p = flash_banks;
|
struct flash_bank *p = flash_banks;
|
||||||
while (NULL != p->next)
|
while (NULL != p->next) {
|
||||||
{
|
|
||||||
bank_num += 1;
|
bank_num += 1;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
p->next = bank;
|
p->next = bank;
|
||||||
bank_num += 1;
|
bank_num += 1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
flash_banks = bank;
|
flash_banks = bank;
|
||||||
|
|
||||||
bank->bank_number = bank_num;
|
bank->bank_number = bank_num;
|
||||||
@@ -156,13 +149,10 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num)
|
|||||||
struct flash_bank *p;
|
struct flash_bank *p;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (p = flash_banks; p; p = p->next)
|
for (p = flash_banks; p; p = p->next) {
|
||||||
{
|
|
||||||
if (i++ == num)
|
if (i++ == num)
|
||||||
{
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
LOG_ERROR("flash bank %d does not exist", num);
|
LOG_ERROR("flash bank %d does not exist", num);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -172,9 +162,7 @@ int flash_get_bank_count(void)
|
|||||||
struct flash_bank *p;
|
struct flash_bank *p;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (p = flash_banks; p; p = p->next)
|
for (p = flash_banks; p; p = p->next)
|
||||||
{
|
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +172,7 @@ struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
|
|||||||
unsigned found = 0;
|
unsigned found = 0;
|
||||||
|
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
for (bank = flash_banks; NULL != bank; bank = bank->next)
|
for (bank = flash_banks; NULL != bank; bank = bank->next) {
|
||||||
{
|
|
||||||
if (strcmp(bank->name, name) == 0)
|
if (strcmp(bank->name, name) == 0)
|
||||||
return bank;
|
return bank;
|
||||||
if (!flash_driver_name_matches(bank->driver->name, name))
|
if (!flash_driver_name_matches(bank->driver->name, name))
|
||||||
@@ -203,12 +190,10 @@ int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
bank = get_flash_bank_by_name_noprobe(name);
|
bank = get_flash_bank_by_name_noprobe(name);
|
||||||
if (bank != NULL)
|
if (bank != NULL) {
|
||||||
{
|
|
||||||
retval = bank->driver->auto_probe(bank);
|
retval = bank->driver->auto_probe(bank);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR("auto_probe failed");
|
LOG_ERROR("auto_probe failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -224,14 +209,11 @@ int get_flash_bank_by_num(int num, struct flash_bank **bank)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
{
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
|
|
||||||
retval = p->driver->auto_probe(p);
|
retval = p->driver->auto_probe(p);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR("auto_probe failed");
|
LOG_ERROR("auto_probe failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -241,38 +223,37 @@ int get_flash_bank_by_num(int num, struct flash_bank **bank)
|
|||||||
|
|
||||||
/* lookup flash bank by address, bank not found is success, but
|
/* lookup flash bank by address, bank not found is success, but
|
||||||
* result_bank is set to NULL. */
|
* result_bank is set to NULL. */
|
||||||
int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank)
|
int get_flash_bank_by_addr(struct target *target,
|
||||||
|
uint32_t addr,
|
||||||
|
bool check,
|
||||||
|
struct flash_bank **result_bank)
|
||||||
{
|
{
|
||||||
struct flash_bank *c;
|
struct flash_bank *c;
|
||||||
|
|
||||||
/* cycle through bank list */
|
/* cycle through bank list */
|
||||||
for (c = flash_banks; c; c = c->next)
|
for (c = flash_banks; c; c = c->next) {
|
||||||
{
|
|
||||||
int retval;
|
int retval;
|
||||||
retval = c->driver->auto_probe(c);
|
retval = c->driver->auto_probe(c);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_ERROR("auto_probe failed");
|
LOG_ERROR("auto_probe failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
/* check whether address belongs to this flash bank */
|
/* check whether address belongs to this flash bank */
|
||||||
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
|
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target) {
|
||||||
{
|
|
||||||
*result_bank = c;
|
*result_bank = c;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result_bank = NULL;
|
*result_bank = NULL;
|
||||||
if (check)
|
if (check) {
|
||||||
{
|
|
||||||
LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
|
LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int default_flash_mem_blank_check(struct flash_bank *bank)
|
static int default_flash_mem_blank_check(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
const int buffer_size = 1024;
|
const int buffer_size = 1024;
|
||||||
@@ -280,38 +261,33 @@ int default_flash_mem_blank_check(struct flash_bank *bank)
|
|||||||
uint32_t nBytes;
|
uint32_t nBytes;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *buffer = malloc(buffer_size);
|
uint8_t *buffer = malloc(buffer_size);
|
||||||
|
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
{
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
bank->sectors[i].is_erased = 1;
|
bank->sectors[i].is_erased = 1;
|
||||||
|
|
||||||
for (j = 0; j < bank->sectors[i].size; j += buffer_size)
|
for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
|
||||||
{
|
|
||||||
uint32_t chunk;
|
uint32_t chunk;
|
||||||
chunk = buffer_size;
|
chunk = buffer_size;
|
||||||
if (chunk > (j - bank->sectors[i].size))
|
if (chunk > (j - bank->sectors[i].size))
|
||||||
{
|
|
||||||
chunk = (j - bank->sectors[i].size);
|
chunk = (j - bank->sectors[i].size);
|
||||||
}
|
|
||||||
|
|
||||||
retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
|
retval = target_read_memory(target,
|
||||||
|
bank->base + bank->sectors[i].offset + j,
|
||||||
|
4,
|
||||||
|
chunk/4,
|
||||||
|
buffer);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
for (nBytes = 0; nBytes < chunk; nBytes++)
|
for (nBytes = 0; nBytes < chunk; nBytes++) {
|
||||||
{
|
if (buffer[nBytes] != 0xFF) {
|
||||||
if (buffer[nBytes] != 0xFF)
|
|
||||||
{
|
|
||||||
bank->sectors[i].is_erased = 0;
|
bank->sectors[i].is_erased = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -333,19 +309,17 @@ int default_flash_blank_check(struct flash_bank *bank)
|
|||||||
int fast_check = 0;
|
int fast_check = 0;
|
||||||
uint32_t blank;
|
uint32_t blank;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
{
|
|
||||||
uint32_t address = bank->base + bank->sectors[i].offset;
|
uint32_t address = bank->base + bank->sectors[i].offset;
|
||||||
uint32_t size = bank->sectors[i].size;
|
uint32_t size = bank->sectors[i].size;
|
||||||
|
|
||||||
if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
|
retval = target_blank_check_memory(target, address, size, &blank);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
fast_check = 0;
|
fast_check = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -356,8 +330,7 @@ int default_flash_blank_check(struct flash_bank *bank)
|
|||||||
fast_check = 1;
|
fast_check = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fast_check)
|
if (!fast_check) {
|
||||||
{
|
|
||||||
LOG_USER("Running slow fallback erase check - add working memory");
|
LOG_USER("Running slow fallback erase check - add working memory");
|
||||||
return default_flash_mem_blank_check(bank);
|
return default_flash_mem_blank_check(bank);
|
||||||
}
|
}
|
||||||
@@ -393,17 +366,14 @@ static int flash_iterate_address_range_inner(struct target *target,
|
|||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (c->size == 0 || c->num_sectors == 0)
|
if (c->size == 0 || c->num_sectors == 0) {
|
||||||
{
|
|
||||||
LOG_ERROR("Bank is invalid");
|
LOG_ERROR("Bank is invalid");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0) {
|
||||||
{
|
|
||||||
/* special case, erase whole bank when length is zero */
|
/* special case, erase whole bank when length is zero */
|
||||||
if (addr != c->base)
|
if (addr != c->base) {
|
||||||
{
|
|
||||||
LOG_ERROR("Whole bank access must start at beginning of bank.");
|
LOG_ERROR("Whole bank access must start at beginning of bank.");
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
@@ -412,8 +382,7 @@ static int flash_iterate_address_range_inner(struct target *target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check whether it all fits in this bank */
|
/* check whether it all fits in this bank */
|
||||||
if (addr + length - 1 > c->base + c->size - 1)
|
if (addr + length - 1 > c->base + c->size - 1) {
|
||||||
{
|
|
||||||
LOG_ERROR("Flash access does not fit into bank.");
|
LOG_ERROR("Flash access does not fit into bank.");
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
@@ -423,8 +392,7 @@ static int flash_iterate_address_range_inner(struct target *target,
|
|||||||
addr -= c->base;
|
addr -= c->base;
|
||||||
last_addr -= c->base;
|
last_addr -= c->base;
|
||||||
|
|
||||||
for (i = 0; i < c->num_sectors; i++)
|
for (i = 0; i < c->num_sectors; i++) {
|
||||||
{
|
|
||||||
struct flash_sector *f = c->sectors + i;
|
struct flash_sector *f = c->sectors + i;
|
||||||
uint32_t end = f->offset + f->size;
|
uint32_t end = f->offset + f->size;
|
||||||
|
|
||||||
@@ -509,16 +477,14 @@ static int flash_iterate_address_range(struct target *target,
|
|||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
/* Danger! zero-length iterations means entire bank! */
|
/* Danger! zero-length iterations means entire bank! */
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
retval = get_flash_bank_by_addr(target, addr, true, &c);
|
retval = get_flash_bank_by_addr(target, addr, true, &c);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
uint32_t cur_length = length;
|
uint32_t cur_length = length;
|
||||||
/* check whether it all fits in this bank */
|
/* check whether it all fits in this bank */
|
||||||
if (addr + length - 1 > c->base + c->size - 1)
|
if (addr + length - 1 > c->base + c->size - 1) {
|
||||||
{
|
|
||||||
LOG_DEBUG("iterating over more than one flash bank.");
|
LOG_DEBUG("iterating over more than one flash bank.");
|
||||||
cur_length = c->base + c->size - addr;
|
cur_length = c->base + c->size - addr;
|
||||||
}
|
}
|
||||||
@@ -564,17 +530,12 @@ static int compare_section (const void * a, const void * b)
|
|||||||
b2 = *((struct imagesection **)b);
|
b2 = *((struct imagesection **)b);
|
||||||
|
|
||||||
if (b1->base_address == b2->base_address)
|
if (b1->base_address == b2->base_address)
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
} else if (b1->base_address > b2->base_address)
|
else if (b1->base_address > b2->base_address)
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
else
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int flash_write_unlock(struct target *target, struct image *image,
|
int flash_write_unlock(struct target *target, struct image *image,
|
||||||
uint32_t *written, int erase, bool unlock)
|
uint32_t *written, int erase, bool unlock)
|
||||||
@@ -592,8 +553,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
if (written)
|
if (written)
|
||||||
*written = 0;
|
*written = 0;
|
||||||
|
|
||||||
if (erase)
|
if (erase) {
|
||||||
{
|
|
||||||
/* assume all sectors need erasing - stops any problems
|
/* assume all sectors need erasing - stops any problems
|
||||||
* when flash_write is called multiple times */
|
* when flash_write is called multiple times */
|
||||||
|
|
||||||
@@ -609,16 +569,13 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
image->num_sections);
|
image->num_sections);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < image->num_sections; i++)
|
for (i = 0; i < image->num_sections; i++)
|
||||||
{
|
|
||||||
sections[i] = &image->sections[i];
|
sections[i] = &image->sections[i];
|
||||||
}
|
|
||||||
|
|
||||||
qsort(sections, image->num_sections, sizeof(struct imagesection *),
|
qsort(sections, image->num_sections, sizeof(struct imagesection *),
|
||||||
compare_section);
|
compare_section);
|
||||||
|
|
||||||
/* loop until we reach end of the image */
|
/* loop until we reach end of the image */
|
||||||
while (section < image->num_sections)
|
while (section < image->num_sections) {
|
||||||
{
|
|
||||||
uint32_t buffer_size;
|
uint32_t buffer_size;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
int section_last;
|
int section_last;
|
||||||
@@ -626,8 +583,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
uint32_t run_size = sections[section]->size - section_offset;
|
uint32_t run_size = sections[section]->size - section_offset;
|
||||||
int pad_bytes = 0;
|
int pad_bytes = 0;
|
||||||
|
|
||||||
if (sections[section]->size == 0)
|
if (sections[section]->size == 0) {
|
||||||
{
|
|
||||||
LOG_WARNING("empty section %d", section);
|
LOG_WARNING("empty section %d", section);
|
||||||
section++;
|
section++;
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
@@ -637,11 +593,9 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
/* find the corresponding flash bank */
|
/* find the corresponding flash bank */
|
||||||
retval = get_flash_bank_by_addr(target, run_address, false, &c);
|
retval = get_flash_bank_by_addr(target, run_address, false, &c);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
if (c == NULL) {
|
||||||
if (c == NULL)
|
LOG_WARNING("no flash bank found for address %x", run_address);
|
||||||
{
|
|
||||||
section++; /* and skip it */
|
section++; /* and skip it */
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
continue;
|
continue;
|
||||||
@@ -650,13 +604,11 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
/* collect consecutive sections which fall into the same bank */
|
/* collect consecutive sections which fall into the same bank */
|
||||||
section_last = section;
|
section_last = section;
|
||||||
padding[section] = 0;
|
padding[section] = 0;
|
||||||
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
while ((run_address + run_size - 1 < c->base + c->size - 1) &&
|
||||||
&& (section_last + 1 < image->num_sections))
|
(section_last + 1 < image->num_sections)) {
|
||||||
{
|
|
||||||
/* sections are sorted */
|
/* sections are sorted */
|
||||||
assert(sections[section_last + 1]->base_address >= c->base);
|
assert(sections[section_last + 1]->base_address >= c->base);
|
||||||
if (sections[section_last + 1]->base_address >= (c->base + c->size))
|
if (sections[section_last + 1]->base_address >= (c->base + c->size)) {
|
||||||
{
|
|
||||||
/* Done with this bank */
|
/* Done with this bank */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -684,11 +636,12 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
run_size += pad_bytes;
|
run_size += pad_bytes;
|
||||||
|
|
||||||
if (pad_bytes > 0)
|
if (pad_bytes > 0)
|
||||||
LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
|
LOG_INFO("Padding image section %d with %d bytes",
|
||||||
|
section_last-1,
|
||||||
|
pad_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run_address + run_size - 1 > c->base + c->size - 1)
|
if (run_address + run_size - 1 > c->base + c->size - 1) {
|
||||||
{
|
|
||||||
/* If we have more than one flash chip back to back, then we limit
|
/* If we have more than one flash chip back to back, then we limit
|
||||||
* the current write operation to the current chip.
|
* the current write operation to the current chip.
|
||||||
*/
|
*/
|
||||||
@@ -721,8 +674,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
|
|
||||||
/* allocate buffer */
|
/* allocate buffer */
|
||||||
buffer = malloc(run_size);
|
buffer = malloc(run_size);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL) {
|
||||||
{
|
|
||||||
LOG_ERROR("Out of memory for flash bank buffer");
|
LOG_ERROR("Out of memory for flash bank buffer");
|
||||||
retval = ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
goto done;
|
goto done;
|
||||||
@@ -730,8 +682,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
buffer_size = 0;
|
buffer_size = 0;
|
||||||
|
|
||||||
/* read sections to the buffer */
|
/* read sections to the buffer */
|
||||||
while (buffer_size < run_size)
|
while (buffer_size < run_size) {
|
||||||
{
|
|
||||||
size_t size_read;
|
size_t size_read;
|
||||||
|
|
||||||
size_read = run_size - buffer_size;
|
size_read = run_size - buffer_size;
|
||||||
@@ -746,12 +697,13 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
|
intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
|
||||||
int t_section_num = diff / sizeof(struct imagesection);
|
int t_section_num = diff / sizeof(struct imagesection);
|
||||||
|
|
||||||
LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, section_offset = %d, buffer_size = %d, size_read = %d",
|
LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, "
|
||||||
(int)section,
|
"section_offset = %d, buffer_size = %d, size_read = %d",
|
||||||
(int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read);
|
(int)section, (int)t_section_num, (int)section_offset,
|
||||||
if ((retval = image_read_section(image, t_section_num, section_offset,
|
(int)buffer_size, (int)size_read);
|
||||||
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
|
retval = image_read_section(image, t_section_num, section_offset,
|
||||||
{
|
size_read, buffer + buffer_size, &size_read);
|
||||||
|
if (retval != ERROR_OK || size_read == 0) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -763,8 +715,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
buffer_size += size_read;
|
buffer_size += size_read;
|
||||||
section_offset += size_read;
|
section_offset += size_read;
|
||||||
|
|
||||||
if (section_offset >= sections[section]->size)
|
if (section_offset >= sections[section]->size) {
|
||||||
{
|
|
||||||
section++;
|
section++;
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
}
|
}
|
||||||
@@ -773,29 +724,23 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
retval = ERROR_OK;
|
retval = ERROR_OK;
|
||||||
|
|
||||||
if (unlock)
|
if (unlock)
|
||||||
{
|
|
||||||
retval = flash_unlock_address_range(target, run_address, run_size);
|
retval = flash_unlock_address_range(target, run_address, run_size);
|
||||||
}
|
if (retval == ERROR_OK) {
|
||||||
if (retval == ERROR_OK)
|
if (erase) {
|
||||||
{
|
|
||||||
if (erase)
|
|
||||||
{
|
|
||||||
/* calculate and erase sectors */
|
/* calculate and erase sectors */
|
||||||
retval = flash_erase_address_range(target,
|
retval = flash_erase_address_range(target,
|
||||||
true, run_address, run_size);
|
true, run_address, run_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK) {
|
||||||
{
|
|
||||||
/* write flash sectors */
|
/* write flash sectors */
|
||||||
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
|
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK) {
|
||||||
{
|
|
||||||
/* abort operation */
|
/* abort operation */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@@ -804,7 +749,6 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
*written += run_size; /* add run size to total written counter */
|
*written += run_size; /* add run size to total written counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free(sections);
|
free(sections);
|
||||||
free(padding);
|
free(padding);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NOR_CORE_H
|
#ifndef FLASH_NOR_CORE_H
|
||||||
#define FLASH_NOR_CORE_H
|
#define FLASH_NOR_CORE_H
|
||||||
|
|
||||||
@@ -39,11 +40,10 @@ struct image;
|
|||||||
* within a flash bank. A single bank typically consists of multiple
|
* within a flash bank. A single bank typically consists of multiple
|
||||||
* sectors, each of which can be erased and protected independently.
|
* sectors, each of which can be erased and protected independently.
|
||||||
*/
|
*/
|
||||||
struct flash_sector
|
struct flash_sector {
|
||||||
{
|
/** Bus offset from start of the flash chip (in bytes). */
|
||||||
/// Bus offset from start of the flash chip (in bytes).
|
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
/// Number of bytes in this flash sector.
|
/** Number of bytes in this flash sector. */
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
/**
|
/**
|
||||||
* Indication of erasure status: 0 = not erased, 1 = erased,
|
* Indication of erasure status: 0 = not erased, 1 = erased,
|
||||||
@@ -72,8 +72,7 @@ struct flash_sector
|
|||||||
* may use the @c driver_priv member to store additional data on a
|
* may use the @c driver_priv member to store additional data on a
|
||||||
* per-bank basis, if required.
|
* per-bank basis, if required.
|
||||||
*/
|
*/
|
||||||
struct flash_bank
|
struct flash_bank {
|
||||||
{
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
struct target *target; /**< Target to which this bank belongs. */
|
struct target *target; /**< Target to which this bank belongs. */
|
||||||
@@ -94,13 +93,13 @@ struct flash_bank
|
|||||||
* some non-zero value during "probe()" or "auto_probe()".
|
* some non-zero value during "probe()" or "auto_probe()".
|
||||||
*/
|
*/
|
||||||
int num_sectors;
|
int num_sectors;
|
||||||
/// Array of sectors, allocated and initilized by the flash driver
|
/** Array of sectors, allocated and initilized by the flash driver */
|
||||||
struct flash_sector *sectors;
|
struct flash_sector *sectors;
|
||||||
|
|
||||||
struct flash_bank *next; /**< The next flash bank on this chip */
|
struct flash_bank *next; /**< The next flash bank on this chip */
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Registers the 'flash' subsystem commands
|
/** Registers the 'flash' subsystem commands */
|
||||||
int flash_register_commands(struct command_context *cmd_ctx);
|
int flash_register_commands(struct command_context *cmd_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +133,7 @@ int flash_write(struct target *target,
|
|||||||
* This routine must be called when the system may modify the status.
|
* This routine must be called when the system may modify the status.
|
||||||
*/
|
*/
|
||||||
void flash_set_dirty(void);
|
void flash_set_dirty(void);
|
||||||
/// @returns The number of flash banks currently defined.
|
/** @returns The number of flash banks currently defined. */
|
||||||
int flash_get_bank_count(void);
|
int flash_get_bank_count(void);
|
||||||
/**
|
/**
|
||||||
* Provides default read implementation for flash memory.
|
* Provides default read implementation for flash memory.
|
||||||
@@ -153,13 +152,6 @@ int default_flash_read(struct flash_bank *bank,
|
|||||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||||
*/
|
*/
|
||||||
int default_flash_blank_check(struct flash_bank *bank);
|
int default_flash_blank_check(struct flash_bank *bank);
|
||||||
/**
|
|
||||||
* Provides a default blank flash memory check. Ensures the contents
|
|
||||||
* of the given bank have truly been erased.
|
|
||||||
* @param bank The flash bank.
|
|
||||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
|
||||||
*/
|
|
||||||
int default_flash_mem_blank_check(struct flash_bank *bank);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the flash bank specified by @a name, which matches the
|
* Returns the flash bank specified by @a name, which matches the
|
||||||
@@ -209,6 +201,7 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num);
|
|||||||
* @param check return ERROR_OK and result_bank NULL if the bank does not exist
|
* @param check return ERROR_OK and result_bank NULL if the bank does not exist
|
||||||
* @returns The struct flash_bank located at @a addr, or NULL.
|
* @returns The struct flash_bank located at @a addr, or NULL.
|
||||||
*/
|
*/
|
||||||
int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank);
|
int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check,
|
||||||
|
struct flash_bank **result_bank);
|
||||||
|
|
||||||
#endif // FLASH_NOR_CORE_H
|
#endif /* FLASH_NOR_CORE_H */
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef FLASH_NOR_DRIVER_H
|
#ifndef FLASH_NOR_DRIVER_H
|
||||||
#define FLASH_NOR_DRIVER_H
|
#define FLASH_NOR_DRIVER_H
|
||||||
|
|
||||||
@@ -48,14 +49,18 @@ struct flash_bank;
|
|||||||
* corresponding static <code>flash_driver_<i>callback</i>()</code>
|
* corresponding static <code>flash_driver_<i>callback</i>()</code>
|
||||||
* routine in flash.c.
|
* routine in flash.c.
|
||||||
*/
|
*/
|
||||||
struct flash_driver
|
struct flash_driver {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* Gives a human-readable name of this flash driver,
|
* Gives a human-readable name of this flash driver,
|
||||||
* This field is used to select and initialize the driver.
|
* This field is used to select and initialize the driver.
|
||||||
*/
|
*/
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives a human-readable description of arguments.
|
||||||
|
*/
|
||||||
|
const char *usage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of driver-specific commands to register. When called
|
* An array of driver-specific commands to register. When called
|
||||||
* during the "flash bank" command, the driver can register addition
|
* during the "flash bank" command, the driver can register addition
|
||||||
@@ -195,7 +200,7 @@ struct flash_driver
|
|||||||
/**
|
/**
|
||||||
* A more gentle flavor of filash_driver_s::probe, performing
|
* A more gentle flavor of filash_driver_s::probe, performing
|
||||||
* setup with less noise. Generally, driver routines should test
|
* setup with less noise. Generally, driver routines should test
|
||||||
* to seee if the bank has already been probed; if it has, the
|
* to see if the bank has already been probed; if it has, the
|
||||||
* driver probably should not perform its probe a second time.
|
* driver probably should not perform its probe a second time.
|
||||||
*
|
*
|
||||||
* This callback is often called from the inside of other
|
* This callback is often called from the inside of other
|
||||||
@@ -208,7 +213,8 @@ struct flash_driver
|
|||||||
int (*auto_probe)(struct flash_bank *bank);
|
int (*auto_probe)(struct flash_bank *bank);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLASH_BANK_COMMAND_HANDLER(name) static __FLASH_BANK_COMMAND(name)
|
#define FLASH_BANK_COMMAND_HANDLER(name) \
|
||||||
|
static __FLASH_BANK_COMMAND(name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a NOR flash driver by its name.
|
* Find a NOR flash driver by its name.
|
||||||
@@ -217,4 +223,4 @@ struct flash_driver
|
|||||||
*/
|
*/
|
||||||
struct flash_driver *flash_driver_find_by_name(const char *name);
|
struct flash_driver *flash_driver_find_by_name(const char *name);
|
||||||
|
|
||||||
#endif // FLASH_NOR_DRIVER_H
|
#endif /* FLASH_NOR_DRIVER_H */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -24,8 +25,10 @@
|
|||||||
extern struct flash_driver lpc2000_flash;
|
extern struct flash_driver lpc2000_flash;
|
||||||
extern struct flash_driver lpc288x_flash;
|
extern struct flash_driver lpc288x_flash;
|
||||||
extern struct flash_driver lpc2900_flash;
|
extern struct flash_driver lpc2900_flash;
|
||||||
|
extern struct flash_driver lpcspifi_flash;
|
||||||
extern struct flash_driver cfi_flash;
|
extern struct flash_driver cfi_flash;
|
||||||
extern struct flash_driver at91sam3_flash;
|
extern struct flash_driver at91sam3_flash;
|
||||||
|
extern struct flash_driver at91sam4_flash;
|
||||||
extern struct flash_driver at91sam7_flash;
|
extern struct flash_driver at91sam7_flash;
|
||||||
extern struct flash_driver str7x_flash;
|
extern struct flash_driver str7x_flash;
|
||||||
extern struct flash_driver str9x_flash;
|
extern struct flash_driver str9x_flash;
|
||||||
@@ -34,8 +37,8 @@ extern struct flash_driver stellaris_flash;
|
|||||||
extern struct flash_driver str9xpec_flash;
|
extern struct flash_driver str9xpec_flash;
|
||||||
extern struct flash_driver stm32f1x_flash;
|
extern struct flash_driver stm32f1x_flash;
|
||||||
extern struct flash_driver stm32f2x_flash;
|
extern struct flash_driver stm32f2x_flash;
|
||||||
|
extern struct flash_driver stm32lx_flash;
|
||||||
extern struct flash_driver tms470_flash;
|
extern struct flash_driver tms470_flash;
|
||||||
extern struct flash_driver ecosflash_flash;
|
|
||||||
extern struct flash_driver ocl_flash;
|
extern struct flash_driver ocl_flash;
|
||||||
extern struct flash_driver pic32mx_flash;
|
extern struct flash_driver pic32mx_flash;
|
||||||
extern struct flash_driver avr_flash;
|
extern struct flash_driver avr_flash;
|
||||||
@@ -43,8 +46,10 @@ extern struct flash_driver faux_flash;
|
|||||||
extern struct flash_driver virtual_flash;
|
extern struct flash_driver virtual_flash;
|
||||||
extern struct flash_driver stmsmi_flash;
|
extern struct flash_driver stmsmi_flash;
|
||||||
extern struct flash_driver em357_flash;
|
extern struct flash_driver em357_flash;
|
||||||
//extern struct flash_driver dsp5680xx_flash;
|
extern struct flash_driver dsp5680xx_flash;
|
||||||
extern struct flash_driver fm3_flash;
|
extern struct flash_driver fm3_flash;
|
||||||
|
extern struct flash_driver kinetis_flash;
|
||||||
|
extern struct flash_driver efm32_flash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of built-in flash drivers.
|
* The list of built-in flash drivers.
|
||||||
@@ -54,9 +59,11 @@ static struct flash_driver *flash_drivers[] = {
|
|||||||
&lpc2000_flash,
|
&lpc2000_flash,
|
||||||
&lpc288x_flash,
|
&lpc288x_flash,
|
||||||
&lpc2900_flash,
|
&lpc2900_flash,
|
||||||
|
&lpcspifi_flash,
|
||||||
&cfi_flash,
|
&cfi_flash,
|
||||||
&at91sam7_flash,
|
&at91sam7_flash,
|
||||||
&at91sam3_flash,
|
&at91sam3_flash,
|
||||||
|
&at91sam4_flash,
|
||||||
&str7x_flash,
|
&str7x_flash,
|
||||||
&str9x_flash,
|
&str9x_flash,
|
||||||
&aduc702x_flash,
|
&aduc702x_flash,
|
||||||
@@ -64,8 +71,8 @@ static struct flash_driver *flash_drivers[] = {
|
|||||||
&str9xpec_flash,
|
&str9xpec_flash,
|
||||||
&stm32f1x_flash,
|
&stm32f1x_flash,
|
||||||
&stm32f2x_flash,
|
&stm32f2x_flash,
|
||||||
|
&stm32lx_flash,
|
||||||
&tms470_flash,
|
&tms470_flash,
|
||||||
&ecosflash_flash,
|
|
||||||
&ocl_flash,
|
&ocl_flash,
|
||||||
&pic32mx_flash,
|
&pic32mx_flash,
|
||||||
&avr_flash,
|
&avr_flash,
|
||||||
@@ -73,16 +80,16 @@ static struct flash_driver *flash_drivers[] = {
|
|||||||
&virtual_flash,
|
&virtual_flash,
|
||||||
&stmsmi_flash,
|
&stmsmi_flash,
|
||||||
&em357_flash,
|
&em357_flash,
|
||||||
// Disabled for now, it generates warnings
|
|
||||||
//&dsp5680xx_flash,
|
|
||||||
&fm3_flash,
|
&fm3_flash,
|
||||||
|
&dsp5680xx_flash,
|
||||||
|
&kinetis_flash,
|
||||||
|
&efm32_flash,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct flash_driver *flash_driver_find_by_name(const char *name)
|
struct flash_driver *flash_driver_find_by_name(const char *name)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; flash_drivers[i]; i++)
|
for (unsigned i = 0; flash_drivers[i]; i++) {
|
||||||
{
|
|
||||||
if (strcmp(name, flash_drivers[i]->name) == 0)
|
if (strcmp(name, flash_drivers[i]->name) == 0)
|
||||||
return flash_drivers[i];
|
return flash_drivers[i];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,28 +35,23 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DSP5680XX_FLASH_H
|
|
||||||
#define DSP5680XX_FLASH_H
|
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
#include <target/algorithm.h>
|
#include <target/algorithm.h>
|
||||||
#include <target/dsp5680xx.h>
|
#include <target/dsp5680xx.h>
|
||||||
|
|
||||||
struct dsp5680xx_flash_bank {
|
static int dsp5680xx_build_sector_list(struct flash_bank *bank)
|
||||||
struct working_area *write_algorithm;
|
{
|
||||||
};
|
|
||||||
|
|
||||||
static int dsp5680xx_build_sector_list(struct flash_bank *bank){
|
|
||||||
uint32_t offset = HFM_FLASH_BASE_ADDR;
|
uint32_t offset = HFM_FLASH_BASE_ADDR;
|
||||||
|
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < bank->num_sectors; ++i) {
|
for (i = 0; i < bank->num_sectors; ++i) {
|
||||||
bank->sectors[i].offset = i * HFM_SECTOR_SIZE;
|
bank->sectors[i].offset = i * HFM_SECTOR_SIZE;
|
||||||
bank->sectors[i].size = HFM_SECTOR_SIZE;
|
bank->sectors[i].size = HFM_SECTOR_SIZE;
|
||||||
@@ -64,20 +59,16 @@ static int dsp5680xx_build_sector_list(struct flash_bank *bank){
|
|||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = -1;
|
bank->sectors[i].is_protected = -1;
|
||||||
}
|
}
|
||||||
LOG_USER("%s not tested yet.",__FUNCTION__);
|
LOG_USER("%s not tested yet.", __func__);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// flash bank dsp5680xx 0 0 0 0 <target#>
|
/* flash bank dsp5680xx 0 0 0 0 <target#> */
|
||||||
FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command){
|
FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command)
|
||||||
struct dsp5680xx_flash_bank *nbank;
|
{
|
||||||
|
|
||||||
nbank = malloc(sizeof(struct dsp5680xx_flash_bank));
|
|
||||||
|
|
||||||
bank->base = HFM_FLASH_BASE_ADDR;
|
bank->base = HFM_FLASH_BASE_ADDR;
|
||||||
bank->size = HFM_SIZE_BYTES; // top 4k not accessible
|
bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */
|
||||||
bank->driver_priv = nbank;
|
|
||||||
bank->num_sectors = HFM_SECTOR_COUNT;
|
bank->num_sectors = HFM_SECTOR_COUNT;
|
||||||
dsp5680xx_build_sector_list(bank);
|
dsp5680xx_build_sector_list(bank);
|
||||||
|
|
||||||
@@ -93,9 +84,12 @@ FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command){
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int dsp5680xx_flash_protect_check(struct flash_bank *bank){
|
static int dsp5680xx_flash_protect_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
uint16_t protected = 0;
|
uint16_t protected = 0;
|
||||||
|
|
||||||
retval = dsp5680xx_f_protect_check(bank->target, &protected);
|
retval = dsp5680xx_f_protect_check(bank->target, &protected);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
for (int i = 0; i < HFM_SECTOR_COUNT; i++)
|
for (int i = 0; i < HFM_SECTOR_COUNT; i++)
|
||||||
@@ -118,7 +112,8 @@ static int dsp5680xx_flash_protect_check(struct flash_bank *bank){
|
|||||||
/**
|
/**
|
||||||
* Protection funcionality is not implemented.
|
* Protection funcionality is not implemented.
|
||||||
* The current implementation applies/removes security on the chip.
|
* The current implementation applies/removes security on the chip.
|
||||||
* The chip is effectively secured/unsecured after the first reset following the execution of this function.
|
* The chip is effectively secured/unsecured after the first reset
|
||||||
|
* following the execution of this function.
|
||||||
*
|
*
|
||||||
* @param bank
|
* @param bank
|
||||||
* @param set Apply or remove security on the chip.
|
* @param set Apply or remove security on the chip.
|
||||||
@@ -127,18 +122,32 @@ static int dsp5680xx_flash_protect_check(struct flash_bank *bank){
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, int last){
|
static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
|
||||||
// This applies security to flash module after next reset, it does not actually apply protection (protection refers to undesired access from the core)
|
int last)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This applies security to flash module after next reset, it does
|
||||||
|
* not actually apply protection (protection refers to undesired access from the core)
|
||||||
|
*/
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
retval = dsp5680xx_f_lock(bank->target);
|
retval = dsp5680xx_f_lock(bank->target);
|
||||||
else
|
else {
|
||||||
retval = dsp5680xx_f_unlock(bank->target);
|
retval = dsp5680xx_f_unlock(bank->target);
|
||||||
|
if (retval == ERROR_OK) {
|
||||||
|
/* mark all as erased */
|
||||||
|
for (int i = 0; i <= (HFM_SECTOR_COUNT - 1); i++)
|
||||||
|
/* FM does not recognize it as erased if erased via JTAG. */
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dsp5680xx use word addressing. The "/2" that appear in the following code are a workaround for the fact that OpenOCD uses byte addressing.
|
* The dsp5680xx use word addressing. The "/2" that appear in the following code
|
||||||
|
* are a workaround for the fact that OpenOCD uses byte addressing.
|
||||||
*
|
*
|
||||||
* @param bank
|
* @param bank
|
||||||
* @param buffer Data to write to flash.
|
* @param buffer Data to write to flash.
|
||||||
@@ -147,19 +156,29 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count){
|
static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t * buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if ((offset + count / 2) > bank->size) {
|
if ((offset + count / 2) > bank->size) {
|
||||||
LOG_ERROR("%s: Flash bank cannot fit data.",__FUNCTION__);
|
LOG_ERROR("%s: Flash bank cannot fit data.", __func__);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
if (offset % 2) {
|
if (offset % 2) {
|
||||||
LOG_ERROR("%s: Writing to odd addresses not supported. This chip uses word addressing, Openocd only supports byte addressing. The workaround results in disabling writing to odd byte addresses.",__FUNCTION__);
|
/**
|
||||||
|
* Writing to odd addresses not supported.
|
||||||
|
* This chip uses word addressing, Openocd only supports byte addressing.
|
||||||
|
* The workaround results in disabling writing to odd byte addresses
|
||||||
|
*/
|
||||||
|
LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset/2, count);
|
retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0);
|
||||||
uint32_t addr_word;
|
uint32_t addr_word;
|
||||||
for(addr_word = bank->base + offset/2;addr_word<count/2;addr_word+=(HFM_SECTOR_SIZE/2)){
|
|
||||||
|
for (addr_word = bank->base + offset / 2; addr_word < count / 2;
|
||||||
|
addr_word += (HFM_SECTOR_SIZE / 2)) {
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK)
|
||||||
bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0;
|
bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0;
|
||||||
else
|
else
|
||||||
@@ -168,19 +187,26 @@ static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t *buffer, uint3
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsp5680xx_probe(struct flash_bank *bank){
|
static int dsp5680xx_probe(struct flash_bank *bank)
|
||||||
LOG_DEBUG("%s not implemented",__FUNCTION__);
|
{
|
||||||
|
LOG_DEBUG("%s not implemented", __func__);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf, int buf_size){
|
static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf,
|
||||||
snprintf(buf, buf_size, "\ndsp5680xx flash driver info:\n - Currently only full erase/lock/unlock are implemented. \n - Call with bank==0 and sector 0 to 0.\n - Protect requires arp_init-reset to complete. \n - Before removing protection the master tap must be selected, and arp_init-reset is required to complete unlocking.");
|
int buf_size)
|
||||||
|
{
|
||||||
|
snprintf(buf, buf_size,
|
||||||
|
"\ndsp5680xx flash driver info:\n - See comments in code.");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flash module (FM) on the dsp5680xx supports both individual sector and mass erase of the flash memory.
|
* The flash module (FM) on the dsp5680xx supports both individual sector
|
||||||
* If this function is called with @first == @last == 0 or if @first is the first sector (#0) and @last is the last sector then the mass erase command is executed (much faster than erasing each sector individually).
|
* and mass erase of the flash memory.
|
||||||
|
* If this function is called with @first == @last == 0 or if @first is the
|
||||||
|
* first sector (#0) and @last is the last sector then the mass erase command
|
||||||
|
* is executed (much faster than erasing each sector individually).
|
||||||
*
|
*
|
||||||
* @param bank
|
* @param bank
|
||||||
* @param first
|
* @param first
|
||||||
@@ -188,14 +214,21 @@ static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf, int buf_size
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int dsp5680xx_flash_erase(struct flash_bank * bank, int first, int last){
|
static int dsp5680xx_flash_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
|
retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
|
||||||
|
if ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1))))
|
||||||
|
last = HFM_SECTOR_COUNT - 1;
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK)
|
||||||
for (int i = first; i <= last; i++)
|
for (int i = first; i <= last; i++)
|
||||||
bank->sectors[i].is_erased = 1;
|
bank->sectors[i].is_erased = 1;
|
||||||
else
|
else
|
||||||
// If an error occurred unknown status is set even though some sector could have been correctly erased.
|
/**
|
||||||
|
* If an error occurred unknown status
|
||||||
|
*is set even though some sector could have been correctly erased.
|
||||||
|
*/
|
||||||
for (int i = first; i <= last; i++)
|
for (int i = first; i <= last; i++)
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
return retval;
|
return retval;
|
||||||
@@ -209,10 +242,14 @@ static int dsp5680xx_flash_erase(struct flash_bank * bank, int first, int last){
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int dsp5680xx_flash_erase_check(struct flash_bank * bank){
|
static int dsp5680xx_flash_erase_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
uint8_t erased = 0;
|
uint8_t erased = 0;
|
||||||
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < HFM_SECTOR_COUNT; i++) {
|
for (i = 0; i < HFM_SECTOR_COUNT; i++) {
|
||||||
if (bank->sectors[i].is_erased == -1) {
|
if (bank->sectors[i].is_erased == -1) {
|
||||||
retval = dsp5680xx_f_erase_check(bank->target, &erased, i);
|
retval = dsp5680xx_f_erase_check(bank->target, &erased, i);
|
||||||
@@ -235,11 +272,10 @@ struct flash_driver dsp5680xx_flash = {
|
|||||||
.erase = dsp5680xx_flash_erase,
|
.erase = dsp5680xx_flash_erase,
|
||||||
.protect = dsp5680xx_flash_protect,
|
.protect = dsp5680xx_flash_protect,
|
||||||
.write = dsp5680xx_flash_write,
|
.write = dsp5680xx_flash_write,
|
||||||
//.read = default_flash_read,
|
/* .read = default_flash_read, */
|
||||||
.probe = dsp5680xx_probe,
|
.probe = dsp5680xx_probe,
|
||||||
.auto_probe = dsp5680xx_probe,
|
.auto_probe = dsp5680xx_probe,
|
||||||
.erase_check = dsp5680xx_flash_erase_check,
|
.erase_check = dsp5680xx_flash_erase_check,
|
||||||
.protect_check = dsp5680xx_flash_protect_check,
|
.protect_check = dsp5680xx_flash_protect_check,
|
||||||
.info = dsp5680xx_flash_info
|
.info = dsp5680xx_flash_info
|
||||||
};
|
};
|
||||||
#endif // dsp5680xx_flash.h
|
|
||||||
|
|||||||
@@ -1,443 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
|
||||||
* oyvind.harboe@zylin.com *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "imp.h"
|
|
||||||
#include <target/embeddedice.h>
|
|
||||||
#include <target/algorithm.h>
|
|
||||||
#include <target/image.h>
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static uint32_t ecosflash_get_flash_status(struct flash_bank *bank);
|
|
||||||
static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode);
|
|
||||||
static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
|
|
||||||
static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ecosflash_flash_bank
|
|
||||||
{
|
|
||||||
struct target *target;
|
|
||||||
struct working_area *write_algorithm;
|
|
||||||
struct working_area *erase_check_algorithm;
|
|
||||||
char *driverPath;
|
|
||||||
uint32_t start_address;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int sectorSize = 0x10000;
|
|
||||||
|
|
||||||
char *
|
|
||||||
flash_errmsg(int err);
|
|
||||||
|
|
||||||
#ifndef __ECOS
|
|
||||||
#define FLASH_ERR_OK 0x00 /* No error - operation complete */
|
|
||||||
#define FLASH_ERR_INVALID 0x01 /* Invalid FLASH address */
|
|
||||||
#define FLASH_ERR_ERASE 0x02 /* Error trying to erase */
|
|
||||||
#define FLASH_ERR_LOCK 0x03 /* Error trying to lock/unlock */
|
|
||||||
#define FLASH_ERR_PROGRAM 0x04 /* Error trying to program */
|
|
||||||
#define FLASH_ERR_PROTOCOL 0x05 /* Generic error */
|
|
||||||
#define FLASH_ERR_PROTECT 0x06 /* Device/region is write-protected */
|
|
||||||
#define FLASH_ERR_NOT_INIT 0x07 /* FLASH info not yet initialized */
|
|
||||||
#define FLASH_ERR_HWR 0x08 /* Hardware (configuration?) problem */
|
|
||||||
#define FLASH_ERR_ERASE_SUSPEND 0x09 /* Device is in erase suspend mode */
|
|
||||||
#define FLASH_ERR_PROGRAM_SUSPEND 0x0a /* Device is in in program suspend mode */
|
|
||||||
#define FLASH_ERR_DRV_VERIFY 0x0b /* Driver failed to verify data */
|
|
||||||
#define FLASH_ERR_DRV_TIMEOUT 0x0c /* Driver timed out waiting for device */
|
|
||||||
#define FLASH_ERR_DRV_WRONG_PART 0x0d /* Driver does not support device */
|
|
||||||
#define FLASH_ERR_LOW_VOLTAGE 0x0e /* Not enough juice to complete job */
|
|
||||||
|
|
||||||
char *
|
|
||||||
flash_errmsg(int err)
|
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case FLASH_ERR_OK:
|
|
||||||
return "No error - operation complete";
|
|
||||||
case FLASH_ERR_ERASE_SUSPEND:
|
|
||||||
return "Device is in erase suspend state";
|
|
||||||
case FLASH_ERR_PROGRAM_SUSPEND:
|
|
||||||
return "Device is in program suspend state";
|
|
||||||
case FLASH_ERR_INVALID:
|
|
||||||
return "Invalid FLASH address";
|
|
||||||
case FLASH_ERR_ERASE:
|
|
||||||
return "Error trying to erase";
|
|
||||||
case FLASH_ERR_LOCK:
|
|
||||||
return "Error trying to lock/unlock";
|
|
||||||
case FLASH_ERR_PROGRAM:
|
|
||||||
return "Error trying to program";
|
|
||||||
case FLASH_ERR_PROTOCOL:
|
|
||||||
return "Generic error";
|
|
||||||
case FLASH_ERR_PROTECT:
|
|
||||||
return "Device/region is write-protected";
|
|
||||||
case FLASH_ERR_NOT_INIT:
|
|
||||||
return "FLASH sub-system not initialized";
|
|
||||||
case FLASH_ERR_DRV_VERIFY:
|
|
||||||
return "Data verify failed after operation";
|
|
||||||
case FLASH_ERR_DRV_TIMEOUT:
|
|
||||||
return "Driver timed out waiting for device";
|
|
||||||
case FLASH_ERR_DRV_WRONG_PART:
|
|
||||||
return "Driver does not support device";
|
|
||||||
case FLASH_ERR_LOW_VOLTAGE:
|
|
||||||
return "Device reports low voltage";
|
|
||||||
default:
|
|
||||||
return "Unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
|
|
||||||
*/
|
|
||||||
FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
|
|
||||||
{
|
|
||||||
struct ecosflash_flash_bank *info;
|
|
||||||
|
|
||||||
if (CMD_ARGC < 7)
|
|
||||||
{
|
|
||||||
LOG_WARNING("incomplete flash_bank ecosflash configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = malloc(sizeof(struct ecosflash_flash_bank));
|
|
||||||
if (info == NULL)
|
|
||||||
{
|
|
||||||
LOG_ERROR("no memory for flash bank info");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
bank->driver_priv = info;
|
|
||||||
info->driverPath = strdup(CMD_ARGV[6]);
|
|
||||||
|
|
||||||
/* eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as
|
|
||||||
* a way to improve impedance match between OpenOCD and eCos flash
|
|
||||||
* driver.
|
|
||||||
*/
|
|
||||||
int i = 0;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
bank->num_sectors = bank->size/sectorSize;
|
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
|
||||||
bank->sectors[i].size = sectorSize;
|
|
||||||
offset += bank->sectors[i].size;
|
|
||||||
bank->sectors[i].is_erased = -1;
|
|
||||||
bank->sectors[i].is_protected = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->target = get_target(CMD_ARGV[5]);
|
|
||||||
if (info->target == NULL)
|
|
||||||
{
|
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int loadDriver(struct ecosflash_flash_bank *info)
|
|
||||||
{
|
|
||||||
size_t buf_cnt;
|
|
||||||
size_t image_size;
|
|
||||||
struct image image;
|
|
||||||
|
|
||||||
image.base_address_set = 0;
|
|
||||||
image.start_address_set = 0;
|
|
||||||
struct target *target = info->target;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
|
|
||||||
{
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->start_address = image.start_address;
|
|
||||||
|
|
||||||
image_size = 0x0;
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < image.num_sections; i++)
|
|
||||||
{
|
|
||||||
void *buffer = malloc(image.sections[i].size);
|
|
||||||
if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
|
|
||||||
{
|
|
||||||
free(buffer);
|
|
||||||
image_close(&image);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
|
|
||||||
image_size += buf_cnt;
|
|
||||||
LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "",
|
|
||||||
buf_cnt, image.sections[i].base_address);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
image_close(&image);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int const OFFSET_ERASE = 0x0;
|
|
||||||
static int const OFFSET_ERASE_SIZE = 0x8;
|
|
||||||
static int const OFFSET_FLASH = 0xc;
|
|
||||||
static int const OFFSET_FLASH_SIZE = 0x8;
|
|
||||||
static int const OFFSET_GET_WORKAREA = 0x18;
|
|
||||||
static int const OFFSET_GET_WORKAREA_SIZE = 0x4;
|
|
||||||
|
|
||||||
static int runCode(struct ecosflash_flash_bank *info,
|
|
||||||
uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2,
|
|
||||||
uint32_t *result,
|
|
||||||
/* timeout in ms */
|
|
||||||
int timeout)
|
|
||||||
{
|
|
||||||
struct target *target = info->target;
|
|
||||||
|
|
||||||
struct reg_param reg_params[3];
|
|
||||||
struct arm_algorithm armv4_5_info;
|
|
||||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
|
||||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
|
||||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
|
||||||
|
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
|
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
|
||||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
|
||||||
|
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, r0);
|
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, r1);
|
|
||||||
buf_set_u32(reg_params[2].value, 0, 32, r2);
|
|
||||||
|
|
||||||
int retval;
|
|
||||||
if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
|
||||||
codeStart,
|
|
||||||
codeStop, timeout,
|
|
||||||
&armv4_5_info)) != ERROR_OK)
|
|
||||||
{
|
|
||||||
LOG_ERROR("error executing eCos flash algorithm");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = buf_get_u32(reg_params[0].value, 0, 32);
|
|
||||||
|
|
||||||
destroy_reg_param(®_params[0]);
|
|
||||||
destroy_reg_param(®_params[1]);
|
|
||||||
destroy_reg_param(®_params[2]);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address, uint32_t len)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/
|
|
||||||
|
|
||||||
retval = loadDriver(info);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
uint32_t flashErr;
|
|
||||||
retval = runCode(info,
|
|
||||||
info->start_address + OFFSET_ERASE,
|
|
||||||
info->start_address + OFFSET_ERASE + OFFSET_ERASE_SIZE,
|
|
||||||
address,
|
|
||||||
len,
|
|
||||||
0,
|
|
||||||
&flashErr,
|
|
||||||
timeout
|
|
||||||
);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (flashErr != 0x0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("Flash erase failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32_t address, uint32_t len)
|
|
||||||
{
|
|
||||||
struct target *target = info->target;
|
|
||||||
const int chunk = 8192;
|
|
||||||
int retval = ERROR_OK;
|
|
||||||
int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/
|
|
||||||
|
|
||||||
retval = loadDriver(info);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
uint32_t buffer;
|
|
||||||
retval = runCode(info,
|
|
||||||
info->start_address + OFFSET_GET_WORKAREA,
|
|
||||||
info->start_address + OFFSET_GET_WORKAREA + OFFSET_GET_WORKAREA_SIZE,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&buffer,
|
|
||||||
1000);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < len; i += chunk)
|
|
||||||
{
|
|
||||||
int t = len-i;
|
|
||||||
if (t > chunk)
|
|
||||||
{
|
|
||||||
t = chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
uint32_t flashErr;
|
|
||||||
retval = runCode(info,
|
|
||||||
info->start_address + OFFSET_FLASH,
|
|
||||||
info->start_address + OFFSET_FLASH + OFFSET_FLASH_SIZE,
|
|
||||||
buffer,
|
|
||||||
address + i,
|
|
||||||
t,
|
|
||||||
&flashErr,
|
|
||||||
timeout);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (flashErr != 0x0)
|
|
||||||
{
|
|
||||||
LOG_ERROR("Flash prog failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_probe(struct flash_bank *bank)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
|
|
||||||
{
|
|
||||||
struct ecosflash_flash_bank *info = bank->driver_priv;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (info->target->endianness == TARGET_LITTLE_ENDIAN)
|
|
||||||
{
|
|
||||||
for (i = bank->bus_width; i > 0; i--)
|
|
||||||
{
|
|
||||||
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 1; i <= bank->bus_width; i++)
|
|
||||||
{
|
|
||||||
*cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
|
|
||||||
{
|
|
||||||
uint32_t retval = 0;
|
|
||||||
switch (bank->bus_width)
|
|
||||||
{
|
|
||||||
case 4:
|
|
||||||
retval = address & 0xfffffffc;
|
|
||||||
case 2:
|
|
||||||
retval = address & 0xfffffffe;
|
|
||||||
case 1:
|
|
||||||
retval = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval + bank->base;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int ecosflash_erase(struct flash_bank *bank, int first, int last)
|
|
||||||
{
|
|
||||||
struct flash_bank *c = bank;
|
|
||||||
struct ecosflash_flash_bank *info = bank->driver_priv;
|
|
||||||
return eCosBoard_erase(info, c->base + first*sectorSize, sectorSize*(last-first + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_protect(struct flash_bank *bank, int set, int first, int last)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
|
||||||
{
|
|
||||||
struct ecosflash_flash_bank *info = bank->driver_priv;
|
|
||||||
struct flash_bank *c = bank;
|
|
||||||
return eCosBoard_flash(info, buffer, c->base + offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_protect_check(struct flash_bank *bank)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_info(struct flash_bank *bank, char *buf, int buf_size)
|
|
||||||
{
|
|
||||||
struct ecosflash_flash_bank *info = bank->driver_priv;
|
|
||||||
snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static uint32_t ecosflash_get_flash_status(struct flash_bank *bank)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct flash_driver ecosflash_flash = {
|
|
||||||
.name = "ecosflash",
|
|
||||||
.flash_bank_command = ecosflash_flash_bank_command,
|
|
||||||
.erase = ecosflash_erase,
|
|
||||||
.protect = ecosflash_protect,
|
|
||||||
.write = ecosflash_write,
|
|
||||||
.read = default_flash_read,
|
|
||||||
.probe = ecosflash_probe,
|
|
||||||
.auto_probe = ecosflash_probe,
|
|
||||||
.erase_check = default_flash_blank_check,
|
|
||||||
.protect_check = ecosflash_protect_check,
|
|
||||||
.info = ecosflash_info
|
|
||||||
};
|
|
||||||
985
src/flash/nor/efm32.c
Normal file
985
src/flash/nor/efm32.c
Normal file
@@ -0,0 +1,985 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2008 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2011 by Andreas Fritiofson *
|
||||||
|
* andreas.fritiofson@gmail.com *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2013 by Roman Dmitrienko *
|
||||||
|
* me@iamroman.org *
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <helper/binarybuffer.h>
|
||||||
|
#include <target/algorithm.h>
|
||||||
|
#include <target/armv7m.h>
|
||||||
|
#include <target/cortex_m.h>
|
||||||
|
|
||||||
|
/* keep family IDs in decimal */
|
||||||
|
#define EFM_FAMILY_ID_GECKO 71
|
||||||
|
#define EFM_FAMILY_ID_GIANT_GECKO 72
|
||||||
|
#define EFM_FAMILY_ID_TINY_GECKO 73
|
||||||
|
#define EFM_FAMILY_ID_LEOPARD_GECKO 74
|
||||||
|
|
||||||
|
#define EFM32_FLASH_ERASE_TMO 100
|
||||||
|
#define EFM32_FLASH_WDATAREADY_TMO 100
|
||||||
|
#define EFM32_FLASH_WRITE_TMO 100
|
||||||
|
|
||||||
|
/* size in bytes, not words; must fit all Gecko devices */
|
||||||
|
#define LOCKBITS_PAGE_SZ 512
|
||||||
|
|
||||||
|
#define EFM32_MSC_INFO_BASE 0x0fe00000
|
||||||
|
|
||||||
|
#define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE
|
||||||
|
#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000)
|
||||||
|
#define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000)
|
||||||
|
|
||||||
|
/* PAGE_SIZE is only present in Leopard and Giant Gecko MCUs */
|
||||||
|
#define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7)
|
||||||
|
#define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8)
|
||||||
|
#define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa)
|
||||||
|
#define EFM32_MSC_DI_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc)
|
||||||
|
#define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe)
|
||||||
|
#define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff)
|
||||||
|
|
||||||
|
#define EFM32_MSC_REGBASE 0x400c0000
|
||||||
|
#define EFM32_MSC_WRITECTRL (EFM32_MSC_REGBASE+0x008)
|
||||||
|
#define EFM32_MSC_WRITECTRL_WREN_MASK 0x1
|
||||||
|
#define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+0x00c)
|
||||||
|
#define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1
|
||||||
|
#define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2
|
||||||
|
#define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8
|
||||||
|
#define EFM32_MSC_ADDRB (EFM32_MSC_REGBASE+0x010)
|
||||||
|
#define EFM32_MSC_WDATA (EFM32_MSC_REGBASE+0x018)
|
||||||
|
#define EFM32_MSC_STATUS (EFM32_MSC_REGBASE+0x01c)
|
||||||
|
#define EFM32_MSC_STATUS_BUSY_MASK 0x1
|
||||||
|
#define EFM32_MSC_STATUS_LOCKED_MASK 0x2
|
||||||
|
#define EFM32_MSC_STATUS_INVADDR_MASK 0x4
|
||||||
|
#define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8
|
||||||
|
#define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10
|
||||||
|
#define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20
|
||||||
|
#define EFM32_MSC_LOCK (EFM32_MSC_REGBASE+0x03c)
|
||||||
|
#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
|
||||||
|
|
||||||
|
struct efm32x_flash_bank {
|
||||||
|
int probed;
|
||||||
|
uint8_t lb_page[LOCKBITS_PAGE_SZ];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct efm32_info {
|
||||||
|
uint16_t flash_sz_kib;
|
||||||
|
uint16_t ram_sz_kib;
|
||||||
|
uint16_t part_num;
|
||||||
|
uint8_t part_family;
|
||||||
|
uint8_t prod_rev;
|
||||||
|
uint16_t page_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int efm32x_write(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count);
|
||||||
|
|
||||||
|
static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz)
|
||||||
|
{
|
||||||
|
return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz)
|
||||||
|
{
|
||||||
|
return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum)
|
||||||
|
{
|
||||||
|
return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily)
|
||||||
|
{
|
||||||
|
return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev)
|
||||||
|
{
|
||||||
|
return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_read_info(struct flash_bank *bank,
|
||||||
|
struct efm32_info *efm32_info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t cpuid = 0;
|
||||||
|
|
||||||
|
memset(efm32_info, 0, sizeof(struct efm32_info));
|
||||||
|
|
||||||
|
ret = target_read_u32(bank->target, CPUID, &cpuid);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (((cpuid >> 4) & 0xfff) == 0xc23) {
|
||||||
|
/* Cortex M3 device */
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Target is not CortexM3");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib));
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib));
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_get_part_num(bank, &(efm32_info->part_num));
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_get_part_family(bank, &(efm32_info->part_family));
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev));
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (EFM_FAMILY_ID_GECKO == efm32_info->part_family ||
|
||||||
|
EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
|
||||||
|
efm32_info->page_size = 512;
|
||||||
|
else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
|
||||||
|
EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
|
||||||
|
if (efm32_info->prod_rev >= 18) {
|
||||||
|
uint8_t pg_size = 0;
|
||||||
|
ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
|
||||||
|
&pg_size);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
efm32_info->page_size = (1 << ((pg_size+10) & 0xff));
|
||||||
|
} else {
|
||||||
|
/* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid
|
||||||
|
for MCUs with PROD_REV < 18 */
|
||||||
|
if (efm32_info->flash_sz_kib < 512)
|
||||||
|
efm32_info->page_size = 2048;
|
||||||
|
else
|
||||||
|
efm32_info->page_size = 4096;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((2048 != efm32_info->page_size) &&
|
||||||
|
(4096 != efm32_info->page_size)) {
|
||||||
|
LOG_ERROR("Invalid page size %u", efm32_info->page_size);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Unknown MCU family %d", efm32_info->part_family);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flash bank efm32 <base> <size> 0 0 <target#>
|
||||||
|
*/
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 6)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
efm32x_info = malloc(sizeof(struct efm32x_flash_bank));
|
||||||
|
|
||||||
|
bank->driver_priv = efm32x_info;
|
||||||
|
efm32x_info->probed = 0;
|
||||||
|
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set or reset given bits in a register */
|
||||||
|
static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg,
|
||||||
|
uint32_t bitmask, int set)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t reg_val = 0;
|
||||||
|
|
||||||
|
ret = target_read_u32(bank->target, reg, ®_val);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (set)
|
||||||
|
reg_val |= bitmask;
|
||||||
|
else
|
||||||
|
reg_val &= ~bitmask;
|
||||||
|
|
||||||
|
return target_write_u32(bank->target, reg, reg_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_set_wren(struct flash_bank *bank, int write_enable)
|
||||||
|
{
|
||||||
|
return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL,
|
||||||
|
EFM32_MSC_WRITECTRL_WREN_MASK, write_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_msc_lock(struct flash_bank *bank, int lock)
|
||||||
|
{
|
||||||
|
return target_write_u32(bank->target, EFM32_MSC_LOCK,
|
||||||
|
(lock ? 0 : EFM32_MSC_LOCK_LOCKKEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_wait_status(struct flash_bank *bank, int timeout,
|
||||||
|
uint32_t wait_mask, int wait_for_set)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t status = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
break;
|
||||||
|
|
||||||
|
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
||||||
|
|
||||||
|
if (((status & wait_mask) == 0) && (0 == wait_for_set))
|
||||||
|
break;
|
||||||
|
else if (((status & wait_mask) != 0) && wait_for_set)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (timeout-- <= 0) {
|
||||||
|
LOG_ERROR("timed out waiting for MSC status");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
alive_sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & EFM32_MSC_STATUS_ERASEABORTED_MASK)
|
||||||
|
LOG_WARNING("page erase was aborted");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
|
||||||
|
{
|
||||||
|
/* this function DOES NOT set WREN; must be set already */
|
||||||
|
/* 1. write address to ADDRB
|
||||||
|
2. write LADDRIM
|
||||||
|
3. check status (INVADDR, LOCKED)
|
||||||
|
4. write ERASEPAGE
|
||||||
|
5. wait until !STATUS_BUSY
|
||||||
|
*/
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t status = 0;
|
||||||
|
|
||||||
|
LOG_DEBUG("erasing flash page at 0x%08x", addr);
|
||||||
|
|
||||||
|
ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
|
||||||
|
EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
LOG_DEBUG("status 0x%x", status);
|
||||||
|
|
||||||
|
if (status & EFM32_MSC_STATUS_LOCKED_MASK) {
|
||||||
|
LOG_ERROR("Page is locked");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
} else if (status & EFM32_MSC_STATUS_INVADDR_MASK) {
|
||||||
|
LOG_ERROR("Invalid address 0x%x", addr);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
|
||||||
|
EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO,
|
||||||
|
EFM32_MSC_STATUS_BUSY_MASK, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int i = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (TARGET_HALTED != target->state) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
efm32x_msc_lock(bank, 0);
|
||||||
|
ret = efm32x_set_wren(bank, 1);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to enable MSC write");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++) {
|
||||||
|
ret = efm32x_erase_page(bank, bank->sectors[i].offset);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
LOG_ERROR("Failed to erase page %d", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_set_wren(bank, 0);
|
||||||
|
efm32x_msc_lock(bank, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_read_lock_data(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int i = 0;
|
||||||
|
int data_size = 0;
|
||||||
|
uint32_t *ptr = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
assert(!(bank->num_sectors & 0x1f));
|
||||||
|
|
||||||
|
data_size = bank->num_sectors / 8; /* number of data bytes */
|
||||||
|
data_size /= 4; /* ...and data dwords */
|
||||||
|
|
||||||
|
ptr = (uint32_t *)efm32x_info->lb_page;
|
||||||
|
|
||||||
|
for (i = 0; i < data_size; i++, ptr++) {
|
||||||
|
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read PLW %d", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* also, read ULW, DLW and MLW */
|
||||||
|
|
||||||
|
/* ULW, word 126 */
|
||||||
|
ptr = ((uint32_t *)efm32x_info->lb_page) + 126;
|
||||||
|
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read ULW");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DLW, word 127 */
|
||||||
|
ptr = ((uint32_t *)efm32x_info->lb_page) + 127;
|
||||||
|
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read DLW");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MLW, word 125, present in GG and LG */
|
||||||
|
ptr = ((uint32_t *)efm32x_info->lb_page) + 125;
|
||||||
|
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read MLW");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_write_lock_data(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to erase LB page");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return efm32x_write(bank, efm32x_info->lb_page, EFM32_MSC_LOCK_BITS,
|
||||||
|
LOCKBITS_PAGE_SZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_get_page_lock(struct flash_bank *bank, size_t page)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
uint32_t dw = ((uint32_t *)efm32x_info->lb_page)[page >> 5];
|
||||||
|
uint32_t mask = 0;
|
||||||
|
|
||||||
|
mask = 1 << (page & 0x1f);
|
||||||
|
|
||||||
|
return (dw & mask) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
uint32_t *dw = &((uint32_t *)efm32x_info->lb_page)[page >> 5];
|
||||||
|
uint32_t mask = 0;
|
||||||
|
|
||||||
|
mask = 1 << (page & 0x1f);
|
||||||
|
|
||||||
|
if (!set)
|
||||||
|
*dw |= mask;
|
||||||
|
else
|
||||||
|
*dw &= ~mask;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int i = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!set) {
|
||||||
|
LOG_ERROR("Erase device data to reset page locks");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++) {
|
||||||
|
ret = efm32x_set_page_lock(bank, i, set);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to set lock on page %d", i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_write_lock_data(bank);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to write LB page");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint32_t buffer_size = 16384;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
struct working_area *source;
|
||||||
|
uint32_t address = bank->base + offset;
|
||||||
|
struct reg_param reg_params[5];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
int ret = ERROR_OK;
|
||||||
|
|
||||||
|
/* see contrib/loaders/flash/efm32.S for src */
|
||||||
|
static const uint8_t efm32x_flash_write_code[] = {
|
||||||
|
/* #define EFM32_MSC_WRITECTRL_OFFSET 0x008 */
|
||||||
|
/* #define EFM32_MSC_WRITECMD_OFFSET 0x00c */
|
||||||
|
/* #define EFM32_MSC_ADDRB_OFFSET 0x010 */
|
||||||
|
/* #define EFM32_MSC_WDATA_OFFSET 0x018 */
|
||||||
|
/* #define EFM32_MSC_STATUS_OFFSET 0x01c */
|
||||||
|
/* #define EFM32_MSC_LOCK_OFFSET 0x03c */
|
||||||
|
|
||||||
|
0x15, 0x4e, /* ldr r6, =#0x1b71 */
|
||||||
|
0xc6, 0x63, /* str r6, [r0, #EFM32_MSC_LOCK_OFFSET] */
|
||||||
|
0x01, 0x26, /* movs r6, #1 */
|
||||||
|
0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */
|
||||||
|
|
||||||
|
/* wait_fifo: */
|
||||||
|
0x16, 0x68, /* ldr r6, [r2, #0] */
|
||||||
|
0x00, 0x2e, /* cmp r6, #0 */
|
||||||
|
0x22, 0xd0, /* beq exit */
|
||||||
|
0x55, 0x68, /* ldr r5, [r2, #4] */
|
||||||
|
0xb5, 0x42, /* cmp r5, r6 */
|
||||||
|
0xf9, 0xd0, /* beq wait_fifo */
|
||||||
|
|
||||||
|
0x04, 0x61, /* str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] */
|
||||||
|
0x01, 0x26, /* movs r6, #1 */
|
||||||
|
0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */
|
||||||
|
0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
|
||||||
|
0x06, 0x27, /* movs r7, #6 */
|
||||||
|
0x3e, 0x42, /* tst r6, r7 */
|
||||||
|
0x16, 0xd1, /* bne error */
|
||||||
|
|
||||||
|
/* wait_wdataready: */
|
||||||
|
0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
|
||||||
|
0x08, 0x27, /* movs r7, #8 */
|
||||||
|
0x3e, 0x42, /* tst r6, r7 */
|
||||||
|
0xfb, 0xd0, /* beq wait_wdataready */
|
||||||
|
|
||||||
|
0x2e, 0x68, /* ldr r6, [r5] */
|
||||||
|
0x86, 0x61, /* str r6, [r0, #EFM32_MSC_WDATA_OFFSET] */
|
||||||
|
0x08, 0x26, /* movs r6, #8 */
|
||||||
|
0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */
|
||||||
|
|
||||||
|
0x04, 0x35, /* adds r5, #4 */
|
||||||
|
0x04, 0x34, /* adds r4, #4 */
|
||||||
|
|
||||||
|
/* busy: */
|
||||||
|
0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
|
||||||
|
0x01, 0x27, /* movs r7, #1 */
|
||||||
|
0x3e, 0x42, /* tst r6, r7 */
|
||||||
|
0xfb, 0xd1, /* bne busy */
|
||||||
|
|
||||||
|
0x9d, 0x42, /* cmp r5, r3 */
|
||||||
|
0x01, 0xd3, /* bcc no_wrap */
|
||||||
|
0x15, 0x46, /* mov r5, r2 */
|
||||||
|
0x08, 0x35, /* adds r5, #8 */
|
||||||
|
|
||||||
|
/* no_wrap: */
|
||||||
|
0x55, 0x60, /* str r5, [r2, #4] */
|
||||||
|
0x01, 0x39, /* subs r1, r1, #1 */
|
||||||
|
0x00, 0x29, /* cmp r1, #0 */
|
||||||
|
0x02, 0xd0, /* beq exit */
|
||||||
|
0xdb, 0xe7, /* b wait_fifo */
|
||||||
|
|
||||||
|
/* error: */
|
||||||
|
0x00, 0x20, /* movs r0, #0 */
|
||||||
|
0x50, 0x60, /* str r0, [r2, #4] */
|
||||||
|
|
||||||
|
/* exit: */
|
||||||
|
0x30, 0x46, /* mov r0, r6 */
|
||||||
|
0x00, 0xbe, /* bkpt #0 */
|
||||||
|
|
||||||
|
/* LOCKKEY */
|
||||||
|
0x71, 0x1b, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/* flash write code */
|
||||||
|
if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code),
|
||||||
|
&write_algorithm) != ERROR_OK) {
|
||||||
|
LOG_WARNING("no working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = target_write_buffer(target, write_algorithm->address,
|
||||||
|
sizeof(efm32x_flash_write_code),
|
||||||
|
(uint8_t *)efm32x_flash_write_code);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* memory buffer */
|
||||||
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
|
||||||
|
buffer_size /= 2;
|
||||||
|
buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
|
||||||
|
if (buffer_size <= 256) {
|
||||||
|
/* we already allocated the writing code, but failed to get a
|
||||||
|
* buffer, free the algorithm */
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
|
|
||||||
|
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
|
||||||
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (word-32bit) */
|
||||||
|
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */
|
||||||
|
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */
|
||||||
|
init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
|
||||||
|
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE);
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, source->address);
|
||||||
|
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
|
||||||
|
buf_set_u32(reg_params[4].value, 0, 32, address);
|
||||||
|
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
|
ret = target_run_flash_async_algorithm(target, buf, count, 4,
|
||||||
|
0, NULL,
|
||||||
|
5, reg_params,
|
||||||
|
source->address, source->size,
|
||||||
|
write_algorithm->address, 0,
|
||||||
|
&armv7m_info);
|
||||||
|
|
||||||
|
if (ret == ERROR_FLASH_OPERATION_FAILED) {
|
||||||
|
LOG_ERROR("flash write failed at address 0x%"PRIx32,
|
||||||
|
buf_get_u32(reg_params[4].value, 0, 32));
|
||||||
|
|
||||||
|
if (buf_get_u32(reg_params[0].value, 0, 32) &
|
||||||
|
EFM32_MSC_STATUS_LOCKED_MASK) {
|
||||||
|
LOG_ERROR("flash memory write protected");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_get_u32(reg_params[0].value, 0, 32) &
|
||||||
|
EFM32_MSC_STATUS_INVADDR_MASK) {
|
||||||
|
LOG_ERROR("invalid flash memory write address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target_free_working_area(target, source);
|
||||||
|
target_free_working_area(target, write_algorithm);
|
||||||
|
|
||||||
|
destroy_reg_param(®_params[0]);
|
||||||
|
destroy_reg_param(®_params[1]);
|
||||||
|
destroy_reg_param(®_params[2]);
|
||||||
|
destroy_reg_param(®_params[3]);
|
||||||
|
destroy_reg_param(®_params[4]);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
|
||||||
|
uint32_t val)
|
||||||
|
{
|
||||||
|
/* this function DOES NOT set WREN; must be set already */
|
||||||
|
/* 1. write address to ADDRB
|
||||||
|
2. write LADDRIM
|
||||||
|
3. check status (INVADDR, LOCKED)
|
||||||
|
4. wait for WDATAREADY
|
||||||
|
5. write data to WDATA
|
||||||
|
6. write WRITECMD_WRITEONCE to WRITECMD
|
||||||
|
7. wait until !STATUS_BUSY
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: EFM32G ref states (7.3.2) that writes should be
|
||||||
|
* performed twice per dword */
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t status = 0;
|
||||||
|
|
||||||
|
/* if not called, GDB errors will be reported during large writes */
|
||||||
|
keep_alive();
|
||||||
|
|
||||||
|
ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD,
|
||||||
|
EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
LOG_DEBUG("status 0x%x", status);
|
||||||
|
|
||||||
|
if (status & EFM32_MSC_STATUS_LOCKED_MASK) {
|
||||||
|
LOG_ERROR("Page is locked");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
} else if (status & EFM32_MSC_STATUS_INVADDR_MASK) {
|
||||||
|
LOG_ERROR("Invalid address 0x%x", addr);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO,
|
||||||
|
EFM32_MSC_STATUS_WDATAREADY_MASK, 1);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Wait for WDATAREADY failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("WDATA write failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD,
|
||||||
|
EFM32_MSC_WRITECMD_WRITEONCE_MASK);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("WRITECMD write failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_wait_status(bank, EFM32_FLASH_WRITE_TMO,
|
||||||
|
EFM32_MSC_STATUS_BUSY_MASK, 0);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Wait for BUSY failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_write(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint8_t *new_buffer = NULL;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset & 0x3) {
|
||||||
|
LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte "
|
||||||
|
"alignment", offset);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count & 0x3) {
|
||||||
|
uint32_t old_count = count;
|
||||||
|
count = (old_count | 3) + 1;
|
||||||
|
new_buffer = malloc(count);
|
||||||
|
if (new_buffer == NULL) {
|
||||||
|
LOG_ERROR("odd number of bytes to write and no memory "
|
||||||
|
"for padding buffer");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
LOG_INFO("odd number of bytes to write (%d), extending to %d "
|
||||||
|
"and padding with 0xff", old_count, count);
|
||||||
|
memset(buffer, 0xff, count);
|
||||||
|
buffer = memcpy(new_buffer, buffer, old_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t words_remaining = count / 4;
|
||||||
|
int retval, retval2;
|
||||||
|
|
||||||
|
/* unlock flash registers */
|
||||||
|
efm32x_msc_lock(bank, 0);
|
||||||
|
retval = efm32x_set_wren(bank, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* try using a block write */
|
||||||
|
retval = efm32x_write_block(bank, buffer, offset, words_remaining);
|
||||||
|
|
||||||
|
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
|
||||||
|
/* if block write failed (no sufficient working area),
|
||||||
|
* we use normal (slow) single word accesses */
|
||||||
|
LOG_WARNING("couldn't use block writes, falling back to single "
|
||||||
|
"memory accesses");
|
||||||
|
|
||||||
|
while (words_remaining > 0) {
|
||||||
|
uint32_t value;
|
||||||
|
memcpy(&value, buffer, sizeof(uint32_t));
|
||||||
|
|
||||||
|
retval = efm32x_write_word(bank, offset, value);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto reset_pg_and_lock;
|
||||||
|
|
||||||
|
words_remaining--;
|
||||||
|
buffer += 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_pg_and_lock:
|
||||||
|
retval2 = efm32x_set_wren(bank, 0);
|
||||||
|
efm32x_msc_lock(bank, 1);
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
retval = retval2;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (new_buffer)
|
||||||
|
free(new_buffer);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
struct efm32_info efm32_mcu_info;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
uint32_t base_address = 0x00000000;
|
||||||
|
|
||||||
|
efm32x_info->probed = 0;
|
||||||
|
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
|
||||||
|
|
||||||
|
ret = efm32x_read_info(bank, &efm32_mcu_info);
|
||||||
|
if (ERROR_OK != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (efm32_mcu_info.part_family) {
|
||||||
|
case EFM_FAMILY_ID_GECKO:
|
||||||
|
LOG_INFO("Gecko MCU detected");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_GIANT_GECKO:
|
||||||
|
LOG_INFO("Giant Gecko MCU detected");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_TINY_GECKO:
|
||||||
|
LOG_INFO("Tiny Gecko MCU detected");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_LEOPARD_GECKO:
|
||||||
|
LOG_INFO("Leopard Gecko MCU detected");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unsupported MCU family %d",
|
||||||
|
efm32_mcu_info.part_family);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("flash size = %dkbytes", efm32_mcu_info.flash_sz_kib);
|
||||||
|
LOG_INFO("flash page size = %dbytes", efm32_mcu_info.page_size);
|
||||||
|
|
||||||
|
assert(0 != efm32_mcu_info.page_size);
|
||||||
|
|
||||||
|
int num_pages = efm32_mcu_info.flash_sz_kib * 1024 /
|
||||||
|
efm32_mcu_info.page_size;
|
||||||
|
|
||||||
|
assert(num_pages > 0);
|
||||||
|
|
||||||
|
if (bank->sectors) {
|
||||||
|
free(bank->sectors);
|
||||||
|
bank->sectors = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->base = base_address;
|
||||||
|
bank->size = (num_pages * efm32_mcu_info.page_size);
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
ret = efm32x_read_lock_data(bank);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read LB data");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||||
|
|
||||||
|
for (i = 0; i < num_pages; i++) {
|
||||||
|
bank->sectors[i].offset = i * efm32_mcu_info.page_size;
|
||||||
|
bank->sectors[i].size = efm32_mcu_info.page_size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
efm32x_info->probed = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_auto_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||||
|
if (efm32x_info->probed)
|
||||||
|
return ERROR_OK;
|
||||||
|
return efm32x_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int efm32x_protect_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = efm32x_read_lock_data(bank);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read LB data");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(NULL != bank->sectors);
|
||||||
|
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
struct efm32_info info;
|
||||||
|
int ret = 0;
|
||||||
|
int printed = 0;
|
||||||
|
|
||||||
|
ret = efm32x_read_info(bank, &info);
|
||||||
|
if (ERROR_OK != ret) {
|
||||||
|
LOG_ERROR("Failed to read EFM32 info");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, "EFM32 ");
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
if (0 >= buf_size)
|
||||||
|
return ERROR_BUF_TOO_SMALL;
|
||||||
|
|
||||||
|
switch (info.part_family) {
|
||||||
|
case EFM_FAMILY_ID_GECKO:
|
||||||
|
printed = snprintf(buf, buf_size, "Gecko");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_GIANT_GECKO:
|
||||||
|
printed = snprintf(buf, buf_size, "Giant Gecko");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_TINY_GECKO:
|
||||||
|
printed = snprintf(buf, buf_size, "Tiny Gecko");
|
||||||
|
break;
|
||||||
|
case EFM_FAMILY_ID_LEOPARD_GECKO:
|
||||||
|
printed = snprintf(buf, buf_size, "Leopard Gecko");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
if (0 >= buf_size)
|
||||||
|
return ERROR_BUF_TOO_SMALL;
|
||||||
|
|
||||||
|
printed = snprintf(buf, buf_size, " - Rev: %d", info.prod_rev);
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
|
||||||
|
if (0 >= buf_size)
|
||||||
|
return ERROR_BUF_TOO_SMALL;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct command_registration efm32x_exec_command_handlers[] = {
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration efm32x_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "efm32",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "efm32 flash command group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = efm32x_exec_command_handlers,
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flash_driver efm32_flash = {
|
||||||
|
.name = "efm32",
|
||||||
|
.commands = efm32x_command_handlers,
|
||||||
|
.flash_bank_command = efm32x_flash_bank_command,
|
||||||
|
.erase = efm32x_erase,
|
||||||
|
.protect = efm32x_protect,
|
||||||
|
.write = efm32x_write,
|
||||||
|
.read = default_flash_read,
|
||||||
|
.probe = efm32x_probe,
|
||||||
|
.auto_probe = efm32x_auto_probe,
|
||||||
|
.erase_check = default_flash_blank_check,
|
||||||
|
.protect_check = efm32x_protect_check,
|
||||||
|
.info = get_efm32x_info,
|
||||||
|
};
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -79,17 +80,14 @@
|
|||||||
#define KEY1 0x45670123
|
#define KEY1 0x45670123
|
||||||
#define KEY2 0xCDEF89AB
|
#define KEY2 0xCDEF89AB
|
||||||
|
|
||||||
struct em357_options
|
struct em357_options {
|
||||||
{
|
|
||||||
uint16_t RDP;
|
uint16_t RDP;
|
||||||
uint16_t user_options;
|
uint16_t user_options;
|
||||||
uint16_t protection[3];
|
uint16_t protection[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct em357_flash_bank
|
struct em357_flash_bank {
|
||||||
{
|
|
||||||
struct em357_options option_bytes;
|
struct em357_options option_bytes;
|
||||||
struct working_area *write_algorithm;
|
|
||||||
int ppage_size;
|
int ppage_size;
|
||||||
int probed;
|
int probed;
|
||||||
};
|
};
|
||||||
@@ -103,15 +101,11 @@ FLASH_BANK_COMMAND_HANDLER(em357_flash_bank_command)
|
|||||||
struct em357_flash_bank *em357_info;
|
struct em357_flash_bank *em357_info;
|
||||||
|
|
||||||
if (CMD_ARGC < 6)
|
if (CMD_ARGC < 6)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank em357 configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
em357_info = malloc(sizeof(struct em357_flash_bank));
|
em357_info = malloc(sizeof(struct em357_flash_bank));
|
||||||
bank->driver_priv = em357_info;
|
bank->driver_priv = em357_info;
|
||||||
|
|
||||||
em357_info->write_algorithm = NULL;
|
|
||||||
em357_info->probed = 0;
|
em357_info->probed = 0;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -130,37 +124,32 @@ static int em357_wait_status_busy(struct flash_bank *bank, int timeout)
|
|||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
/* wait for busy to clear */
|
/* wait for busy to clear */
|
||||||
for (;;)
|
for (;; ) {
|
||||||
{
|
|
||||||
retval = em357_get_flash_status(bank, &status);
|
retval = em357_get_flash_status(bank, &status);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
||||||
if ((status & FLASH_BSY) == 0)
|
if ((status & FLASH_BSY) == 0)
|
||||||
break;
|
break;
|
||||||
if (timeout-- <= 0)
|
if (timeout-- <= 0) {
|
||||||
{
|
|
||||||
LOG_ERROR("timed out waiting for flash");
|
LOG_ERROR("timed out waiting for flash");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & FLASH_WRPRTERR)
|
if (status & FLASH_WRPRTERR) {
|
||||||
{
|
|
||||||
LOG_ERROR("em357 device protected");
|
LOG_ERROR("em357 device protected");
|
||||||
retval = ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & FLASH_PGERR)
|
if (status & FLASH_PGERR) {
|
||||||
{
|
|
||||||
LOG_ERROR("em357 device programming failed");
|
LOG_ERROR("em357 device programming failed");
|
||||||
retval = ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear but report errors */
|
/* Clear but report errors */
|
||||||
if (status & (FLASH_WRPRTERR | FLASH_PGERR))
|
if (status & (FLASH_WRPRTERR | FLASH_PGERR)) {
|
||||||
{
|
|
||||||
/* If this operation fails, we ignore it and report the original
|
/* If this operation fails, we ignore it and report the original
|
||||||
* retval
|
* retval
|
||||||
*/
|
*/
|
||||||
@@ -331,8 +320,7 @@ static int em357_protect_check(struct flash_bank *bank)
|
|||||||
int num_bits;
|
int num_bits;
|
||||||
int set;
|
int set;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
@@ -345,8 +333,7 @@ static int em357_protect_check(struct flash_bank *bank)
|
|||||||
/* each protection bit is for 4 * 2K pages */
|
/* each protection bit is for 4 * 2K pages */
|
||||||
num_bits = (bank->num_sectors / em357_info->ppage_size);
|
num_bits = (bank->num_sectors / em357_info->ppage_size);
|
||||||
|
|
||||||
for (i = 0; i < num_bits; i++)
|
for (i = 0; i < num_bits; i++) {
|
||||||
{
|
|
||||||
set = 1;
|
set = 1;
|
||||||
if (protection & (1 << i))
|
if (protection & (1 << i))
|
||||||
set = 0;
|
set = 0;
|
||||||
@@ -363,16 +350,16 @@ static int em357_erase(struct flash_bank *bank, int first, int last)
|
|||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((first == 0) && (last == (bank->num_sectors - 1)))
|
if ((first == 0) && (last == (bank->num_sectors - 1)))
|
||||||
{
|
|
||||||
return em357_mass_erase(bank);
|
return em357_mass_erase(bank);
|
||||||
}
|
|
||||||
|
/* Enable FPEC clock */
|
||||||
|
target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
||||||
|
|
||||||
/* unlock flash registers */
|
/* unlock flash registers */
|
||||||
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
@@ -382,8 +369,7 @@ static int em357_erase(struct flash_bank *bank, int first, int last)
|
|||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
for (i = first; i <= last; i++)
|
for (i = first; i <= last; i++) {
|
||||||
{
|
|
||||||
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER);
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
@@ -420,20 +406,17 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
|
|
||||||
em357_info = bank->driver_priv;
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((first % em357_info->ppage_size) != 0)
|
if ((first % em357_info->ppage_size) != 0) {
|
||||||
{
|
|
||||||
LOG_WARNING("aligned start protect sector to a %d sector boundary",
|
LOG_WARNING("aligned start protect sector to a %d sector boundary",
|
||||||
em357_info->ppage_size);
|
em357_info->ppage_size);
|
||||||
first = first - (first % em357_info->ppage_size);
|
first = first - (first % em357_info->ppage_size);
|
||||||
}
|
}
|
||||||
if (((last + 1) % em357_info->ppage_size) != 0)
|
if (((last + 1) % em357_info->ppage_size) != 0) {
|
||||||
{
|
|
||||||
LOG_WARNING("aligned end protect sector to a %d sector boundary",
|
LOG_WARNING("aligned end protect sector to a %d sector boundary",
|
||||||
em357_info->ppage_size);
|
em357_info->ppage_size);
|
||||||
last++;
|
last++;
|
||||||
@@ -450,8 +433,7 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
prot_reg[1] = (uint16_t)(protection >> 8);
|
prot_reg[1] = (uint16_t)(protection >> 8);
|
||||||
prot_reg[2] = (uint16_t)(protection >> 16);
|
prot_reg[2] = (uint16_t)(protection >> 16);
|
||||||
|
|
||||||
for (i = first; i <= last; i++)
|
for (i = first; i <= last; i++) {
|
||||||
{
|
|
||||||
reg = (i / em357_info->ppage_size) / 8;
|
reg = (i / em357_info->ppage_size) / 8;
|
||||||
bit = (i / em357_info->ppage_size) - (reg * 8);
|
bit = (i / em357_info->ppage_size) - (reg * 8);
|
||||||
|
|
||||||
@@ -462,7 +444,8 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
prot_reg[reg] |= (1 << bit);
|
prot_reg[reg] |= (1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status = em357_erase_options(bank)) != ERROR_OK)
|
status = em357_erase_options(bank);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
em357_info->option_bytes.protection[0] = prot_reg[0];
|
em357_info->option_bytes.protection[0] = prot_reg[0];
|
||||||
@@ -475,9 +458,9 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||||
uint32_t offset, uint32_t count)
|
uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
struct em357_flash_bank *em357_info = bank->driver_priv;
|
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
uint32_t buffer_size = 16384;
|
uint32_t buffer_size = 16384;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
struct working_area *source;
|
struct working_area *source;
|
||||||
uint32_t address = bank->base + offset;
|
uint32_t address = bank->base + offset;
|
||||||
struct reg_param reg_params[4];
|
struct reg_param reg_params[4];
|
||||||
@@ -488,18 +471,20 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
* a modified *_FLASH_BASE */
|
* a modified *_FLASH_BASE */
|
||||||
|
|
||||||
static const uint8_t em357_flash_write_code[] = {
|
static const uint8_t em357_flash_write_code[] = {
|
||||||
/* #define EM357_FLASH_CR_OFFSET 0x10 */
|
/* #define EM357_FLASH_CR_OFFSET 0x10
|
||||||
/* #define EM357_FLASH_SR_OFFSET 0x0C */
|
* #define EM357_FLASH_SR_OFFSET 0x0C
|
||||||
/* write: */
|
* write: */
|
||||||
0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */
|
0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */
|
||||||
0x1c, 0x44, /* add r4, r3 */
|
0x1c, 0x44, /* add r4, r3 */
|
||||||
/* write_half_word: */
|
/* write_half_word: */
|
||||||
0x01, 0x23, /* movs r3, #0x01 */
|
0x01, 0x23, /* movs r3, #0x01 */
|
||||||
0x23, 0x61, /* str r3, [r4, #EM357_FLASH_CR_OFFSET] */
|
0x23, 0x61, /* str r3, [r4,
|
||||||
|
*#EM357_FLASH_CR_OFFSET] */
|
||||||
0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
|
0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
|
||||||
0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
|
0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
|
||||||
/* busy: */
|
/* busy: */
|
||||||
0xe3, 0x68, /* ldr r3, [r4, #EM357_FLASH_SR_OFFSET] */
|
0xe3, 0x68, /* ldr r3, [r4,
|
||||||
|
*#EM357_FLASH_SR_OFFSET] */
|
||||||
0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
|
0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
|
||||||
0xfb, 0xd0, /* beq busy */
|
0xfb, 0xd0, /* beq busy */
|
||||||
0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
|
0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
|
||||||
@@ -513,48 +498,45 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
|
|
||||||
/* flash write code */
|
/* flash write code */
|
||||||
if (target_alloc_working_area(target, sizeof(em357_flash_write_code),
|
if (target_alloc_working_area(target, sizeof(em357_flash_write_code),
|
||||||
&em357_info->write_algorithm) != ERROR_OK)
|
&write_algorithm) != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_WARNING("no working area available, can't do block memory writes");
|
LOG_WARNING("no working area available, can't do block memory writes");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
};
|
}
|
||||||
|
;
|
||||||
|
|
||||||
if ((retval = target_write_buffer(target, em357_info->write_algorithm->address,
|
retval = target_write_buffer(target, write_algorithm->address,
|
||||||
sizeof(em357_flash_write_code),
|
sizeof(em357_flash_write_code), (uint8_t *)em357_flash_write_code);
|
||||||
(uint8_t*)em357_flash_write_code)) != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* memory buffer */
|
/* memory buffer */
|
||||||
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
|
||||||
{
|
|
||||||
buffer_size /= 2;
|
buffer_size /= 2;
|
||||||
if (buffer_size <= 256)
|
if (buffer_size <= 256) {
|
||||||
{
|
/* we already allocated the writing code, but failed to get a
|
||||||
/* if we already allocated the writing code, but failed to get a
|
|
||||||
* buffer, free the algorithm */
|
* buffer, free the algorithm */
|
||||||
if (em357_info->write_algorithm)
|
target_free_working_area(target, write_algorithm);
|
||||||
target_free_working_area(target, em357_info->write_algorithm);
|
|
||||||
|
|
||||||
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
LOG_WARNING(
|
||||||
|
"no large enough working area available, can't do block memory writes");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
armv7m_info.core_mode = ARMV7M_MODE_ANY;
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||||
init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT);
|
init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT);
|
||||||
|
|
||||||
while (count > 0)
|
while (count > 0) {
|
||||||
{
|
|
||||||
uint32_t thisrun_count = (count > (buffer_size / 2)) ?
|
uint32_t thisrun_count = (count > (buffer_size / 2)) ?
|
||||||
(buffer_size / 2) : count;
|
(buffer_size / 2) : count;
|
||||||
|
|
||||||
if ((retval = target_write_buffer(target, source->address,
|
retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer);
|
||||||
thisrun_count * 2, buffer)) != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||||
@@ -562,17 +544,14 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
|
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
|
||||||
buf_set_u32(reg_params[3].value, 0, 32, 0);
|
buf_set_u32(reg_params[3].value, 0, 32, 0);
|
||||||
|
|
||||||
if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||||
em357_info->write_algorithm->address,
|
write_algorithm->address, 0, 10000, &armv7m_info);
|
||||||
0,
|
if (retval != ERROR_OK) {
|
||||||
10000, &armv7m_info)) != ERROR_OK)
|
|
||||||
{
|
|
||||||
LOG_ERROR("error executing em357 flash write algorithm");
|
LOG_ERROR("error executing em357 flash write algorithm");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
|
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) {
|
||||||
{
|
|
||||||
LOG_ERROR("flash memory not erased before writing");
|
LOG_ERROR("flash memory not erased before writing");
|
||||||
/* Clear but report errors */
|
/* Clear but report errors */
|
||||||
target_write_u32(target, EM357_FLASH_SR, FLASH_PGERR);
|
target_write_u32(target, EM357_FLASH_SR, FLASH_PGERR);
|
||||||
@@ -580,8 +559,7 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
|
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) {
|
||||||
{
|
|
||||||
LOG_ERROR("flash memory write protected");
|
LOG_ERROR("flash memory write protected");
|
||||||
/* Clear but report errors */
|
/* Clear but report errors */
|
||||||
target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR);
|
target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR);
|
||||||
@@ -595,7 +573,7 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
target_free_working_area(target, source);
|
target_free_working_area(target, source);
|
||||||
target_free_working_area(target, em357_info->write_algorithm);
|
target_free_working_area(target, write_algorithm);
|
||||||
|
|
||||||
destroy_reg_param(®_params[0]);
|
destroy_reg_param(®_params[0]);
|
||||||
destroy_reg_param(®_params[1]);
|
destroy_reg_param(®_params[1]);
|
||||||
@@ -615,14 +593,12 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
uint32_t bytes_written = 0;
|
uint32_t bytes_written = 0;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_HALTED)
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset & 0x1)
|
if (offset & 0x1) {
|
||||||
{
|
|
||||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
|
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
@@ -635,21 +611,20 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
||||||
|
|
||||||
/* multiple half words (2-byte) to be programmed? */
|
/* multiple half words (2-byte) to be programmed? */
|
||||||
if (words_remaining > 0)
|
if (words_remaining > 0) {
|
||||||
{
|
|
||||||
/* try using a block write */
|
/* try using a block write */
|
||||||
if ((retval = em357_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
|
retval = em357_write_block(bank, buffer, offset, words_remaining);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
|
||||||
{
|
|
||||||
/* if block write failed (no sufficient working area),
|
/* if block write failed (no sufficient working area),
|
||||||
* we use normal (slow) single dword accesses */
|
* we use normal (slow) single dword accesses */
|
||||||
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
LOG_WARNING(
|
||||||
|
"couldn't use block writes, falling back to single memory accesses");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer += words_remaining * 2;
|
buffer += words_remaining * 2;
|
||||||
address += words_remaining * 2;
|
address += words_remaining * 2;
|
||||||
words_remaining = 0;
|
words_remaining = 0;
|
||||||
@@ -659,8 +634,7 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
|
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
while (words_remaining > 0)
|
while (words_remaining > 0) {
|
||||||
{
|
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
|
memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
|
||||||
|
|
||||||
@@ -680,8 +654,7 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
address += 2;
|
address += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_remaining)
|
if (bytes_remaining) {
|
||||||
{
|
|
||||||
uint16_t value = 0xffff;
|
uint16_t value = 0xffff;
|
||||||
memcpy(&value, buffer + bytes_written, bytes_remaining);
|
memcpy(&value, buffer + bytes_written, bytes_remaining);
|
||||||
|
|
||||||
@@ -711,19 +684,44 @@ static int em357_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
em357_info->probed = 0;
|
em357_info->probed = 0;
|
||||||
|
|
||||||
|
switch (bank->size) {
|
||||||
|
case 0x10000:
|
||||||
|
/* 64k -- 64 1k pages */
|
||||||
|
num_pages = 64;
|
||||||
|
page_size = 1024;
|
||||||
|
break;
|
||||||
|
case 0x20000:
|
||||||
|
/* 128k -- 128 1k pages */
|
||||||
|
num_pages = 128;
|
||||||
|
page_size = 1024;
|
||||||
|
break;
|
||||||
|
case 0x30000:
|
||||||
|
/* 192k -- 96 2k pages */
|
||||||
|
num_pages = 96;
|
||||||
|
page_size = 2048;
|
||||||
|
break;
|
||||||
|
case 0x40000:
|
||||||
|
/* 256k -- 128 2k pages */
|
||||||
|
num_pages = 128;
|
||||||
|
page_size = 2048;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARNING("No size specified for em357 flash driver, assuming 192k!");
|
||||||
|
num_pages = 96;
|
||||||
|
page_size = 2048;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable FPEC CLK */
|
/* Enable FPEC CLK */
|
||||||
int retval = target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
int retval = target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
page_size = 2048;
|
|
||||||
em357_info->ppage_size = 4;
|
em357_info->ppage_size = 4;
|
||||||
num_pages = 96;
|
|
||||||
|
|
||||||
LOG_INFO("flash size = %dkbytes", num_pages*page_size/1024);
|
LOG_INFO("flash size = %dkbytes", num_pages*page_size/1024);
|
||||||
|
|
||||||
if (bank->sectors)
|
if (bank->sectors) {
|
||||||
{
|
|
||||||
free(bank->sectors);
|
free(bank->sectors);
|
||||||
bank->sectors = NULL;
|
bank->sectors = NULL;
|
||||||
}
|
}
|
||||||
@@ -733,8 +731,7 @@ static int em357_probe(struct flash_bank *bank)
|
|||||||
bank->num_sectors = num_pages;
|
bank->num_sectors = num_pages;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||||
|
|
||||||
for (i = 0; i < num_pages; i++)
|
for (i = 0; i < num_pages; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = i * page_size;
|
bank->sectors[i].offset = i * page_size;
|
||||||
bank->sectors[i].size = page_size;
|
bank->sectors[i].size = page_size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
@@ -757,10 +754,7 @@ static int em357_auto_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
static int get_em357_info(struct flash_bank *bank, char *buf, int buf_size)
|
static int get_em357_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
{
|
{
|
||||||
int printed;
|
snprintf(buf, buf_size, "em357\n");
|
||||||
printed = snprintf(buf, buf_size, "em357\n");
|
|
||||||
buf += printed;
|
|
||||||
buf_size -= printed;
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,10 +764,7 @@ COMMAND_HANDLER(em357_handle_lock_command)
|
|||||||
struct em357_flash_bank *em357_info = NULL;
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 1)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
command_print(CMD_CTX, "em357 lock <bank>");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
@@ -784,14 +775,12 @@ COMMAND_HANDLER(em357_handle_lock_command)
|
|||||||
|
|
||||||
target = bank->target;
|
target = bank->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em357_erase_options(bank) != ERROR_OK)
|
if (em357_erase_options(bank) != ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "em357 failed to erase options");
|
command_print(CMD_CTX, "em357 failed to erase options");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -799,8 +788,7 @@ COMMAND_HANDLER(em357_handle_lock_command)
|
|||||||
/* set readout protection */
|
/* set readout protection */
|
||||||
em357_info->option_bytes.RDP = 0;
|
em357_info->option_bytes.RDP = 0;
|
||||||
|
|
||||||
if (em357_write_options(bank) != ERROR_OK)
|
if (em357_write_options(bank) != ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "em357 failed to lock device");
|
command_print(CMD_CTX, "em357 failed to lock device");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -815,10 +803,7 @@ COMMAND_HANDLER(em357_handle_unlock_command)
|
|||||||
struct target *target = NULL;
|
struct target *target = NULL;
|
||||||
|
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 1)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
command_print(CMD_CTX, "em357 unlock <bank>");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
@@ -827,20 +812,17 @@ COMMAND_HANDLER(em357_handle_unlock_command)
|
|||||||
|
|
||||||
target = bank->target;
|
target = bank->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em357_erase_options(bank) != ERROR_OK)
|
if (em357_erase_options(bank) != ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "em357 failed to unlock device");
|
command_print(CMD_CTX, "em357 failed to unlock device");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em357_write_options(bank) != ERROR_OK)
|
if (em357_write_options(bank) != ERROR_OK) {
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "em357 failed to lock device");
|
command_print(CMD_CTX, "em357 failed to lock device");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -856,12 +838,14 @@ static int em357_mass_erase(struct flash_bank *bank)
|
|||||||
{
|
{
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED) {
|
||||||
{
|
|
||||||
LOG_ERROR("Target not halted");
|
LOG_ERROR("Target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure the flash clock is on */
|
||||||
|
target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
||||||
|
|
||||||
/* unlock option flash registers */
|
/* unlock option flash registers */
|
||||||
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
@@ -894,10 +878,7 @@ COMMAND_HANDLER(em357_handle_mass_erase_command)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 1)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
command_print(CMD_CTX, "em357 mass_erase <bank>");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
@@ -905,20 +886,14 @@ COMMAND_HANDLER(em357_handle_mass_erase_command)
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
retval = em357_mass_erase(bank);
|
retval = em357_mass_erase(bank);
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK) {
|
||||||
{
|
|
||||||
/* set all sectors as erased */
|
/* set all sectors as erased */
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
{
|
|
||||||
bank->sectors[i].is_erased = 1;
|
bank->sectors[i].is_erased = 1;
|
||||||
}
|
|
||||||
|
|
||||||
command_print(CMD_CTX, "em357 mass erase complete");
|
command_print(CMD_CTX, "em357 mass erase complete");
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "em357 mass erase failed");
|
command_print(CMD_CTX, "em357 mass erase failed");
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -926,23 +901,23 @@ COMMAND_HANDLER(em357_handle_mass_erase_command)
|
|||||||
static const struct command_registration em357_exec_command_handlers[] = {
|
static const struct command_registration em357_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "lock",
|
.name = "lock",
|
||||||
|
.usage = "<bank>",
|
||||||
.handler = em357_handle_lock_command,
|
.handler = em357_handle_lock_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.usage = "bank_id",
|
|
||||||
.help = "Lock entire flash device.",
|
.help = "Lock entire flash device.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "unlock",
|
.name = "unlock",
|
||||||
|
.usage = "<bank>",
|
||||||
.handler = em357_handle_unlock_command,
|
.handler = em357_handle_unlock_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.usage = "bank_id",
|
|
||||||
.help = "Unlock entire protected flash device.",
|
.help = "Unlock entire protected flash device.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "mass_erase",
|
.name = "mass_erase",
|
||||||
|
.usage = "<bank>",
|
||||||
.handler = em357_handle_mass_erase_command,
|
.handler = em357_handle_mass_erase_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.usage = "bank_id",
|
|
||||||
.help = "Erase entire flash device.",
|
.help = "Erase entire flash device.",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
@@ -953,6 +928,7 @@ static const struct command_registration em357_command_handlers[] = {
|
|||||||
.name = "em357",
|
.name = "em357",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "em357 flash command group",
|
.help = "em357 flash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = em357_exec_command_handlers,
|
.chain = em357_exec_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
@@ -968,7 +944,7 @@ struct flash_driver em357_flash = {
|
|||||||
.read = default_flash_read,
|
.read = default_flash_read,
|
||||||
.probe = em357_probe,
|
.probe = em357_probe,
|
||||||
.auto_probe = em357_auto_probe,
|
.auto_probe = em357_auto_probe,
|
||||||
.erase_check = default_flash_mem_blank_check,
|
.erase_check = default_flash_blank_check,
|
||||||
.protect_check = em357_protect_check,
|
.protect_check = em357_protect_check,
|
||||||
.info = get_em357_info,
|
.info = get_em357_info,
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user