Compare commits
742 Commits
v0.5.0-rc2
...
v0.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9c4700b4d | ||
|
|
e69b94295e | ||
|
|
6d1ea5a7a9 | ||
|
|
8f944fc226 | ||
|
|
6544018321 | ||
|
|
80a9e44ac7 | ||
|
|
f5793f9a4a | ||
|
|
6145b016c2 | ||
|
|
2d0750d708 | ||
|
|
00581ae591 | ||
|
|
f8a537aa92 | ||
|
|
feb926a770 | ||
|
|
0c0c1b81e2 | ||
|
|
a384596034 | ||
|
|
027f8c9fb3 | ||
|
|
612cad7f7c | ||
|
|
07a73c01d1 | ||
|
|
6cb0c3ff14 | ||
|
|
f254667a13 | ||
|
|
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 | ||
|
|
2fced63147 | ||
|
|
bbd84417f6 | ||
|
|
0d7a948c8d | ||
|
|
29f0ac0efd | ||
|
|
d02dfff48b | ||
|
|
69ac20a155 | ||
|
|
633b1a2b49 | ||
|
|
852289bc49 | ||
|
|
89f593d8cb | ||
|
|
c73342fbe7 | ||
|
|
b066a7db24 | ||
|
|
b5a324e63c | ||
|
|
1cfd3fdda9 | ||
|
|
ba4b8af4d7 | ||
|
|
577c3bc087 | ||
|
|
e872d2880e | ||
|
|
d6c42bf312 | ||
|
|
ffbb5cd85c | ||
|
|
5e7c8d074c | ||
|
|
e7269e32a7 | ||
|
|
f44bde23b9 | ||
|
|
0ea76bc778 | ||
|
|
b765688be6 | ||
|
|
b238735f89 | ||
|
|
107ddb38b7 | ||
|
|
898dd3af46 | ||
|
|
ac43d7a69f |
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,7 +307,7 @@ 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.
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
159
HACKING
159
HACKING
@@ -1,56 +1,157 @@
|
|||||||
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
|
@b NB! 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
|
@b NB2! 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.
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
-# Add an SSH public key following the directions on github:
|
||||||
|
https://help.github.com/articles/generating-ssh-keys
|
||||||
|
-# Clone the git repository, rather than just download the source:
|
||||||
|
@code
|
||||||
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
git clone git://openocd.git.sourceforge.net/gitroot/openocd/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://repo.or.cz/r/openocd.git
|
||||||
|
@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://openocd.zylin.com/p/openocd.git
|
||||||
|
git config remote.review.push HEAD:refs/publish/master
|
||||||
|
@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
|
||||||
|
@b 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
|
||||||
TIP! use "git add ." before commit to add new files.
|
@b TIP! use "git add ." before commit to add new files.
|
||||||
|
@code
|
||||||
--- example comment, notice the short first line w/topic ---
|
--- example comment, notice the short first line w/topic ---
|
||||||
topic: short comment
|
topic: short comment
|
||||||
<blank line>
|
<blank line>
|
||||||
longer comments over several
|
longer comments over several
|
||||||
lines...
|
lines...
|
||||||
|
<blank line>
|
||||||
|
Signed-off-by: ...
|
||||||
-----
|
-----
|
||||||
|
@endcode
|
||||||
3. Next you need to make sure that your patches
|
-# 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.
|
||||||
|
|
||||||
|
@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
|
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,10 +63,13 @@ $(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:
|
||||||
|
if test -d $(srcdir)/.git -a \( ! -e $(distdir)/ChangeLog -o -w $(distdir)/ChangeLog \) ; then \
|
||||||
|
git --git-dir $(srcdir)/.git log | $(srcdir)/tools/git2cl/git2cl > $(distdir)/ChangeLog ; \
|
||||||
|
fi
|
||||||
for i in $$($(TCL_FILES)); do \
|
for i in $$($(TCL_FILES)); do \
|
||||||
j="$(distdir)/$(TCL_PATH)/$$i" && \
|
j="$(distdir)/$(TCL_PATH)/$$i" && \
|
||||||
mkdir -p "$$(dirname $$j)" && \
|
mkdir -p "$$(dirname $$j)" && \
|
||||||
|
|||||||
76
NEWS
76
NEWS
@@ -1,63 +1,44 @@
|
|||||||
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 STLINK V1/V2 JTAG/SWD adapter support.
|
||||||
Rename various commands so they're not JTAG-specific
|
New OSJTAG adapter support.
|
||||||
There are migration procedures for most of these, but you should
|
New Tincantools Flyswatter2 support.
|
||||||
convert your scripts to the new names, since those procedures
|
Improved ULINK driver.
|
||||||
will not be around forever.
|
Improved RLINK driver.
|
||||||
jtag jinterface ... is now adapter_name
|
Support for adapters based on FT232H chips.
|
||||||
jtag_khz ... is now adapter_khz
|
New experimental driver for FTDI based adapters, using libusb-1.0 in asynchronous mode.
|
||||||
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 Cortex-M0 support.
|
||||||
- basic semihosting support for ARMv7M.
|
New Cortex-M4 support.
|
||||||
- renamed "armv7m" command prefix as "arm"
|
Improved Working area algorithm.
|
||||||
MIPS:
|
New RTOS support. Currently linux, FreeRTOS, ThreadX and eCos.
|
||||||
- "ejtag_srst" variant removed. The same functionality is
|
Connecting under reset to Cortex-Mx and MIPS chips.
|
||||||
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 SST39WF1601 support.
|
||||||
to recover locked devices (restoring non-volatile
|
New EN29LV800BB support.
|
||||||
state to the factory defaults, including erasing
|
New async algorithm support for selected targets, stm32, stellaris and pic32.
|
||||||
the flash and its protection bits, and possibly
|
New Atmel SAM3S, SAM3N support.
|
||||||
re-enabling hardware debugging).
|
New ST STM32L support.
|
||||||
PIC32MX now uses algorithm for flash programming, this
|
New Microchip PIC32MX1xx/2xx support.
|
||||||
has increased the performance by approx 96%.
|
New Freescale Kinetis K40 support.
|
||||||
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 Dangerous Prototypes Bus Blaster.
|
||||||
Support Voipac PXA270/PXA270M module.
|
Support ST SPEAr Family.
|
||||||
New $PARPORTADDR tcl variable used to change default
|
Support Gumstix Verdex boards.
|
||||||
parallel port address used.
|
Support TI Beaglebone.
|
||||||
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:
|
||||||
|
Improved HACKING info for submitting patches.
|
||||||
|
Fixed numerous broken links.
|
||||||
|
|
||||||
Build and Release:
|
Build and Release:
|
||||||
|
|
||||||
@@ -71,4 +52,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).
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
73
README
73
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,84 @@ 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-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-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-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.
|
||||||
|
|||||||
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
|
||||||
@@ -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
|
||||||
@@ -67,5 +71,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
|
||||||
|
|||||||
@@ -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 version 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
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
655
doc/openocd.texi
655
doc/openocd.texi
@@ -168,19 +168,19 @@ STM32x). Preliminary support for various NAND flash controllers
|
|||||||
|
|
||||||
The OpenOCD web site provides the latest public news from the community:
|
The OpenOCD web site provides the latest public news from the community:
|
||||||
|
|
||||||
@uref{http://openocd.berlios.de/web/}
|
@uref{http://openocd.sourceforge.net/}
|
||||||
|
|
||||||
@section Latest User's Guide:
|
@section Latest User's Guide:
|
||||||
|
|
||||||
The user's guide you are now reading may not be the latest one
|
The user's guide you are now reading may not be the latest one
|
||||||
available. A version for more recent code may be available.
|
available. A version for more recent code may be available.
|
||||||
Its HTML form is published irregularly at:
|
Its HTML form is published regularly at:
|
||||||
|
|
||||||
@uref{http://openocd.berlios.de/doc/html/index.html}
|
@uref{http://openocd.sourceforge.net/doc/html/index.html}
|
||||||
|
|
||||||
PDF form is likewise published at:
|
PDF form is likewise published at:
|
||||||
|
|
||||||
@uref{http://openocd.berlios.de/doc/pdf/openocd.pdf}
|
@uref{http://openocd.sourceforge.net/doc/pdf/openocd.pdf}
|
||||||
|
|
||||||
@section OpenOCD User's Forum
|
@section OpenOCD User's Forum
|
||||||
|
|
||||||
@@ -192,6 +192,17 @@ instead of this forum.
|
|||||||
|
|
||||||
@uref{http://forum.sparkfun.com/viewforum.php?f=18}
|
@uref{http://forum.sparkfun.com/viewforum.php?f=18}
|
||||||
|
|
||||||
|
@section OpenOCD User's Mailing List
|
||||||
|
|
||||||
|
The OpenOCD User Mailing List provides the primary means of
|
||||||
|
communication between users:
|
||||||
|
|
||||||
|
@uref{https://lists.sourceforge.net/mailman/listinfo/openocd-user}
|
||||||
|
|
||||||
|
@section OpenOCD IRC
|
||||||
|
|
||||||
|
Support can also be found on irc:
|
||||||
|
@uref{irc://irc.freenode.net/openocd}
|
||||||
|
|
||||||
@node Developers
|
@node Developers
|
||||||
@chapter OpenOCD Developer Resources
|
@chapter OpenOCD Developer Resources
|
||||||
@@ -241,7 +252,7 @@ providing a Doxygen reference manual. This document contains more
|
|||||||
technical information about the software internals, development
|
technical information about the software internals, development
|
||||||
processes, and similar documentation:
|
processes, and similar documentation:
|
||||||
|
|
||||||
@uref{http://openocd.berlios.de/doc/doxygen/index.html}
|
@uref{http://openocd.sourceforge.net/doc/doxygen/html/index.html}
|
||||||
|
|
||||||
This document is a work-in-progress, but contributions would be welcome
|
This document is a work-in-progress, but contributions would be welcome
|
||||||
to fill in the gaps. All of the source files are provided in-tree,
|
to fill in the gaps. All of the source files are provided in-tree,
|
||||||
@@ -252,10 +263,10 @@ listed in the Doxyfile configuration in the top of the source tree.
|
|||||||
The OpenOCD Developer Mailing List provides the primary means of
|
The OpenOCD Developer Mailing List provides the primary means of
|
||||||
communication between developers:
|
communication between developers:
|
||||||
|
|
||||||
@uref{https://lists.berlios.de/mailman/listinfo/openocd-development}
|
@uref{https://lists.sourceforge.net/mailman/listinfo/openocd-devel}
|
||||||
|
|
||||||
Discuss and submit patches to this list.
|
Discuss and submit patches to this list.
|
||||||
The @file{PATCHES.txt} file contains basic information about how
|
The @file{HACKING} file contains basic information about how
|
||||||
to prepare patches.
|
to prepare patches.
|
||||||
|
|
||||||
@section OpenOCD Bug Database
|
@section OpenOCD Bug Database
|
||||||
@@ -309,7 +320,7 @@ RTCK support? Also known as ``adaptive clocking''
|
|||||||
|
|
||||||
@section Stand alone Systems
|
@section Stand alone Systems
|
||||||
|
|
||||||
@b{ZY1000} See: @url{http://www.zylin.com/zy1000.html} Technically, not a
|
@b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe} Technically, not a
|
||||||
dongle, but a standalone box. The ZY1000 has the advantage that it does
|
dongle, but a standalone box. The ZY1000 has the advantage that it does
|
||||||
not require any drivers installed on the developer PC. It also has
|
not require any drivers installed on the developer PC. It also has
|
||||||
a built in web interface. It supports RTCK/RCLK or adaptive clocking
|
a built in web interface. It supports RTCK/RCLK or adaptive clocking
|
||||||
@@ -336,7 +347,7 @@ a built-in low cost debug adapter and usb-to-serial solution.
|
|||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item @b{usbjtag}
|
@item @b{usbjtag}
|
||||||
@* Link @url{http://www.hs-augsburg.de/~hhoegl/proj/usbjtag/usbjtag.html}
|
@* Link @url{http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html}
|
||||||
@item @b{jtagkey}
|
@item @b{jtagkey}
|
||||||
@* See: @url{http://www.amontec.com/jtagkey.shtml}
|
@* See: @url{http://www.amontec.com/jtagkey.shtml}
|
||||||
@item @b{jtagkey2}
|
@item @b{jtagkey2}
|
||||||
@@ -358,7 +369,7 @@ Evaluation Kits. Like the non-detachable FT2232 support on the other
|
|||||||
Stellaris eval boards, they can be used to debug other target boards.
|
Stellaris eval boards, they can be used to debug other target boards.
|
||||||
@item @b{olimex-jtag}
|
@item @b{olimex-jtag}
|
||||||
@* See: @url{http://www.olimex.com}
|
@* See: @url{http://www.olimex.com}
|
||||||
@item @b{flyswatter}
|
@item @b{Flyswatter/Flyswatter2}
|
||||||
@* See: @url{http://www.tincantools.com}
|
@* See: @url{http://www.tincantools.com}
|
||||||
@item @b{turtelizer2}
|
@item @b{turtelizer2}
|
||||||
@* See:
|
@* See:
|
||||||
@@ -369,9 +380,14 @@ Stellaris eval boards, they can be used to debug other target boards.
|
|||||||
@item @b{stm32stick}
|
@item @b{stm32stick}
|
||||||
@* Link @url{http://www.hitex.com/stm32-stick}
|
@* Link @url{http://www.hitex.com/stm32-stick}
|
||||||
@item @b{axm0432_jtag}
|
@item @b{axm0432_jtag}
|
||||||
@* Axiom AXM-0432 Link @url{http://www.axman.com}
|
@* Axiom AXM-0432 Link @url{http://www.axman.com} - NOTE: This JTAG does not appear
|
||||||
|
to be available anymore as of April 2012.
|
||||||
@item @b{cortino}
|
@item @b{cortino}
|
||||||
@* Link @url{http://www.hitex.com/index.php?id=cortino}
|
@* Link @url{http://www.hitex.com/index.php?id=cortino}
|
||||||
|
@item @b{dlp-usb1232h}
|
||||||
|
@* Link @url{http://www.dlpdesign.com/usb/usb1232h.shtml}
|
||||||
|
@item @b{digilent-hs1}
|
||||||
|
@* Link @url{http://www.digilentinc.com/Products/Detail.cfm?Prod=JTAG-HS1}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section USB-JTAG / Altera USB-Blaster compatibles
|
@section USB-JTAG / Altera USB-Blaster compatibles
|
||||||
@@ -388,7 +404,7 @@ product. The driver can be configured to search for any VID/PID pair
|
|||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@item @b{USB-JTAG} Kolja Waschk's USB Blaster-compatible adapter
|
@item @b{USB-JTAG} Kolja Waschk's USB Blaster-compatible adapter
|
||||||
@* Link: @url{http://www.ixo.de/info/usb_jtag/}
|
@* Link: @url{http://ixo-jtag.sourceforge.net/}
|
||||||
@item @b{Altera USB-Blaster}
|
@item @b{Altera USB-Blaster}
|
||||||
@* Link: @url{http://www.altera.com/literature/ug/ug_usb_blstr.pdf}
|
@* Link: @url{http://www.altera.com/literature/ug/ug_usb_blstr.pdf}
|
||||||
@end itemize
|
@end itemize
|
||||||
@@ -404,7 +420,7 @@ AT91SAM764 internally.
|
|||||||
@item @b{SEGGER JLINK}
|
@item @b{SEGGER JLINK}
|
||||||
@* Link: @url{http://www.segger.com/jlink.html}
|
@* Link: @url{http://www.segger.com/jlink.html}
|
||||||
@item @b{IAR J-Link}
|
@item @b{IAR J-Link}
|
||||||
@* Link: @url{http://www.iar.com/website1/1.0.1.0/369/1/index.php}
|
@* Link: @url{http://www.iar.com/en/products/hardware-debug-probes/iar-j-link/}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section USB RLINK based
|
@section USB RLINK based
|
||||||
@@ -412,35 +428,65 @@ Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form o
|
|||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item @b{Raisonance RLink}
|
@item @b{Raisonance RLink}
|
||||||
@* Link: @url{http://www.raisonance.com/products/RLink.php}
|
@* Link: @url{http://www.mcu-raisonance.com/~rlink-debugger-programmer__microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html}
|
||||||
@item @b{STM32 Primer}
|
@item @b{STM32 Primer}
|
||||||
@* Link: @url{http://www.stm32circle.com/resources/stm32primer.php}
|
@* Link: @url{http://www.stm32circle.com/resources/stm32primer.php}
|
||||||
@item @b{STM32 Primer2}
|
@item @b{STM32 Primer2}
|
||||||
@* Link: @url{http://www.stm32circle.com/resources/stm32primer2.php}
|
@* Link: @url{http://www.stm32circle.com/resources/stm32primer2.php}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
@section USB ST-LINK based
|
||||||
|
ST Micro has an adapter called @b{ST-LINK}.
|
||||||
|
They only work with ST Micro chips, notably STM32 and STM8.
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item @b{ST-LINK}
|
||||||
|
@* This is available standalone and as part of some kits, eg. STM32VLDISCOVERY.
|
||||||
|
@* Link: @url{http://www.st.com/internet/evalboard/product/219866.jsp}
|
||||||
|
@item @b{ST-LINK/V2}
|
||||||
|
@* This is available standalone and as part of some kits, eg. STM32F4DISCOVERY.
|
||||||
|
@* Link: @url{http://www.st.com/internet/evalboard/product/251168.jsp}
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
For info the original ST-LINK enumerates using the mass storage usb class, however
|
||||||
|
it's implementation is completely broken. The result is this causes issues under linux.
|
||||||
|
The simplest solution is to get linux to ignore the ST-LINK using one of the following methods:
|
||||||
|
@itemize @bullet
|
||||||
|
@item modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
|
||||||
|
@item add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@section USB Other
|
@section USB Other
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item @b{USBprog}
|
@item @b{USBprog}
|
||||||
@* Link: @url{http://www.embedded-projects.net/usbprog} - which uses an Atmel MEGA32 and a UBN9604
|
@* Link: @url{http://shop.embedded-projects.net/} - which uses an Atmel MEGA32 and a UBN9604
|
||||||
|
|
||||||
@item @b{USB - Presto}
|
@item @b{USB - Presto}
|
||||||
@* Link: @url{http://tools.asix.net/prg_presto.htm}
|
@* Link: @url{http://tools.asix.net/prg_presto.htm}
|
||||||
|
|
||||||
@item @b{Versaloon-Link}
|
@item @b{Versaloon-Link}
|
||||||
@* Link: @url{http://www.simonqian.com/en/Versaloon}
|
@* Link: @url{http://www.versaloon.com}
|
||||||
|
|
||||||
@item @b{ARM-JTAG-EW}
|
@item @b{ARM-JTAG-EW}
|
||||||
@* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html}
|
@* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html}
|
||||||
|
|
||||||
@item @b{Buspirate}
|
@item @b{Buspirate}
|
||||||
@* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/}
|
@* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/}
|
||||||
|
|
||||||
|
@item @b{opendous}
|
||||||
|
@* Link: @url{http://code.google.com/p/opendous-jtag/}
|
||||||
|
|
||||||
|
@item @b{estick}
|
||||||
|
@* Link: @url{http://code.google.com/p/estick-jtag/}
|
||||||
|
|
||||||
|
@item @b{Keil ULINK v1}
|
||||||
|
@* Link: @url{http://www.keil.com/ulink1/}
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section IBM PC Parallel Printer Port Based
|
@section IBM PC Parallel Printer Port Based
|
||||||
|
|
||||||
The two well known ``JTAG Parallel Ports'' cables are the Xilnx DLC5
|
The two well known ``JTAG Parallel Ports'' cables are the Xilnx DLC5
|
||||||
and the MacGraigor Wiggler. There are many clones and variations of
|
and the Macraigor Wiggler. There are many clones and variations of
|
||||||
these on the market.
|
these on the market.
|
||||||
|
|
||||||
Note that parallel ports are becoming much less common, so if you
|
Note that parallel ports are becoming much less common, so if you
|
||||||
@@ -463,8 +509,7 @@ produced, PDF schematics are easily found and it is easy to make.
|
|||||||
@* Link: @url{http://www.gateworks.com/products/avila_accessories/gw16042.php}
|
@* Link: @url{http://www.gateworks.com/products/avila_accessories/gw16042.php}
|
||||||
|
|
||||||
@item @b{Wiggler2}
|
@item @b{Wiggler2}
|
||||||
@*@uref{http://www.ccac.rwth-aachen.de/@/~michaels/@/index.php/hardware/@/armjtag,
|
@* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag}
|
||||||
Improved parallel-port wiggler-style JTAG adapter}
|
|
||||||
|
|
||||||
@item @b{Wiggler_ntrst_inverted}
|
@item @b{Wiggler_ntrst_inverted}
|
||||||
@* Yet another variation - See the source code, src/jtag/parport.c
|
@* Yet another variation - See the source code, src/jtag/parport.c
|
||||||
@@ -487,8 +532,7 @@ Improved parallel-port wiggler-style JTAG adapter}
|
|||||||
|
|
||||||
@item @b{flashlink}
|
@item @b{flashlink}
|
||||||
@* From ST Microsystems;
|
@* From ST Microsystems;
|
||||||
@uref{http://www.st.com/stonline/@/products/literature/um/7889.pdf,
|
@* Link: @url{http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/DM00039500.pdf}
|
||||||
FlashLINK JTAG programing cable for PSD and uPSD}
|
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@@ -526,7 +570,7 @@ OpenOCD mailing list.
|
|||||||
@item @b{Jim vs. Tcl}
|
@item @b{Jim vs. Tcl}
|
||||||
@* Jim-Tcl is a stripped down version of the well known Tcl language,
|
@* Jim-Tcl is a stripped down version of the well known Tcl language,
|
||||||
which can be found here: @url{http://www.tcl.tk}. Jim-Tcl has far
|
which can be found here: @url{http://www.tcl.tk}. Jim-Tcl has far
|
||||||
fewer features. Jim-Tcl is a single .C file and a single .H file and
|
fewer features. Jim-Tcl is several dozens of .C files and .H files and
|
||||||
implements the basic Tcl command set. In contrast: Tcl 8.6 is a
|
implements the basic Tcl command set. In contrast: Tcl 8.6 is a
|
||||||
4.2 MB .zip file containing 1540 files.
|
4.2 MB .zip file containing 1540 files.
|
||||||
|
|
||||||
@@ -632,7 +676,7 @@ If all goes well you'll see output something like
|
|||||||
@example
|
@example
|
||||||
Open On-Chip Debugger 0.4.0 (2010-01-14-15:06)
|
Open On-Chip Debugger 0.4.0 (2010-01-14-15:06)
|
||||||
For bug reports, read
|
For bug reports, read
|
||||||
http://openocd.berlios.de/doc/doxygen/bugs.html
|
http://openocd.sourceforge.net/doc/doxygen/bugs.html
|
||||||
Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477
|
Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477
|
||||||
(mfg: 0x23b, part: 0xba00, ver: 0x3)
|
(mfg: 0x23b, part: 0xba00, ver: 0x3)
|
||||||
@end example
|
@end example
|
||||||
@@ -676,8 +720,6 @@ setting from within a telnet or gdb session using @command{debug_level
|
|||||||
You can redirect all output from the daemon to a file using the
|
You can redirect all output from the daemon to a file using the
|
||||||
@option{-l <logfile>} switch.
|
@option{-l <logfile>} switch.
|
||||||
|
|
||||||
For details on the @option{-p} option. @xref{Connecting to GDB}.
|
|
||||||
|
|
||||||
Note! OpenOCD will launch the GDB & telnet server even if it can not
|
Note! OpenOCD will launch the GDB & telnet server even if it can not
|
||||||
establish a connection with the target. In general, it is possible for
|
establish a connection with the target. In general, it is possible for
|
||||||
the JTAG controller to be unresponsive until the target is set up
|
the JTAG controller to be unresponsive until the target is set up
|
||||||
@@ -1203,17 +1245,30 @@ These are for debug adapters.
|
|||||||
Files that configure JTAG adapters go here.
|
Files that configure JTAG adapters go here.
|
||||||
@example
|
@example
|
||||||
$ ls interface
|
$ ls interface
|
||||||
arm-jtag-ew.cfg hitex_str9-comstick.cfg oocdlink.cfg
|
altera-usb-blaster.cfg hilscher_nxhx50_etm.cfg openrd.cfg
|
||||||
arm-usb-ocd.cfg icebear.cfg openocd-usb.cfg
|
arm-jtag-ew.cfg hilscher_nxhx50_re.cfg osbdm.cfg
|
||||||
at91rm9200.cfg jlink.cfg parport.cfg
|
arm-usb-ocd.cfg hitex_str9-comstick.cfg parport.cfg
|
||||||
axm0432.cfg jtagkey2.cfg parport_dlc5.cfg
|
at91rm9200.cfg icebear.cfg parport_dlc5.cfg
|
||||||
calao-usb-a9260-c01.cfg jtagkey.cfg rlink.cfg
|
axm0432.cfg jlink.cfg redbee-econotag.cfg
|
||||||
calao-usb-a9260-c02.cfg jtagkey-tiny.cfg sheevaplug.cfg
|
busblaster.cfg jtagkey2.cfg redbee-usb.cfg
|
||||||
calao-usb-a9260.cfg luminary.cfg signalyzer.cfg
|
buspirate.cfg jtagkey2p.cfg rlink.cfg
|
||||||
chameleon.cfg luminary-icdi.cfg stm32-stick.cfg
|
calao-usb-a9260-c01.cfg jtagkey.cfg sheevaplug.cfg
|
||||||
cortino.cfg luminary-lm3s811.cfg turtelizer2.cfg
|
calao-usb-a9260-c02.cfg jtagkey-tiny.cfg signalyzer.cfg
|
||||||
dummy.cfg olimex-arm-usb-ocd.cfg usbprog.cfg
|
calao-usb-a9260.cfg kt-link.cfg signalyzer-h2.cfg
|
||||||
|
chameleon.cfg lisa-l.cfg signalyzer-h4.cfg
|
||||||
|
cortino.cfg luminary.cfg signalyzer-lite.cfg
|
||||||
|
digilent-hs1.cfg luminary-icdi.cfg stlink-v1.cfg
|
||||||
|
dlp-usb1232h.cfg luminary-lm3s811.cfg stlink-v2.cfg
|
||||||
|
dummy.cfg minimodule.cfg stm32-stick.cfg
|
||||||
|
estick.cfg neodb.cfg turtelizer2.cfg
|
||||||
|
flashlink.cfg ngxtech.cfg ulink.cfg
|
||||||
|
flossjtag.cfg olimex-arm-usb-ocd.cfg usb-jtag.cfg
|
||||||
|
flossjtag-noeeprom.cfg olimex-arm-usb-ocd-h.cfg usbprog.cfg
|
||||||
|
flyswatter2.cfg olimex-arm-usb-tiny-h.cfg vpaclink.cfg
|
||||||
flyswatter.cfg olimex-jtag-tiny.cfg vsllink.cfg
|
flyswatter.cfg olimex-jtag-tiny.cfg vsllink.cfg
|
||||||
|
hilscher_nxhx10_etm.cfg oocdlink.cfg xds100v2.cfg
|
||||||
|
hilscher_nxhx500_etm.cfg opendous.cfg
|
||||||
|
hilscher_nxhx500_re.cfg openocd-usb.cfg
|
||||||
$
|
$
|
||||||
@end example
|
@end example
|
||||||
@item @file{board} ...
|
@item @file{board} ...
|
||||||
@@ -1229,32 +1284,72 @@ board file. Boards may also contain multiple targets: two CPUs; or
|
|||||||
a CPU and an FPGA.
|
a CPU and an FPGA.
|
||||||
@example
|
@example
|
||||||
$ ls board
|
$ ls board
|
||||||
arm_evaluator7t.cfg keil_mcb1700.cfg
|
actux3.cfg logicpd_imx27.cfg
|
||||||
at91rm9200-dk.cfg keil_mcb2140.cfg
|
am3517evm.cfg lubbock.cfg
|
||||||
at91sam9g20-ek.cfg linksys_nslu2.cfg
|
arm_evaluator7t.cfg mcb1700.cfg
|
||||||
atmel_at91sam7s-ek.cfg logicpd_imx27.cfg
|
at91cap7a-stk-sdram.cfg microchip_explorer16.cfg
|
||||||
atmel_at91sam9260-ek.cfg mini2440.cfg
|
at91eb40a.cfg mini2440.cfg
|
||||||
atmel_sam3u_ek.cfg olimex_LPC2378STK.cfg
|
at91rm9200-dk.cfg mini6410.cfg
|
||||||
crossbow_tech_imote2.cfg olimex_lpc_h2148.cfg
|
at91rm9200-ek.cfg olimex_LPC2378STK.cfg
|
||||||
csb337.cfg olimex_sam7_ex256.cfg
|
at91sam9261-ek.cfg olimex_lpc_h2148.cfg
|
||||||
csb732.cfg olimex_sam9_l9260.cfg
|
at91sam9263-ek.cfg olimex_sam7_ex256.cfg
|
||||||
digi_connectcore_wi-9c.cfg olimex_stm32_h103.cfg
|
at91sam9g20-ek.cfg olimex_sam9_l9260.cfg
|
||||||
dm355evm.cfg omap2420_h4.cfg
|
atmel_at91sam7s-ek.cfg olimex_stm32_h103.cfg
|
||||||
dm365evm.cfg osk5912.cfg
|
atmel_at91sam9260-ek.cfg olimex_stm32_h107.cfg
|
||||||
dm6446evm.cfg pic-p32mx.cfg
|
atmel_at91sam9rl-ek.cfg olimex_stm32_p107.cfg
|
||||||
eir.cfg propox_mmnet1001.cfg
|
atmel_sam3n_ek.cfg omap2420_h4.cfg
|
||||||
ek-lm3s1968.cfg pxa255_sst.cfg
|
atmel_sam3s_ek.cfg open-bldc.cfg
|
||||||
ek-lm3s3748.cfg sheevaplug.cfg
|
atmel_sam3u_ek.cfg openrd.cfg
|
||||||
ek-lm3s811.cfg stm3210e_eval.cfg
|
atmel_sam3x_ek.cfg osk5912.cfg
|
||||||
ek-lm3s9b9x.cfg stm32f10x_128k_eval.cfg
|
atmel_sam4s_ek.cfg phytec_lpc3250.cfg
|
||||||
hammer.cfg str910-eval.cfg
|
balloon3-cpu.cfg pic-p32mx.cfg
|
||||||
hitex_lpc2929.cfg telo.cfg
|
colibri.cfg propox_mmnet1001.cfg
|
||||||
hitex_stm32-performancestick.cfg ti_beagleboard.cfg
|
crossbow_tech_imote2.cfg pxa255_sst.cfg
|
||||||
hitex_str9-comstick.cfg topas910.cfg
|
csb337.cfg redbee.cfg
|
||||||
iar_str912_sk.cfg topasa900.cfg
|
csb732.cfg rsc-w910.cfg
|
||||||
imx27ads.cfg unknown_at91sam9260.cfg
|
da850evm.cfg sheevaplug.cfg
|
||||||
imx27lnst.cfg x300t.cfg
|
digi_connectcore_wi-9c.cfg smdk6410.cfg
|
||||||
imx31pdk.cfg zy1000.cfg
|
diolan_lpc4350-db1.cfg spear300evb.cfg
|
||||||
|
dm355evm.cfg spear300evb_mod.cfg
|
||||||
|
dm365evm.cfg spear310evb20.cfg
|
||||||
|
dm6446evm.cfg spear310evb20_mod.cfg
|
||||||
|
efikamx.cfg spear320cpu.cfg
|
||||||
|
eir.cfg spear320cpu_mod.cfg
|
||||||
|
ek-lm3s1968.cfg steval_pcc010.cfg
|
||||||
|
ek-lm3s3748.cfg stm320518_eval_stlink.cfg
|
||||||
|
ek-lm3s6965.cfg stm32100b_eval.cfg
|
||||||
|
ek-lm3s811.cfg stm3210b_eval.cfg
|
||||||
|
ek-lm3s811-revb.cfg stm3210c_eval.cfg
|
||||||
|
ek-lm3s9b9x.cfg stm3210e_eval.cfg
|
||||||
|
ek-lm4f232.cfg stm3220g_eval.cfg
|
||||||
|
embedded-artists_lpc2478-32.cfg stm3220g_eval_stlink.cfg
|
||||||
|
ethernut3.cfg stm3241g_eval.cfg
|
||||||
|
glyn_tonga2.cfg stm3241g_eval_stlink.cfg
|
||||||
|
hammer.cfg stm32f0discovery.cfg
|
||||||
|
hilscher_nxdb500sys.cfg stm32f4discovery.cfg
|
||||||
|
hilscher_nxeb500hmi.cfg stm32ldiscovery.cfg
|
||||||
|
hilscher_nxhx10.cfg stm32vldiscovery.cfg
|
||||||
|
hilscher_nxhx500.cfg str910-eval.cfg
|
||||||
|
hilscher_nxhx50.cfg telo.cfg
|
||||||
|
hilscher_nxsb100.cfg ti_beagleboard.cfg
|
||||||
|
hitex_lpc2929.cfg ti_beagleboard_xm.cfg
|
||||||
|
hitex_stm32-performancestick.cfg ti_beaglebone.cfg
|
||||||
|
hitex_str9-comstick.cfg ti_blaze.cfg
|
||||||
|
iar_lpc1768.cfg ti_pandaboard.cfg
|
||||||
|
iar_str912_sk.cfg ti_pandaboard_es.cfg
|
||||||
|
icnova_imx53_sodimm.cfg topas910.cfg
|
||||||
|
icnova_sam9g45_sodimm.cfg topasa900.cfg
|
||||||
|
imx27ads.cfg twr-k60n512.cfg
|
||||||
|
imx27lnst.cfg tx25_stk5.cfg
|
||||||
|
imx28evk.cfg tx27_stk5.cfg
|
||||||
|
imx31pdk.cfg unknown_at91sam9260.cfg
|
||||||
|
imx35pdk.cfg uptech_2410.cfg
|
||||||
|
imx53loco.cfg verdex.cfg
|
||||||
|
keil_mcb1700.cfg voipac.cfg
|
||||||
|
keil_mcb2140.cfg voltcraft_dso-3062c.cfg
|
||||||
|
kwikstik.cfg x300t.cfg
|
||||||
|
linksys_nslu2.cfg zy1000.cfg
|
||||||
|
lisa-l.cfg
|
||||||
$
|
$
|
||||||
@end example
|
@end example
|
||||||
@item @file{target} ...
|
@item @file{target} ...
|
||||||
@@ -1266,32 +1361,71 @@ When a chip has multiple TAPs (maybe it has both ARM and DSP cores),
|
|||||||
the target config file defines all of them.
|
the target config file defines all of them.
|
||||||
@example
|
@example
|
||||||
$ ls target
|
$ ls target
|
||||||
aduc702x.cfg imx27.cfg pxa255.cfg
|
$duc702x.cfg ixp42x.cfg
|
||||||
ar71xx.cfg imx31.cfg pxa270.cfg
|
am335x.cfg k40.cfg
|
||||||
at91eb40a.cfg imx35.cfg readme.txt
|
amdm37x.cfg k60.cfg
|
||||||
at91r40008.cfg is5114.cfg sam7se512.cfg
|
ar71xx.cfg lpc1768.cfg
|
||||||
at91rm9200.cfg ixp42x.cfg sam7x256.cfg
|
at32ap7000.cfg lpc2103.cfg
|
||||||
at91sam3u1c.cfg lm3s1968.cfg samsung_s3c2410.cfg
|
at91r40008.cfg lpc2124.cfg
|
||||||
at91sam3u1e.cfg lm3s3748.cfg samsung_s3c2440.cfg
|
at91rm9200.cfg lpc2129.cfg
|
||||||
at91sam3u2c.cfg lm3s6965.cfg samsung_s3c2450.cfg
|
at91sam3ax_4x.cfg lpc2148.cfg
|
||||||
at91sam3u2e.cfg lm3s811.cfg samsung_s3c4510.cfg
|
at91sam3ax_8x.cfg lpc2294.cfg
|
||||||
at91sam3u4c.cfg lm3s9b9x.cfg samsung_s3c6410.cfg
|
at91sam3ax_xx.cfg lpc2378.cfg
|
||||||
at91sam3u4e.cfg lpc1768.cfg sharp_lh79532.cfg
|
at91sam3nXX.cfg lpc2460.cfg
|
||||||
at91sam3uXX.cfg lpc2103.cfg smdk6410.cfg
|
at91sam3sXX.cfg lpc2478.cfg
|
||||||
at91sam7sx.cfg lpc2124.cfg smp8634.cfg
|
at91sam3u1c.cfg lpc2900.cfg
|
||||||
at91sam9260.cfg lpc2129.cfg stm32.cfg
|
at91sam3u1e.cfg lpc2xxx.cfg
|
||||||
c100.cfg lpc2148.cfg str710.cfg
|
at91sam3u2c.cfg lpc3131.cfg
|
||||||
c100config.tcl lpc2294.cfg str730.cfg
|
at91sam3u2e.cfg lpc3250.cfg
|
||||||
c100helper.tcl lpc2378.cfg str750.cfg
|
at91sam3u4c.cfg lpc4350.cfg
|
||||||
c100regs.tcl lpc2478.cfg str912.cfg
|
at91sam3u4e.cfg mc13224v.cfg
|
||||||
cs351x.cfg lpc2900.cfg telo.cfg
|
at91sam3uxx.cfg nuc910.cfg
|
||||||
davinci.cfg mega128.cfg ti_dm355.cfg
|
at91sam3XXX.cfg omap2420.cfg
|
||||||
dragonite.cfg netx500.cfg ti_dm365.cfg
|
at91sam4sXX.cfg omap3530.cfg
|
||||||
epc9301.cfg omap2420.cfg ti_dm6446.cfg
|
at91sam4XXX.cfg omap4430.cfg
|
||||||
feroceon.cfg omap3530.cfg tmpa900.cfg
|
at91sam7se512.cfg omap4460.cfg
|
||||||
icepick.cfg omap5912.cfg tmpa910.cfg
|
at91sam7sx.cfg omap5912.cfg
|
||||||
imx21.cfg pic32mx.cfg xba_revA3.cfg
|
at91sam7x256.cfg omapl138.cfg
|
||||||
$
|
at91sam7x512.cfg pic32mx.cfg
|
||||||
|
at91sam9260.cfg pxa255.cfg
|
||||||
|
at91sam9260_ext_RAM_ext_flash.cfg pxa270.cfg
|
||||||
|
at91sam9261.cfg pxa3xx.cfg
|
||||||
|
at91sam9263.cfg readme.txt
|
||||||
|
at91sam9.cfg samsung_s3c2410.cfg
|
||||||
|
at91sam9g10.cfg samsung_s3c2440.cfg
|
||||||
|
at91sam9g20.cfg samsung_s3c2450.cfg
|
||||||
|
at91sam9g45.cfg samsung_s3c4510.cfg
|
||||||
|
at91sam9rl.cfg samsung_s3c6410.cfg
|
||||||
|
atmega128.cfg sharp_lh79532.cfg
|
||||||
|
avr32.cfg smp8634.cfg
|
||||||
|
c100.cfg spear3xx.cfg
|
||||||
|
c100config.tcl stellaris.cfg
|
||||||
|
c100helper.tcl stm32.cfg
|
||||||
|
c100regs.tcl stm32f0x_stlink.cfg
|
||||||
|
cs351x.cfg stm32f1x.cfg
|
||||||
|
davinci.cfg stm32f1x_stlink.cfg
|
||||||
|
dragonite.cfg stm32f2x.cfg
|
||||||
|
dsp56321.cfg stm32f2x_stlink.cfg
|
||||||
|
dsp568013.cfg stm32f2xxx.cfg
|
||||||
|
dsp568037.cfg stm32f4x.cfg
|
||||||
|
epc9301.cfg stm32f4x_stlink.cfg
|
||||||
|
faux.cfg stm32l.cfg
|
||||||
|
feroceon.cfg stm32lx_stlink.cfg
|
||||||
|
fm3.cfg stm32_stlink.cfg
|
||||||
|
hilscher_netx10.cfg stm32xl.cfg
|
||||||
|
hilscher_netx500.cfg str710.cfg
|
||||||
|
hilscher_netx50.cfg str730.cfg
|
||||||
|
icepick.cfg str750.cfg
|
||||||
|
imx21.cfg str912.cfg
|
||||||
|
imx25.cfg swj-dp.tcl
|
||||||
|
imx27.cfg test_reset_syntax_error.cfg
|
||||||
|
imx28.cfg test_syntax_error.cfg
|
||||||
|
imx31.cfg ti_dm355.cfg
|
||||||
|
imx35.cfg ti_dm365.cfg
|
||||||
|
imx51.cfg ti_dm6446.cfg
|
||||||
|
imx53.cfg tmpa900.cfg
|
||||||
|
imx.cfg tmpa910.cfg
|
||||||
|
is5114.cfg u8500.cfg
|
||||||
@end example
|
@end example
|
||||||
@item @emph{more} ... browse for other library files which may be useful.
|
@item @emph{more} ... browse for other library files which may be useful.
|
||||||
For example, there are various generic and CPU-specific utilities.
|
For example, there are various generic and CPU-specific utilities.
|
||||||
@@ -1318,7 +1452,7 @@ have only been used by the developer who created it.
|
|||||||
|
|
||||||
A separate chapter gives information about how to set these up.
|
A separate chapter gives information about how to set these up.
|
||||||
@xref{Debug Adapter Configuration}.
|
@xref{Debug Adapter Configuration}.
|
||||||
Read the OpenOCD source code (and Developer's GUide)
|
Read the OpenOCD source code (and Developer's Guide)
|
||||||
if you have a new kind of hardware interface
|
if you have a new kind of hardware interface
|
||||||
and need to provide a driver for it.
|
and need to provide a driver for it.
|
||||||
|
|
||||||
@@ -1528,6 +1662,47 @@ also supports it. Otherwise use @command{adapter_khz}.
|
|||||||
Set the slow rate at the beginning of the reset sequence,
|
Set the slow rate at the beginning of the reset sequence,
|
||||||
and the faster rate as soon as the clocks are at full speed.
|
and the faster rate as soon as the clocks are at full speed.
|
||||||
|
|
||||||
|
@anchor{The init_board procedure}
|
||||||
|
@subsection The init_board procedure
|
||||||
|
@cindex init_board procedure
|
||||||
|
|
||||||
|
The concept of @code{init_board} procedure is very similar to @code{init_targets} (@xref{The init_targets procedure}.)
|
||||||
|
- it's a replacement of ``linear'' configuration scripts. This procedure is meant to be executed when OpenOCD enters run
|
||||||
|
stage (@xref{Entering the Run Stage},) after @code{init_targets}. The idea to have spearate @code{init_targets} and
|
||||||
|
@code{init_board} procedures is to allow the first one to configure everything target specific (internal flash,
|
||||||
|
internal RAM, etc.) and the second one to configure everything board specific (reset signals, chip frequency,
|
||||||
|
reset-init event handler, external memory, etc.). Additionally ``linear'' board config file will most likely fail when
|
||||||
|
target config file uses @code{init_targets} scheme (``linear'' script is executed before @code{init} and
|
||||||
|
@code{init_targets} - after), so separating these two configuration stages is very convenient, as the easiest way to
|
||||||
|
overcome this problem is to convert board config file to use @code{init_board} procedure. Board config scripts don't
|
||||||
|
need to override @code{init_targets} defined in target config files when they only need to to add some specifics.
|
||||||
|
|
||||||
|
Just as @code{init_targets}, the @code{init_board} procedure can be overriden by ``next level'' script (which sources
|
||||||
|
the original), allowing greater code reuse.
|
||||||
|
|
||||||
|
@example
|
||||||
|
### board_file.cfg ###
|
||||||
|
|
||||||
|
# source target file that does most of the config in init_targets
|
||||||
|
source [find target/target.cfg]
|
||||||
|
|
||||||
|
proc enable_fast_clock @{@} @{
|
||||||
|
# enables fast on-board clock source
|
||||||
|
# configures the chip to use it
|
||||||
|
@}
|
||||||
|
|
||||||
|
# initialize only board specifics - reset, clock, adapter frequency
|
||||||
|
proc init_board @{@} @{
|
||||||
|
reset_config trst_and_srst trst_pulls_srst
|
||||||
|
|
||||||
|
$_TARGETNAME configure -event reset-init @{
|
||||||
|
adapter_khz 1
|
||||||
|
enable_fast_clock
|
||||||
|
adapter_khz 10000
|
||||||
|
@}
|
||||||
|
@}
|
||||||
|
@end example
|
||||||
|
|
||||||
@section Target Config Files
|
@section Target Config Files
|
||||||
@cindex config file, target
|
@cindex config file, target
|
||||||
@cindex target config file
|
@cindex target config file
|
||||||
@@ -1679,7 +1854,7 @@ Again using the at91sam7 as an example, this can look like:
|
|||||||
$_TARGETNAME configure -work-area-phys 0x00200000 \
|
$_TARGETNAME configure -work-area-phys 0x00200000 \
|
||||||
-work-area-size 0x4000 -work-area-backup 0
|
-work-area-size 0x4000 -work-area-backup 0
|
||||||
@end example
|
@end example
|
||||||
@pxref{Define CPU targets working in SMP}
|
|
||||||
@anchor{Define CPU targets working in SMP}
|
@anchor{Define CPU targets working in SMP}
|
||||||
@subsection Define CPU targets working in SMP
|
@subsection Define CPU targets working in SMP
|
||||||
@cindex SMP
|
@cindex SMP
|
||||||
@@ -1789,6 +1964,47 @@ OpenOCD verifies the scan chain after reset,
|
|||||||
look at how you are setting up JTAG clocking.
|
look at how you are setting up JTAG clocking.
|
||||||
@end quotation
|
@end quotation
|
||||||
|
|
||||||
|
@anchor{The init_targets procedure}
|
||||||
|
@subsection The init_targets procedure
|
||||||
|
@cindex init_targets procedure
|
||||||
|
|
||||||
|
Target config files can either be ``linear'' (script executed line-by-line when parsed in configuration stage,
|
||||||
|
@xref{Configuration Stage},) or they can contain a special procedure called @code{init_targets}, which will be executed
|
||||||
|
when entering run stage (after parsing all config files or after @code{init} command, @xref{Entering the Run Stage}.)
|
||||||
|
Such procedure can be overriden by ``next level'' script (which sources the original). This concept faciliates code
|
||||||
|
reuse when basic target config files provide generic configuration procedures and @code{init_targets} procedure, which
|
||||||
|
can then be sourced and enchanced or changed in a ``more specific'' target config file. This is not possible with
|
||||||
|
``linear'' config scripts, because sourcing them executes every initialization commands they provide.
|
||||||
|
|
||||||
|
@example
|
||||||
|
### generic_file.cfg ###
|
||||||
|
|
||||||
|
proc setup_my_chip @{chip_name flash_size ram_size@} @{
|
||||||
|
# basic initialization procedure ...
|
||||||
|
@}
|
||||||
|
|
||||||
|
proc init_targets @{@} @{
|
||||||
|
# initializes generic chip with 4kB of flash and 1kB of RAM
|
||||||
|
setup_my_chip MY_GENERIC_CHIP 4096 1024
|
||||||
|
@}
|
||||||
|
|
||||||
|
### specific_file.cfg ###
|
||||||
|
|
||||||
|
source [find target/generic_file.cfg]
|
||||||
|
|
||||||
|
proc init_targets @{@} @{
|
||||||
|
# initializes specific chip with 128kB of flash and 64kB of RAM
|
||||||
|
setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536
|
||||||
|
@}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The easiest way to convert ``linear'' config files to @code{init_targets} version is to enclose every line of ``code''
|
||||||
|
(i.e. not @code{source} commands, procedures, etc.) in this procedure.
|
||||||
|
|
||||||
|
For an example of this scheme see LPC2000 target config files.
|
||||||
|
|
||||||
|
The @code{init_boards} procedure is a similar concept concerning board config files (@xref{The init_board procedure}.)
|
||||||
|
|
||||||
@subsection ARM Core Specific Hacks
|
@subsection ARM Core Specific Hacks
|
||||||
|
|
||||||
If the chip has a DCC, enable it. If the chip is an ARM9 with some
|
If the chip has a DCC, enable it. If the chip is an ARM9 with some
|
||||||
@@ -1901,6 +2117,7 @@ may access or activate TAPs.
|
|||||||
After it leaves this stage, configuration commands may no
|
After it leaves this stage, configuration commands may no
|
||||||
longer be issued.
|
longer be issued.
|
||||||
|
|
||||||
|
@anchor{Entering the Run Stage}
|
||||||
@section Entering the Run Stage
|
@section Entering the Run Stage
|
||||||
|
|
||||||
The first thing OpenOCD does after leaving the configuration
|
The first thing OpenOCD does after leaving the configuration
|
||||||
@@ -2323,6 +2540,43 @@ ft2232_vid_pid 0x0403 0xbdc8
|
|||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Interface Driver} {remote_bitbang}
|
||||||
|
Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection
|
||||||
|
with a remote process and sends ASCII encoded bitbang requests to that process
|
||||||
|
instead of directly driving JTAG.
|
||||||
|
|
||||||
|
The remote_bitbang driver is useful for debugging software running on
|
||||||
|
processors which are being simulated.
|
||||||
|
|
||||||
|
@deffn {Config Command} {remote_bitbang_port} number
|
||||||
|
Specifies the TCP port of the remote process to connect to or 0 to use UNIX
|
||||||
|
sockets instead of TCP.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {remote_bitbang_host} hostname
|
||||||
|
Specifies the hostname of the remote process to connect to using TCP, or the
|
||||||
|
name of the UNIX socket to use if remote_bitbang_port is 0.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
For example, to connect remotely via TCP to the host foobar you might have
|
||||||
|
something like:
|
||||||
|
|
||||||
|
@example
|
||||||
|
interface remote_bitbang
|
||||||
|
remote_bitbang_port 3335
|
||||||
|
remote_bitbang_host foobar
|
||||||
|
@end example
|
||||||
|
|
||||||
|
To connect to another process running locally via UNIX sockets with socket
|
||||||
|
named mysocket:
|
||||||
|
|
||||||
|
@example
|
||||||
|
interface remote_bitbang
|
||||||
|
remote_bitbang_port 0
|
||||||
|
remote_bitbang_host mysocket
|
||||||
|
@end example
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Interface Driver} {usb_blaster}
|
@deffn {Interface Driver} {usb_blaster}
|
||||||
USB JTAG/USB-Blaster compatibles over one of the userspace libraries
|
USB JTAG/USB-Blaster compatibles over one of the userspace libraries
|
||||||
for FTDI chips. These interfaces have several commands, used to
|
for FTDI chips. These interfaces have several commands, used to
|
||||||
@@ -2376,33 +2630,56 @@ This is a write-once setting.
|
|||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Interface Driver} {jlink}
|
@deffn {Interface Driver} {jlink}
|
||||||
Segger jlink USB adapter
|
Segger J-Link family of USB adapters. It currently supports only the JTAG transport.
|
||||||
@c command: jlink caps
|
|
||||||
@c dumps jlink capabilities
|
@quotation Compatibility Note
|
||||||
@c command: jlink config
|
Segger released many firmware versions for the many harware versions they
|
||||||
@c access J-Link configurationif no argument this will dump the config
|
produced. OpenOCD was extensively tested and intended to run on all of them,
|
||||||
@c command: jlink config kickstart [val]
|
but some combinations were reported as incompatible. As a general
|
||||||
@c set Kickstart power on JTAG-pin 19.
|
recommendation, it is advisable to use the latest firmware version
|
||||||
@c command: jlink config mac_address [ff:ff:ff:ff:ff:ff]
|
available for each hardware version. However the current V8 is a moving
|
||||||
@c set the MAC Address
|
target, and Segger firmware versions released after the OpenOCD was
|
||||||
@c command: jlink config ip [A.B.C.D[/E] [F.G.H.I]]
|
released may not be compatible. In such cases it is recommended to
|
||||||
@c set the ip address of the J-Link Pro, "
|
revert to the last known functional version. For 0.5.0, this is from
|
||||||
@c where A.B.C.D is the ip,
|
"Feb 8 2012 14:30:39", packed with 4.42c. For 0.6.0, the last known
|
||||||
@c E the bit of the subnet mask
|
version is from "May 3 2012 18:36:22", packed with 4.46f.
|
||||||
@c F.G.H.I the subnet mask
|
@end quotation
|
||||||
@c command: jlink config reset
|
|
||||||
@c reset the current config
|
@deffn {Command} {jlink caps}
|
||||||
@c command: jlink config save
|
Display the device firmware capabilities.
|
||||||
@c save the current config
|
@end deffn
|
||||||
@c command: jlink config usb_address [0x00 to 0x03 or 0xff]
|
@deffn {Command} {jlink info}
|
||||||
@c set the USB-Address,
|
Display various device information, like hardware version, firmware version, current bus status.
|
||||||
@c This will change the product id
|
@end deffn
|
||||||
@c command: jlink info
|
@deffn {Command} {jlink hw_jtag} [@option{2}|@option{3}]
|
||||||
@c dumps status
|
Set the JTAG protocol version to be used. Without argument, show the actual JTAG protocol version.
|
||||||
@c command: jlink hw_jtag (2|3)
|
@end deffn
|
||||||
@c sets version 2 or 3
|
@deffn {Command} {jlink config}
|
||||||
@c command: jlink pid
|
Display the J-Link configuration.
|
||||||
@c set the pid of the interface we want to use
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config kickstart} [val]
|
||||||
|
Set the Kickstart power on JTAG-pin 19. Without argument, show the Kickstart configuration.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config mac_address} [@option{ff:ff:ff:ff:ff:ff}]
|
||||||
|
Set the MAC address of the J-Link Pro. Without argument, show the MAC address.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config ip} [@option{A.B.C.D}(@option{/E}|@option{F.G.H.I})]
|
||||||
|
Set the IP configuration of the J-Link Pro, where A.B.C.D is the IP address,
|
||||||
|
E the bit of the subnet mask and
|
||||||
|
F.G.H.I the subnet mask. Without arguments, show the IP configuration.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config usb_address} [@option{0x00} to @option{0x03} or @option{0xff}]
|
||||||
|
Set the USB address; this will also change the product id. Without argument, show the USB address.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config reset}
|
||||||
|
Reset the current configuration.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Command} {jlink config save}
|
||||||
|
Save the current configuration to the internal persistent storage.
|
||||||
|
@end deffn
|
||||||
|
@deffn {Config} {jlink pid} val
|
||||||
|
Set the USB PID of the interface. As a configuration command, it can be used only before 'init'.
|
||||||
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Interface Driver} {parport}
|
@deffn {Interface Driver} {parport}
|
||||||
@@ -2527,6 +2804,38 @@ which are not currently documented here.
|
|||||||
@end quotation
|
@end quotation
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Interface Driver} {stlink}
|
||||||
|
ST Micro ST-LINK adapter.
|
||||||
|
|
||||||
|
@deffn {Config Command} {stlink_device_desc} description
|
||||||
|
Currently Not Supported.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {stlink_serial} serial
|
||||||
|
Currently Not Supported.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {stlink_layout} (@option{sg}|@option{usb})
|
||||||
|
Specifies the stlink layout to use.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {stlink_vid_pid} vid pid
|
||||||
|
The vendor ID and product ID of the STLINK device.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {stlink_api} api_level
|
||||||
|
Manually sets the stlink api used, valid options are 1 or 2.
|
||||||
|
@end deffn
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Interface Driver} {opendous}
|
||||||
|
opendous-jtag is a freely programmable USB adapter.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Interface Driver} {ulink}
|
||||||
|
This is the Keil ULINK v1 JTAG debugger.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Interface Driver} {ZY1000}
|
@deffn {Interface Driver} {ZY1000}
|
||||||
This is the Zylin ZY1000 JTAG debugger.
|
This is the Zylin ZY1000 JTAG debugger.
|
||||||
@end deffn
|
@end deffn
|
||||||
@@ -3224,7 +3533,7 @@ hardware to find these values.
|
|||||||
option. When vendors put out multiple versions of a chip, or use the same
|
option. When vendors put out multiple versions of a chip, or use the same
|
||||||
JTAG-level ID for several largely-compatible chips, it may be more practical
|
JTAG-level ID for several largely-compatible chips, it may be more practical
|
||||||
to ignore the version field than to update config files to handle all of
|
to ignore the version field than to update config files to handle all of
|
||||||
the various chip IDs.
|
the various chip IDs. The version field is defined as bit 28-31 of the IDCODE.
|
||||||
@item @code{-ircapture} @var{NUMBER}
|
@item @code{-ircapture} @var{NUMBER}
|
||||||
@*The bit pattern loaded by the TAP into the JTAG shift register
|
@*The bit pattern loaded by the TAP into the JTAG shift register
|
||||||
on entry to the @sc{ircapture} state, such as 0x01.
|
on entry to the @sc{ircapture} state, such as 0x01.
|
||||||
@@ -3604,14 +3913,7 @@ At this writing, the supported CPU types and variants are:
|
|||||||
(Support for this is preliminary and incomplete.)
|
(Support for this is preliminary and incomplete.)
|
||||||
@item @code{cortex_a8} -- this is an ARMv7 core with an MMU
|
@item @code{cortex_a8} -- this is an ARMv7 core with an MMU
|
||||||
@item @code{cortex_m3} -- this is an ARMv7 core, supporting only the
|
@item @code{cortex_m3} -- this is an ARMv7 core, supporting only the
|
||||||
compact Thumb2 instruction set. It supports one variant:
|
compact Thumb2 instruction set.
|
||||||
@itemize @minus
|
|
||||||
@item @code{lm3s} ... Use this when debugging older Stellaris LM3S targets.
|
|
||||||
This will cause OpenOCD to use a software reset rather than asserting
|
|
||||||
SRST, to avoid a issue with clearing the debug registers.
|
|
||||||
This is fixed in Fury Rev B, DustDevil Rev B, Tempest; these revisions will
|
|
||||||
be detected and the normal reset behaviour used.
|
|
||||||
@end itemize
|
|
||||||
@item @code{dragonite} -- resembles arm966e
|
@item @code{dragonite} -- resembles arm966e
|
||||||
@item @code{dsp563xx} -- implements Freescale's 24-bit DSP.
|
@item @code{dsp563xx} -- implements Freescale's 24-bit DSP.
|
||||||
(Support for this is still incomplete.)
|
(Support for this is still incomplete.)
|
||||||
@@ -3771,6 +4073,10 @@ base @var{address} to be used when an MMU is active.
|
|||||||
The value should normally correspond to a static mapping for the
|
The value should normally correspond to a static mapping for the
|
||||||
@code{-work-area-phys} address, set up by the current operating system.
|
@code{-work-area-phys} address, set up by the current operating system.
|
||||||
|
|
||||||
|
@item @code{-rtos} @var{rtos_type} -- enable rtos support for target,
|
||||||
|
@var{rtos_type} can be one of @option{auto}|@option{eCos}|@option{ThreadX}|
|
||||||
|
@option{FreeRTOS}|@option{linux}.
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@@ -3962,12 +4268,10 @@ The following target events are defined:
|
|||||||
@* The target has resumed (i.e.: gdb said run)
|
@* The target has resumed (i.e.: gdb said run)
|
||||||
@item @b{early-halted}
|
@item @b{early-halted}
|
||||||
@* Occurs early in the halt process
|
@* Occurs early in the halt process
|
||||||
@ignore
|
|
||||||
@item @b{examine-end}
|
|
||||||
@* Currently not used (goal: when JTAG examine completes)
|
|
||||||
@item @b{examine-start}
|
@item @b{examine-start}
|
||||||
@* Currently not used (goal: when JTAG examine starts)
|
@* Before target examine is called.
|
||||||
@end ignore
|
@item @b{examine-end}
|
||||||
|
@* After target examine is called with no errors.
|
||||||
@item @b{gdb-attach}
|
@item @b{gdb-attach}
|
||||||
@* When GDB connects. This is before any communication with the target, so this
|
@* When GDB connects. This is before any communication with the target, so this
|
||||||
can be used to set up the target so it is possible to probe flash. Probing flash
|
can be used to set up the target so it is possible to probe flash. Probing flash
|
||||||
@@ -3990,12 +4294,6 @@ depending on whether the breakpoint is in RAM or read only memory.
|
|||||||
@* Before the target steps, gdb is trying to start/resume the target
|
@* Before the target steps, gdb is trying to start/resume the target
|
||||||
@item @b{halted}
|
@item @b{halted}
|
||||||
@* The target has halted
|
@* The target has halted
|
||||||
@ignore
|
|
||||||
@item @b{old-gdb_program_config}
|
|
||||||
@* DO NOT USE THIS: Used internally
|
|
||||||
@item @b{old-pre_resume}
|
|
||||||
@* DO NOT USE THIS: Used internally
|
|
||||||
@end ignore
|
|
||||||
@item @b{reset-assert-pre}
|
@item @b{reset-assert-pre}
|
||||||
@* Issued as part of @command{reset} processing
|
@* Issued as part of @command{reset} processing
|
||||||
after @command{reset_init} was triggered
|
after @command{reset_init} was triggered
|
||||||
@@ -4055,13 +4353,10 @@ when reset disables PLLs needed to use a fast clock.
|
|||||||
@* Before any target is resumed
|
@* Before any target is resumed
|
||||||
@item @b{resume-end}
|
@item @b{resume-end}
|
||||||
@* After all targets have resumed
|
@* After all targets have resumed
|
||||||
@item @b{resume-ok}
|
|
||||||
@* Success
|
|
||||||
@item @b{resumed}
|
@item @b{resumed}
|
||||||
@* Target has resumed
|
@* Target has resumed
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
@node Flash Commands
|
@node Flash Commands
|
||||||
@chapter Flash Commands
|
@chapter Flash Commands
|
||||||
|
|
||||||
@@ -4399,6 +4694,7 @@ flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME
|
|||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@anchor{at91sam3}
|
||||||
@deffn {Flash Driver} at91sam3
|
@deffn {Flash Driver} at91sam3
|
||||||
@cindex at91sam3
|
@cindex at91sam3
|
||||||
All members of the AT91SAM3 microcontroller family from
|
All members of the AT91SAM3 microcontroller family from
|
||||||
@@ -4463,6 +4759,13 @@ This command shows/sets the slow clock frequency used in the
|
|||||||
@end deffn
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} at91sam4
|
||||||
|
@cindex at91sam4
|
||||||
|
All members of the AT91SAM4 microcontroller family from
|
||||||
|
Atmel include internal flash and use ARM's Cortex-M4 core.
|
||||||
|
This driver uses the same cmd names/syntax as @xref{at91sam3}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} at91sam7
|
@deffn {Flash Driver} at91sam7
|
||||||
All members of the AT91SAM7 microcontroller family from Atmel include
|
All members of the AT91SAM7 microcontroller family from Atmel include
|
||||||
internal flash and use ARM7TDMI cores. The driver automatically
|
internal flash and use ARM7TDMI cores. The driver automatically
|
||||||
@@ -4516,13 +4819,6 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory.
|
|||||||
@comment - defines mass_erase ... pointless given flash_erase_address
|
@comment - defines mass_erase ... pointless given flash_erase_address
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} ecosflash
|
|
||||||
@emph{No idea what this is...}
|
|
||||||
The @var{ecosflash} driver defines one mandatory parameter,
|
|
||||||
the name of a modules of target code which is downloaded
|
|
||||||
and executed.
|
|
||||||
@end deffn
|
|
||||||
|
|
||||||
@deffn {Flash Driver} lpc2000
|
@deffn {Flash Driver} lpc2000
|
||||||
Most members of the LPC1700 and LPC2000 microcontroller families from NXP
|
Most members of the LPC1700 and LPC2000 microcontroller families from NXP
|
||||||
include internal flash and use Cortex-M3 (LPC1700) or ARM7TDMI (LPC2000) cores.
|
include internal flash and use Cortex-M3 (LPC1700) or ARM7TDMI (LPC2000) cores.
|
||||||
@@ -4764,44 +5060,57 @@ applied to all of them.
|
|||||||
@end quotation
|
@end quotation
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} stm32x
|
@deffn {Flash Driver} stm32f1x
|
||||||
All members of the STM32 microcontroller family from ST Microelectronics
|
All members of the STM32f1x microcontroller family from ST Microelectronics
|
||||||
include internal flash and use ARM Cortex M3 cores.
|
include internal flash and use ARM Cortex M3 cores.
|
||||||
The driver automatically recognizes a number of these chips using
|
The driver automatically recognizes a number of these chips using
|
||||||
the chip identification register, and autoconfigures itself.
|
the chip identification register, and autoconfigures itself.
|
||||||
|
|
||||||
@example
|
@example
|
||||||
flash bank $_FLASHNAME stm32x 0 0 0 0 $_TARGETNAME
|
flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Some stm32x-specific commands
|
If you have a target with dual flash banks then define the second bank
|
||||||
@footnote{Currently there is a @command{stm32x mass_erase} command.
|
as per the following example.
|
||||||
|
@example
|
||||||
|
flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Some stm32f1x-specific commands
|
||||||
|
@footnote{Currently there is a @command{stm32f1x mass_erase} command.
|
||||||
That seems pointless since the same effect can be had using the
|
That seems pointless since the same effect can be had using the
|
||||||
standard @command{flash erase_address} command.}
|
standard @command{flash erase_address} command.}
|
||||||
are defined:
|
are defined:
|
||||||
|
|
||||||
@deffn Command {stm32x lock} num
|
@deffn Command {stm32f1x lock} num
|
||||||
Locks the entire stm32 device.
|
Locks the entire stm32 device.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {stm32x unlock} num
|
@deffn Command {stm32f1x unlock} num
|
||||||
Unlocks the entire stm32 device.
|
Unlocks the entire stm32 device.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {stm32x options_read} num
|
@deffn Command {stm32f1x options_read} num
|
||||||
Read and display the stm32 option bytes written by
|
Read and display the stm32 option bytes written by
|
||||||
the @command{stm32x options_write} command.
|
the @command{stm32f1x options_write} command.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {stm32x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP})
|
@deffn Command {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP})
|
||||||
Writes the stm32 option byte with the specified values.
|
Writes the stm32 option byte with the specified values.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
@end deffn
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} stm32f2x
|
||||||
|
All members of the STM32f2x microcontroller family from ST Microelectronics
|
||||||
|
include internal flash and use ARM Cortex M3 cores.
|
||||||
|
The driver automatically recognizes a number of these chips using
|
||||||
|
the chip identification register, and autoconfigures itself.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} str7x
|
@deffn {Flash Driver} str7x
|
||||||
All members of the STR7 microcontroller family from ST Microelectronics
|
All members of the STR7 microcontroller family from ST Microelectronics
|
||||||
include internal flash and use ARM7TDMI cores.
|
include internal flash and use ARM7TDMI cores.
|
||||||
@@ -4884,6 +5193,19 @@ flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME
|
|||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} fm3
|
||||||
|
All members of the FM3 microcontroller family from Fujitsu
|
||||||
|
include internal flash and use ARM Cortex M3 cores.
|
||||||
|
The @var{fm3} driver uses the @var{target} parameter to select the
|
||||||
|
correct bank config, it can currently be one of the following:
|
||||||
|
@code{mb9bfxx1.cpu}, @code{mb9bfxx2.cpu}, @code{mb9bfxx3.cpu},
|
||||||
|
@code{mb9bfxx4.cpu}, @code{mb9bfxx5.cpu} or @code{mb9bfxx6.cpu}.
|
||||||
|
|
||||||
|
@example
|
||||||
|
flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME
|
||||||
|
@end example
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@subsection str9xpec driver
|
@subsection str9xpec driver
|
||||||
@cindex str9xpec
|
@cindex str9xpec
|
||||||
|
|
||||||
@@ -5424,6 +5746,27 @@ in the MLC controller mode, but won't change SLC behavior.
|
|||||||
@end deffn
|
@end deffn
|
||||||
@comment current lpc3180 code won't issue 5-byte address cycles
|
@comment current lpc3180 code won't issue 5-byte address cycles
|
||||||
|
|
||||||
|
@deffn {NAND Driver} mx3
|
||||||
|
This driver handles the NAND controller in i.MX31. The mxc driver
|
||||||
|
should work for this chip aswell.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {NAND Driver} mxc
|
||||||
|
This driver handles the NAND controller found in Freescale i.MX
|
||||||
|
chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35).
|
||||||
|
The driver takes 3 extra arguments, chip (@option{mx27},
|
||||||
|
@option{mx31}, @option{mx35}), ecc (@option{noecc}, @option{hwecc})
|
||||||
|
and optionally if bad block information should be swapped between
|
||||||
|
main area and spare area (@option{biswap}), defaults to off.
|
||||||
|
@example
|
||||||
|
nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap
|
||||||
|
@end example
|
||||||
|
@deffn Command {mxc biswap} bank_num [enable|disable]
|
||||||
|
Turns on/off bad block information swaping from main area,
|
||||||
|
without parameter query status.
|
||||||
|
@end deffn
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {NAND Driver} orion
|
@deffn {NAND Driver} orion
|
||||||
These controllers require an extra @command{nand device}
|
These controllers require an extra @command{nand device}
|
||||||
parameter: the address of the controller.
|
parameter: the address of the controller.
|
||||||
|
|||||||
@@ -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: 411e92fea9...43d0866133
@@ -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 \
|
||||||
@@ -45,10 +45,11 @@ libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
|||||||
# guess-rev.sh returns either a repository version ID or "-snapshot"
|
# guess-rev.sh returns either a repository version ID or "-snapshot"
|
||||||
if RELEASE
|
if RELEASE
|
||||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
||||||
|
libopenocd_la_CPPFLAGS += -DGITVERSION=\"\"
|
||||||
else
|
else
|
||||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||||
endif
|
|
||||||
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
||||||
|
endif
|
||||||
|
|
||||||
# add default CPPFLAGS
|
# add default CPPFLAGS
|
||||||
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||||
@@ -76,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 \
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include <target/arm.h>
|
#include <target/arm.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 +60,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +96,7 @@ 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 algo;
|
||||||
struct arm *armv4_5 = target->arch_info;
|
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;
|
||||||
@@ -121,10 +120,9 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
|
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
|
||||||
retval = arm_code_to_working_area(target, code, sizeof(code),
|
retval = arm_code_to_working_area(target, code, sizeof(code),
|
||||||
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_WRITE;
|
nand->op = ARM_NAND_WRITE;
|
||||||
|
|
||||||
@@ -152,7 +150,7 @@ 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 + sizeof(code) - 4;
|
||||||
|
|
||||||
/* use alg to write data from work area to NAND chip */
|
/* use alg to write data from work area to NAND chip */
|
||||||
@@ -181,7 +179,7 @@ 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 algo;
|
||||||
struct arm *armv4_5 = target->arch_info;
|
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;
|
||||||
@@ -206,10 +204,9 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
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, code, sizeof(code),
|
||||||
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 + sizeof(code);
|
||||||
@@ -228,7 +225,7 @@ 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 + sizeof(code) - 4;
|
||||||
|
|
||||||
/* use alg to write data from NAND chip to work area */
|
/* use alg to write data from NAND chip to work area */
|
||||||
@@ -246,4 +243,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,11 +9,11 @@ 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 \
|
|
||||||
em357.c \
|
em357.c \
|
||||||
faux.c \
|
faux.c \
|
||||||
lpc2000.c \
|
lpc2000.c \
|
||||||
@@ -24,16 +24,17 @@ NOR_DRIVERS = \
|
|||||||
pic32mx.c \
|
pic32mx.c \
|
||||||
stmsmi.c \
|
stmsmi.c \
|
||||||
stellaris.c \
|
stellaris.c \
|
||||||
stm32x.c \
|
stm32f1x.c \
|
||||||
stm32f2xxx.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 \
|
||||||
# Disabled for now, it generates warnings
|
dsp5680xx_flash.c \
|
||||||
# dsp5680xx_flash.c
|
kinetis.c
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
core.h \
|
core.h \
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -57,7 +56,7 @@ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
|||||||
nbank = malloc(sizeof(struct aduc702x_flash_bank));
|
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;
|
bank->driver_priv = nbank;
|
||||||
|
|
||||||
aduc702x_build_sector_list(bank);
|
aduc702x_build_sector_list(bank);
|
||||||
@@ -67,16 +66,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 +93,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 +108,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 +120,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,7 +152,10 @@ 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 aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
@@ -165,11 +163,10 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
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,50 +186,46 @@ 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)
|
&aduc702x_info->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,
|
retval = target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
||||||
sizeof(aduc702x_flash_write_code), (uint8_t *)aduc702x_flash_write_code);
|
sizeof(aduc702x_flash_write_code), (uint8_t *)aduc702x_flash_write_code);
|
||||||
if (retval != 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) {
|
||||||
{
|
/* if 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)
|
if (aduc702x_info->write_algorithm)
|
||||||
target_free_working_area(target, aduc702x_info->write_algorithm);
|
target_free_working_area(target, aduc702x_info->write_algorithm);
|
||||||
|
|
||||||
@@ -241,9 +234,9 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +244,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, aduc702x_info->write_algorithm->address,
|
||||||
aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
|
aduc702x_info->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;
|
||||||
@@ -302,7 +292,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 +304,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 +339,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 +372,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 +390,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
2319
src/flash/nor/at91sam4.c
Normal file
2319
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,
|
||||||
};
|
};
|
||||||
|
|||||||
1325
src/flash/nor/cfi.c
1325
src/flash/nor/cfi.c
File diff suppressed because it is too large
Load Diff
@@ -17,14 +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;
|
struct working_area *write_algorithm;
|
||||||
|
|
||||||
int x16_as_x8;
|
int x16_as_x8;
|
||||||
@@ -80,8 +80,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 +99,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 +122,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 +137,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 +156,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
|
||||||
@@ -26,16 +27,17 @@ extern struct flash_driver lpc288x_flash;
|
|||||||
extern struct flash_driver lpc2900_flash;
|
extern struct flash_driver lpc2900_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;
|
||||||
extern struct flash_driver aduc702x_flash;
|
extern struct flash_driver aduc702x_flash;
|
||||||
extern struct flash_driver stellaris_flash;
|
extern struct flash_driver stellaris_flash;
|
||||||
extern struct flash_driver str9xpec_flash;
|
extern struct flash_driver str9xpec_flash;
|
||||||
extern struct flash_driver stm32x_flash;
|
extern struct flash_driver stm32f1x_flash;
|
||||||
extern struct flash_driver stm32xf2xxx_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,7 +45,9 @@ 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 kinetis_flash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of built-in flash drivers.
|
* The list of built-in flash drivers.
|
||||||
@@ -56,15 +60,16 @@ static struct flash_driver *flash_drivers[] = {
|
|||||||
&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,
|
||||||
&stellaris_flash,
|
&stellaris_flash,
|
||||||
&str9xpec_flash,
|
&str9xpec_flash,
|
||||||
&stm32x_flash,
|
&stm32f1x_flash,
|
||||||
&stm32xf2xxx_flash,
|
&stm32f2x_flash,
|
||||||
|
&stm32lx_flash,
|
||||||
&tms470_flash,
|
&tms470_flash,
|
||||||
&ecosflash_flash,
|
|
||||||
&ocl_flash,
|
&ocl_flash,
|
||||||
&pic32mx_flash,
|
&pic32mx_flash,
|
||||||
&avr_flash,
|
&avr_flash,
|
||||||
@@ -72,15 +77,15 @@ static struct flash_driver *flash_drivers[] = {
|
|||||||
&virtual_flash,
|
&virtual_flash,
|
||||||
&stmsmi_flash,
|
&stmsmi_flash,
|
||||||
&em357_flash,
|
&em357_flash,
|
||||||
// Disabled for now, it generates warnings
|
&fm3_flash,
|
||||||
//&dsp5680xx_flash,
|
&dsp5680xx_flash,
|
||||||
|
&kinetis_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,14 +35,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#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>
|
||||||
@@ -53,10 +49,13 @@ struct dsp5680xx_flash_bank {
|
|||||||
struct working_area *write_algorithm;
|
struct working_area *write_algorithm;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dsp5680xx_build_sector_list(struct flash_bank *bank){
|
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,19 +63,20 @@ 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;
|
struct dsp5680xx_flash_bank *nbank;
|
||||||
|
|
||||||
nbank = malloc(sizeof(struct dsp5680xx_flash_bank));
|
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->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 +93,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 +121,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 +131,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 +165,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 +196,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 +223,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 +251,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 +281,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
|
|
||||||
};
|
|
||||||
@@ -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,15 +80,13 @@
|
|||||||
#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;
|
struct working_area *write_algorithm;
|
||||||
int ppage_size;
|
int ppage_size;
|
||||||
@@ -103,10 +102,7 @@ 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;
|
||||||
@@ -130,37 +126,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 +322,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 +335,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 +352,13 @@ 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);
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 +368,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 +405,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 +432,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 +443,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];
|
||||||
@@ -488,18 +470,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,32 +497,32 @@ 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)
|
&em357_info->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, em357_info->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) {
|
||||||
{
|
|
||||||
/* if 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)
|
if (em357_info->write_algorithm)
|
||||||
target_free_working_area(target, em357_info->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 = ARMV7M_MODE_ANY;
|
||||||
@@ -548,13 +532,12 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
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 +545,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,
|
em357_info->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 +560,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);
|
||||||
@@ -615,14 +594,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;
|
||||||
}
|
}
|
||||||
@@ -636,20 +613,17 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* 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 +633,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 +653,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);
|
||||||
|
|
||||||
@@ -722,8 +694,7 @@ static int em357_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
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 +704,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 +727,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 +737,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 +748,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 +761,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 +776,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 +785,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,8 +811,7 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -894,10 +848,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 +856,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 +871,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 +898,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 +914,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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -25,9 +26,7 @@
|
|||||||
#include <target/image.h>
|
#include <target/image.h>
|
||||||
#include "hello.h"
|
#include "hello.h"
|
||||||
|
|
||||||
|
struct faux_flash_bank {
|
||||||
struct faux_flash_bank
|
|
||||||
{
|
|
||||||
struct target *target;
|
struct target *target;
|
||||||
uint8_t *memory;
|
uint8_t *memory;
|
||||||
uint32_t start_address;
|
uint32_t start_address;
|
||||||
@@ -43,20 +42,15 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
|||||||
struct faux_flash_bank *info;
|
struct faux_flash_bank *info;
|
||||||
|
|
||||||
if (CMD_ARGC < 6)
|
if (CMD_ARGC < 6)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank faux configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
info = malloc(sizeof(struct faux_flash_bank));
|
info = malloc(sizeof(struct faux_flash_bank));
|
||||||
if (info == NULL)
|
if (info == NULL) {
|
||||||
{
|
|
||||||
LOG_ERROR("no memory for flash bank info");
|
LOG_ERROR("no memory for flash bank info");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
info->memory = malloc(bank->size);
|
info->memory = malloc(bank->size);
|
||||||
if (info == NULL)
|
if (info == NULL) {
|
||||||
{
|
|
||||||
free(info);
|
free(info);
|
||||||
LOG_ERROR("no memory for flash bank info");
|
LOG_ERROR("no memory for flash bank info");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
@@ -68,8 +62,7 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
|||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
bank->num_sectors = bank->size/sectorSize;
|
bank->num_sectors = bank->size/sectorSize;
|
||||||
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 = sectorSize;
|
bank->sectors[i].size = sectorSize;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
@@ -78,8 +71,7 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
info->target = get_target(CMD_ARGV[5]);
|
info->target = get_target(CMD_ARGV[5]);
|
||||||
if (info->target == NULL)
|
if (info->target == NULL) {
|
||||||
{
|
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
||||||
free(info->memory);
|
free(info->memory);
|
||||||
free(info);
|
free(info);
|
||||||
|
|||||||
827
src/flash/nor/fm3.c
Normal file
827
src/flash/nor/fm3.c
Normal file
@@ -0,0 +1,827 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Marc Willam, Holger Wech *
|
||||||
|
* openOCD.fseu(AT)de.fujitsu.com *
|
||||||
|
* Copyright (C) 2011 Ronny Strutz *
|
||||||
|
* *
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#define FLASH_DQ6 0x00000040 /* Data toggle flag bit (TOGG) position */
|
||||||
|
#define FLASH_DQ5 0x00000020 /* Time limit exceeding flag bit (TLOV) position */
|
||||||
|
|
||||||
|
enum fm3_variant {
|
||||||
|
mb9bfxx1, /* Flash Type '1' */
|
||||||
|
mb9bfxx2,
|
||||||
|
mb9bfxx3,
|
||||||
|
mb9bfxx4,
|
||||||
|
mb9bfxx5,
|
||||||
|
mb9bfxx6,
|
||||||
|
mb9afxx1, /* Flash Type '2' */
|
||||||
|
mb9afxx2,
|
||||||
|
mb9afxx3,
|
||||||
|
mb9afxx4,
|
||||||
|
mb9afxx5,
|
||||||
|
mb9afxx6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fm3_flash_type {
|
||||||
|
fm3_no_flash_type = 0,
|
||||||
|
fm3_flash_type1 = 1,
|
||||||
|
fm3_flash_type2 = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fm3_flash_bank {
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
enum fm3_variant variant;
|
||||||
|
enum fm3_flash_type flashtype;
|
||||||
|
int probed;
|
||||||
|
};
|
||||||
|
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command)
|
||||||
|
{
|
||||||
|
struct fm3_flash_bank *fm3_info;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 6)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
fm3_info = malloc(sizeof(struct fm3_flash_bank));
|
||||||
|
bank->driver_priv = fm3_info;
|
||||||
|
|
||||||
|
/* Flash type '1' */
|
||||||
|
if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx1;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx2;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx3;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx4;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx5;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9bfxx6;
|
||||||
|
fm3_info->flashtype = fm3_flash_type1;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) { /* Flash type '2' */
|
||||||
|
fm3_info->variant = mb9afxx1;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9afxx2;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9afxx3;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9afxx4;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9afxx5;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
} else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) {
|
||||||
|
fm3_info->variant = mb9afxx6;
|
||||||
|
fm3_info->flashtype = fm3_flash_type2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unknown Flash type */
|
||||||
|
else {
|
||||||
|
LOG_ERROR("unknown fm3 variant: %s", CMD_ARGV[5]);
|
||||||
|
free(fm3_info);
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
fm3_info->write_algorithm = NULL;
|
||||||
|
fm3_info->probed = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data polling algorithm */
|
||||||
|
static int fm3_busy_wait(struct target *target, uint32_t offset, int timeout_ms)
|
||||||
|
{
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint16_t state1, state2;
|
||||||
|
int ms = 0;
|
||||||
|
|
||||||
|
/* While(1) loop exit via "break" and "return" on error */
|
||||||
|
while (1) {
|
||||||
|
/* dummy-read - see flash manual */
|
||||||
|
retval = target_read_u16(target, offset, &state1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Data polling 1 */
|
||||||
|
retval = target_read_u16(target, offset, &state1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Data polling 2 */
|
||||||
|
retval = target_read_u16(target, offset, &state2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Flash command finished via polled data equal? */
|
||||||
|
if ((state1 & FLASH_DQ6) == (state2 & FLASH_DQ6))
|
||||||
|
break;
|
||||||
|
/* Timeout Flag? */
|
||||||
|
else if (state1 & FLASH_DQ5) {
|
||||||
|
/* Retry data polling */
|
||||||
|
|
||||||
|
/* Data polling 1 */
|
||||||
|
retval = target_read_u16(target, offset, &state1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Data polling 2 */
|
||||||
|
retval = target_read_u16(target, offset, &state2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Flash command finished via polled data equal? */
|
||||||
|
if ((state1 & FLASH_DQ6) != (state2 & FLASH_DQ6))
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
/* finish anyway */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1000);
|
||||||
|
++ms;
|
||||||
|
|
||||||
|
/* Polling time exceeded? */
|
||||||
|
if (ms > timeout_ms) {
|
||||||
|
LOG_ERROR("Polling data reading timed out!");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
LOG_DEBUG("fm3_busy_wait(%x) needs about %d ms", offset, ms);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm3_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
{
|
||||||
|
struct fm3_flash_bank *fm3_info = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint32_t u32DummyRead;
|
||||||
|
int sector, odd;
|
||||||
|
uint32_t u32FlashType;
|
||||||
|
uint32_t u32FlashSeqAddress1;
|
||||||
|
uint32_t u32FlashSeqAddress2;
|
||||||
|
|
||||||
|
u32FlashType = (uint32_t) fm3_info->flashtype;
|
||||||
|
|
||||||
|
if (u32FlashType == fm3_flash_type1) {
|
||||||
|
u32FlashSeqAddress1 = 0x00001550;
|
||||||
|
u32FlashSeqAddress2 = 0x00000AA8;
|
||||||
|
} else if (u32FlashType == fm3_flash_type2) {
|
||||||
|
u32FlashSeqAddress1 = 0x00000AA8;
|
||||||
|
u32FlashSeqAddress2 = 0x00000554;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Flash/Device type unknown!");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Fujitsu MB9Bxxx: Sector Erase ... (%d to %d)", first, last);
|
||||||
|
|
||||||
|
/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash acccess) */
|
||||||
|
retval = target_write_u32(target, 0x40000000, 0x0001);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* dummy read of FASZR */
|
||||||
|
retval = target_read_u32(target, 0x40000000, &u32DummyRead);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
for (sector = first ; sector <= last ; sector++) {
|
||||||
|
uint32_t offset = bank->sectors[sector].offset;
|
||||||
|
|
||||||
|
for (odd = 0; odd < 2 ; odd++) {
|
||||||
|
if (odd)
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
/* Flash unlock sequence */
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x0080);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Sector erase command (0x0030) */
|
||||||
|
retval = target_write_u16(target, offset, 0x0030);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = fm3_busy_wait(target, offset, 500);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
bank->sectors[sector].is_erased = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FASZR = 0x02, Enables CPU Run Mode (32-bit Flash acccess) */
|
||||||
|
retval = target_write_u32(target, 0x40000000, 0x0002);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm3_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct fm3_flash_bank *fm3_info = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint32_t buffer_size = 2048; /* 8192 for MB9Bxx6! */
|
||||||
|
struct working_area *source;
|
||||||
|
uint32_t address = bank->base + offset;
|
||||||
|
struct reg_param reg_params[6];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint32_t u32FlashType;
|
||||||
|
uint32_t u32FlashSeqAddress1;
|
||||||
|
uint32_t u32FlashSeqAddress2;
|
||||||
|
|
||||||
|
u32FlashType = (uint32_t) fm3_info->flashtype;
|
||||||
|
|
||||||
|
if (u32FlashType == fm3_flash_type1) {
|
||||||
|
u32FlashSeqAddress1 = 0x00001550;
|
||||||
|
u32FlashSeqAddress2 = 0x00000AA8;
|
||||||
|
} else if (u32FlashType == fm3_flash_type2) {
|
||||||
|
u32FlashSeqAddress1 = 0x00000AA8;
|
||||||
|
u32FlashSeqAddress2 = 0x00000554;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Flash/Device type unknown!");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RAMCODE used for fm3 Flash programming: */
|
||||||
|
/* R0 keeps source start address (u32Source) */
|
||||||
|
/* R1 keeps target start address (u32Target) */
|
||||||
|
/* R2 keeps number of halfwords to write (u32Count) */
|
||||||
|
/* R3 keeps Flash Sequence address 1 (u32FlashSeq1) */
|
||||||
|
/* R4 keeps Flash Sequence address 2 (u32FlashSeq2) */
|
||||||
|
/* R5 returns result value (u32FlashResult) */
|
||||||
|
|
||||||
|
const uint8_t fm3_flash_write_code[] = {
|
||||||
|
/* fm3_FLASH_IF->FASZ &= 0xFFFD; */
|
||||||
|
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x4F, 0xF6, 0xFD, 0x76, /* MOVW R6, #0xFFFD */
|
||||||
|
0x35, 0x40, /* ANDS R5, R5, R6 */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x35, 0x60, /* STR R5, [R6] */
|
||||||
|
/* fm3_FLASH_IF->FASZ |= 1; */
|
||||||
|
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R3] */
|
||||||
|
0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x35, 0x60, /* STR R5, [R6] */
|
||||||
|
/* u32DummyRead = fm3_FLASH_IF->FASZ; */
|
||||||
|
0x28, 0x4D, /* LDR.N R5, ??u32DummyRead */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x36, 0x68, /* LDR R6, [R6] */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
/* u32FlashResult = FLASH_WRITE_NO_RESULT */
|
||||||
|
0x26, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x00, 0x26, /* MOVS R6, #0 */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
/* while ((u32Count > 0 ) */
|
||||||
|
/* && (u32FlashResult */
|
||||||
|
/* == FLASH_WRITE_NO_RESULT)) */
|
||||||
|
0x01, 0x2A, /* L0: CMP R2, #1 */
|
||||||
|
0x2C, 0xDB, /* BLT.N L1 */
|
||||||
|
0x24, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x00, 0x2D, /* CMP R5, #0 */
|
||||||
|
0x28, 0xD1, /* BNE.N L1 */
|
||||||
|
/* *u32FlashSeq1 = FLASH_WRITE_1; */
|
||||||
|
0xAA, 0x25, /* MOVS R5, #0xAA */
|
||||||
|
0x1D, 0x60, /* STR R5, [R3] */
|
||||||
|
/* *u32FlashSeq2 = FLASH_WRITE_2; */
|
||||||
|
0x55, 0x25, /* MOVS R5, #0x55 */
|
||||||
|
0x25, 0x60, /* STR R5, [R4] */
|
||||||
|
/* *u32FlashSeq1 = FLASH_WRITE_3; */
|
||||||
|
0xA0, 0x25, /* MOVS R5, #0xA0 */
|
||||||
|
0x1D, 0x60, /* STRH R5, [R3] */
|
||||||
|
/* *(volatile uint16_t*)u32Target */
|
||||||
|
/* = *(volatile uint16_t*)u32Source; */
|
||||||
|
0x05, 0x88, /* LDRH R5, [R0] */
|
||||||
|
0x0D, 0x80, /* STRH R5, [R1] */
|
||||||
|
/* while (u32FlashResult */
|
||||||
|
/* == FLASH_WRITE_NO_RESTULT) */
|
||||||
|
0x1E, 0x4D, /* L2: LDR.N R5, ??u32FlashResult */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x00, 0x2D, /* CMP R5, #0 */
|
||||||
|
0x11, 0xD1, /* BNE.N L3 */
|
||||||
|
/* if ((*(volatile uint16_t*)u32Target */
|
||||||
|
/* & FLASH_DQ5) == FLASH_DQ5) */
|
||||||
|
0x0D, 0x88, /* LDRH R5, [R1] */
|
||||||
|
0xAD, 0x06, /* LSLS R5, R5, #0x1A */
|
||||||
|
0x02, 0xD5, /* BPL.N L4 */
|
||||||
|
/* u32FlashResult = FLASH_WRITE_TIMEOUT */
|
||||||
|
0x1A, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x02, 0x26, /* MOVS R6, #2 */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
/* if ((*(volatile uint16_t *)u32Target */
|
||||||
|
/* & FLASH_DQ7) */
|
||||||
|
/* == (*(volatile uint16_t*)u32Source */
|
||||||
|
/* & FLASH_DQ7)) */
|
||||||
|
0x0D, 0x88, /* L4: LDRH R5, [R1] */
|
||||||
|
0x15, 0xF0, 0x80, 0x05, /* ANDS.W R5, R5, #0x80 */
|
||||||
|
0x06, 0x88, /* LDRH R6, [R0] */
|
||||||
|
0x16, 0xF0, 0x80, 0x06, /* ANDS.W R6, R6, #0x80 */
|
||||||
|
0xB5, 0x42, /* CMP R5, R6 */
|
||||||
|
0xED, 0xD1, /* BNE.N L2 */
|
||||||
|
/* u32FlashResult = FLASH_WRITE_OKAY */
|
||||||
|
0x15, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x01, 0x26, /* MOVS R6, #1 */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
0xE9, 0xE7, /* B.N L2 */
|
||||||
|
/* if (u32FlashResult */
|
||||||
|
/* != FLASH_WRITE_TIMEOUT) */
|
||||||
|
0x13, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x02, 0x2D, /* CMP R5, #2 */
|
||||||
|
0x02, 0xD0, /* BEQ.N L5 */
|
||||||
|
/* u32FlashResult = FLASH_WRITE_NO_RESULT */
|
||||||
|
0x11, 0x4D, /* LDR.N R5, ??u32FlashResult */
|
||||||
|
0x00, 0x26, /* MOVS R6, #0 */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
/* u32Count--; */
|
||||||
|
0x52, 0x1E, /* L5: SUBS R2, R2, #1 */
|
||||||
|
/* u32Source += 2; */
|
||||||
|
0x80, 0x1C, /* ADDS R0, R0, #2 */
|
||||||
|
/* u32Target += 2; */
|
||||||
|
0x89, 0x1C, /* ADDS R1, R1, #2 */
|
||||||
|
0xD0, 0xE7, /* B.N L0 */
|
||||||
|
/* fm3_FLASH_IF->FASZ &= 0xFFFE; */
|
||||||
|
0x5F, 0xF0, 0x80, 0x45, /* L1: MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x4F, 0xF6, 0xFE, 0x76, /* MOVW R6, #0xFFFE */
|
||||||
|
0x35, 0x40, /* ANDS R5, R5, R6 */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x35, 0x60, /* STR R5, [R6] */
|
||||||
|
/* fm3_FLASH_IF->FASZ |= 2; */
|
||||||
|
0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x35, 0x60, /* STR R5, [R6] */
|
||||||
|
/* u32DummyRead = fm3_FLASH_IF->FASZ; */
|
||||||
|
0x04, 0x4D, /* LDR.N R5, ??u32DummyRead */
|
||||||
|
0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */
|
||||||
|
0x36, 0x68, /* LDR R6, [R6] */
|
||||||
|
0x2E, 0x60, /* STR R6, [R5] */
|
||||||
|
/* copy u32FlashResult to R3 for return */
|
||||||
|
/* value */
|
||||||
|
0xDF, 0xF8, 0x08, 0x50, /* LDR.W R5, ??u32FlashResult */
|
||||||
|
0x2D, 0x68, /* LDR R5, [R5] */
|
||||||
|
/* Breakpoint here */
|
||||||
|
0x00, 0xBE, /* BKPT #0 */
|
||||||
|
|
||||||
|
/* The following address pointers assume, that the code is running from */
|
||||||
|
/* address 0x1FFF8008. These address pointers will be patched, if a */
|
||||||
|
/* different start address in RAM is used (e.g. for Flash type 2)! */
|
||||||
|
0x00, 0x80, 0xFF, 0x1F, /* u32DummyRead address in RAM (0x1FFF8000) */
|
||||||
|
0x04, 0x80, 0xFF, 0x1F /* u32FlashResult address in RAM (0x1FFF8004) */
|
||||||
|
};
|
||||||
|
|
||||||
|
LOG_INFO("Fujitsu MB9B500: FLASH Write ...");
|
||||||
|
|
||||||
|
/* disable HW watchdog */
|
||||||
|
retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(target, 0x40011008, 0x00000000);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
count = count / 2; /* number bytes -> number halfwords */
|
||||||
|
|
||||||
|
/* check code alignment */
|
||||||
|
if (offset & 0x1) {
|
||||||
|
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate working area with flash programming code */
|
||||||
|
if (target_alloc_working_area(target, sizeof(fm3_flash_write_code),
|
||||||
|
&fm3_info->write_algorithm) != ERROR_OK) {
|
||||||
|
LOG_WARNING("no working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = target_write_buffer(target, fm3_info->write_algorithm->address,
|
||||||
|
sizeof(fm3_flash_write_code), fm3_flash_write_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* memory buffer */
|
||||||
|
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
|
||||||
|
buffer_size /= 2;
|
||||||
|
if (buffer_size <= 256) {
|
||||||
|
/* free working area, if write algorithm already allocated */
|
||||||
|
if (fm3_info->write_algorithm)
|
||||||
|
target_free_working_area(target, fm3_info->write_algorithm);
|
||||||
|
|
||||||
|
LOG_WARNING("No large enough working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARMV7M_MODE_ANY;
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* source start address */
|
||||||
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* target start address */
|
||||||
|
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */
|
||||||
|
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */
|
||||||
|
init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */
|
||||||
|
init_reg_param(®_params[5], "r5", 32, PARAM_IN); /* result */
|
||||||
|
|
||||||
|
/* write code buffer and use Flash programming code within fm3 */
|
||||||
|
/* Set breakpoint to 0 with time-out of 1000 ms */
|
||||||
|
while (count > 0) {
|
||||||
|
uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
|
||||||
|
|
||||||
|
retval = target_write_buffer(target, fm3_info->write_algorithm->address, 8,
|
||||||
|
fm3_flash_write_code);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Patching 'local variable address' for different RAM addresses */
|
||||||
|
if (fm3_info->write_algorithm->address != 0x1FFF8008) {
|
||||||
|
/* Algorithm: u32DummyRead: */
|
||||||
|
retval = target_write_u32(target, (fm3_info->write_algorithm->address)
|
||||||
|
+ sizeof(fm3_flash_write_code) - 8, (fm3_info->write_algorithm->address) - 8);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Algorithm: u32FlashResult: */
|
||||||
|
retval = target_write_u32(target, (fm3_info->write_algorithm->address)
|
||||||
|
+ sizeof(fm3_flash_write_code) - 4, (fm3_info->write_algorithm->address) - 4);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, address);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
|
||||||
|
buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1);
|
||||||
|
buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2);
|
||||||
|
|
||||||
|
retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
|
||||||
|
fm3_info->write_algorithm->address, 0, 1000, &armv7m_info);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Error executing fm3 Flash programming algorithm");
|
||||||
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) {
|
||||||
|
LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %x",
|
||||||
|
buf_get_u32(reg_params[5].value, 0, 32));
|
||||||
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += thisrun_count * 2;
|
||||||
|
address += thisrun_count * 2;
|
||||||
|
count -= thisrun_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_free_working_area(target, source);
|
||||||
|
target_free_working_area(target, fm3_info->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]);
|
||||||
|
destroy_reg_param(®_params[5]);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm3_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct fm3_flash_bank *fm3_info = bank->driver_priv;
|
||||||
|
uint16_t num_pages;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_pages = 6; /* max number of Flash pages for malloc */
|
||||||
|
fm3_info->probed = 0;
|
||||||
|
|
||||||
|
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||||
|
bank->base = 0x00000000;
|
||||||
|
bank->size = 32 * 1024; /* bytes */
|
||||||
|
|
||||||
|
bank->sectors[0].offset = 0;
|
||||||
|
bank->sectors[0].size = 16 * 1024;
|
||||||
|
bank->sectors[0].is_erased = -1;
|
||||||
|
bank->sectors[0].is_protected = -1;
|
||||||
|
|
||||||
|
bank->sectors[1].offset = 0x4000;
|
||||||
|
bank->sectors[1].size = 16 * 1024;
|
||||||
|
bank->sectors[1].is_erased = -1;
|
||||||
|
bank->sectors[1].is_protected = -1;
|
||||||
|
|
||||||
|
if ((fm3_info->variant == mb9bfxx1)
|
||||||
|
|| (fm3_info->variant == mb9afxx1)) {
|
||||||
|
num_pages = 3;
|
||||||
|
bank->size = 64 * 1024; /* bytes */
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
bank->sectors[2].offset = 0x8000;
|
||||||
|
bank->sectors[2].size = 32 * 1024;
|
||||||
|
bank->sectors[2].is_erased = -1;
|
||||||
|
bank->sectors[2].is_protected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fm3_info->variant == mb9bfxx2)
|
||||||
|
|| (fm3_info->variant == mb9bfxx4)
|
||||||
|
|| (fm3_info->variant == mb9bfxx5)
|
||||||
|
|| (fm3_info->variant == mb9bfxx6)
|
||||||
|
|| (fm3_info->variant == mb9afxx2)
|
||||||
|
|| (fm3_info->variant == mb9afxx4)
|
||||||
|
|| (fm3_info->variant == mb9afxx5)
|
||||||
|
|| (fm3_info->variant == mb9afxx6)) {
|
||||||
|
num_pages = 3;
|
||||||
|
bank->size = 128 * 1024; /* bytes */
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
bank->sectors[2].offset = 0x8000;
|
||||||
|
bank->sectors[2].size = 96 * 1024;
|
||||||
|
bank->sectors[2].is_erased = -1;
|
||||||
|
bank->sectors[2].is_protected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fm3_info->variant == mb9bfxx4)
|
||||||
|
|| (fm3_info->variant == mb9bfxx5)
|
||||||
|
|| (fm3_info->variant == mb9bfxx6)
|
||||||
|
|| (fm3_info->variant == mb9afxx4)
|
||||||
|
|| (fm3_info->variant == mb9afxx5)
|
||||||
|
|| (fm3_info->variant == mb9afxx6)) {
|
||||||
|
num_pages = 4;
|
||||||
|
bank->size = 256 * 1024; /* bytes */
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
bank->sectors[3].offset = 0x20000;
|
||||||
|
bank->sectors[3].size = 128 * 1024;
|
||||||
|
bank->sectors[3].is_erased = -1;
|
||||||
|
bank->sectors[3].is_protected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fm3_info->variant == mb9bfxx5)
|
||||||
|
|| (fm3_info->variant == mb9bfxx6)
|
||||||
|
|| (fm3_info->variant == mb9afxx5)
|
||||||
|
|| (fm3_info->variant == mb9afxx6)) {
|
||||||
|
num_pages = 5;
|
||||||
|
bank->size = 384 * 1024; /* bytes */
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
bank->sectors[4].offset = 0x40000;
|
||||||
|
bank->sectors[4].size = 128 * 1024;
|
||||||
|
bank->sectors[4].is_erased = -1;
|
||||||
|
bank->sectors[4].is_protected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fm3_info->variant == mb9bfxx6)
|
||||||
|
|| (fm3_info->variant == mb9afxx6)) {
|
||||||
|
num_pages = 6;
|
||||||
|
bank->size = 512 * 1024; /* bytes */
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
|
||||||
|
bank->sectors[5].offset = 0x60000;
|
||||||
|
bank->sectors[5].size = 128 * 1024;
|
||||||
|
bank->sectors[5].is_erased = -1;
|
||||||
|
bank->sectors[5].is_protected = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fm3_info->probed = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm3_auto_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct fm3_flash_bank *fm3_info = bank->driver_priv;
|
||||||
|
if (fm3_info->probed)
|
||||||
|
return ERROR_OK;
|
||||||
|
return fm3_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fm3_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
snprintf(buf, buf_size, "Fujitsu fm3 Device does not support Chip-ID (Type unknown)");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chip erase */
|
||||||
|
static int fm3_chip_erase(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
struct fm3_flash_bank *fm3_info2 = bank->driver_priv;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint32_t u32DummyRead;
|
||||||
|
uint32_t u32FlashType;
|
||||||
|
uint32_t u32FlashSeqAddress1;
|
||||||
|
uint32_t u32FlashSeqAddress2;
|
||||||
|
|
||||||
|
u32FlashType = (uint32_t) fm3_info2->flashtype;
|
||||||
|
|
||||||
|
if (u32FlashType == fm3_flash_type1) {
|
||||||
|
LOG_INFO("*** Erasing mb9bfxxx type");
|
||||||
|
u32FlashSeqAddress1 = 0x00001550;
|
||||||
|
u32FlashSeqAddress2 = 0x00000AA8;
|
||||||
|
} else if (u32FlashType == fm3_flash_type2) {
|
||||||
|
LOG_INFO("*** Erasing mb9afxxx type");
|
||||||
|
u32FlashSeqAddress1 = 0x00000AA8;
|
||||||
|
u32FlashSeqAddress2 = 0x00000554;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Flash/Device type unknown!");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Fujitsu MB9[AB]xxx: Chip Erase ... (may take several seconds)");
|
||||||
|
|
||||||
|
/* Implement Flash chip erase (mass erase) completely on host */
|
||||||
|
|
||||||
|
/* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */
|
||||||
|
retval = target_write_u32(target, 0x40000000, 0x0001);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* dummy read of FASZR */
|
||||||
|
retval = target_read_u32(target, 0x40000000, &u32DummyRead);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Flash unlock sequence */
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x0080);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* Chip Erase command (0x0010) */
|
||||||
|
retval = target_write_u16(target, u32FlashSeqAddress1, 0x0010);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = fm3_busy_wait(target, u32FlashSeqAddress2, 20000); /* 20s timeout */
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* FASZR = 0x02, Re-enables CPU Run Mode (32-bit Flash access) */
|
||||||
|
retval = target_write_u32(target, 0x40000000, 0x0002);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(fm3_handle_chip_erase_command)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 1)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (fm3_chip_erase(bank) == ERROR_OK) {
|
||||||
|
/* set all sectors as erased */
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
|
||||||
|
command_print(CMD_CTX, "fm3 chip erase complete");
|
||||||
|
} else {
|
||||||
|
command_print(CMD_CTX, "fm3 chip erase failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct command_registration fm3_exec_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "chip_erase",
|
||||||
|
.usage = "<bank>",
|
||||||
|
.handler = fm3_handle_chip_erase_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Erase entire Flash device.",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration fm3_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "fm3",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "fm3 Flash command group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = fm3_exec_command_handlers,
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flash_driver fm3_flash = {
|
||||||
|
.name = "fm3",
|
||||||
|
.commands = fm3_command_handlers,
|
||||||
|
.flash_bank_command = fm3_flash_bank_command,
|
||||||
|
.erase = fm3_erase,
|
||||||
|
.write = fm3_write_block,
|
||||||
|
.probe = fm3_probe,
|
||||||
|
.auto_probe = fm3_auto_probe,
|
||||||
|
.erase_check = default_flash_blank_check,
|
||||||
|
.info = fm3_info,
|
||||||
|
};
|
||||||
@@ -16,13 +16,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 FLASH_NOR_IMP_H
|
#ifndef FLASH_NOR_IMP_H
|
||||||
#define FLASH_NOR_IMP_H
|
#define FLASH_NOR_IMP_H
|
||||||
|
|
||||||
// this is an internal header
|
/* this is an internal header */
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
// almost all drivers will need this file
|
/* almost all drivers will need this file */
|
||||||
#include <target/target.h>
|
#include <target/target.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,4 +48,4 @@ int flash_driver_read(struct flash_bank *bank,
|
|||||||
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);
|
||||||
|
|
||||||
#endif // FLASH_NOR_IMP_H
|
#endif /* FLASH_NOR_IMP_H */
|
||||||
|
|||||||
814
src/flash/nor/kinetis.c
Normal file
814
src/flash/nor/kinetis.c
Normal file
@@ -0,0 +1,814 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Mathias Kuester *
|
||||||
|
* kesmtp@freenet.de *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2011 sleep(5) ltd *
|
||||||
|
* tomas@sleepfive.com *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2012 by Christopher D. Kilgour *
|
||||||
|
* techie at whiterocker.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 "helper/binarybuffer.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation Notes
|
||||||
|
*
|
||||||
|
* The persistent memories in the Kinetis chip families K10 through
|
||||||
|
* K70 are all manipulated with the Flash Memory Module. Some
|
||||||
|
* variants call this module the FTFE, others call it the FTFL. To
|
||||||
|
* indicate that both are considered here, we use FTFX.
|
||||||
|
*
|
||||||
|
* Within the module, according to the chip variant, the persistent
|
||||||
|
* memory is divided into what Freescale terms Program Flash, FlexNVM,
|
||||||
|
* and FlexRAM. All chip variants have Program Flash. Some chip
|
||||||
|
* variants also have FlexNVM and FlexRAM, which always appear
|
||||||
|
* together.
|
||||||
|
*
|
||||||
|
* A given Kinetis chip may have 2 or 4 blocks of flash. Here we map
|
||||||
|
* each block to a separate bank. Each block size varies by chip and
|
||||||
|
* may be determined by the read-only SIM_FCFG1 register. The sector
|
||||||
|
* size within each bank/block varies by the chip granularity as
|
||||||
|
* described below.
|
||||||
|
*
|
||||||
|
* Kinetis offers four different of flash granularities applicable
|
||||||
|
* across the chip families. The granularity is apparently reflected
|
||||||
|
* by at least the reference manual suffix. For example, for chip
|
||||||
|
* MK60FN1M0VLQ12, reference manual K60P144M150SF3RM ends in "SF3RM",
|
||||||
|
* where the "3" indicates there are four flash blocks with 4kiB
|
||||||
|
* sectors. All possible granularities are indicated below.
|
||||||
|
*
|
||||||
|
* The first half of the flash (1 or 2 blocks, depending on the
|
||||||
|
* granularity) is always Program Flash and always starts at address
|
||||||
|
* 0x00000000. The "PFLSH" flag, bit 23 of the read-only SIM_FCFG2
|
||||||
|
* register, determines whether the second half of the flash is also
|
||||||
|
* Program Flash or FlexNVM+FlexRAM. When PFLSH is set, the second
|
||||||
|
* half of flash is Program Flash and is contiguous in the memory map
|
||||||
|
* from the first half. When PFLSH is clear, the second half of flash
|
||||||
|
* is FlexNVM and always starts at address 0x10000000. FlexRAM, which
|
||||||
|
* is also present when PFLSH is clear, always starts at address
|
||||||
|
* 0x14000000.
|
||||||
|
*
|
||||||
|
* The Flash Memory Module provides a register set where flash
|
||||||
|
* commands are loaded to perform flash operations like erase and
|
||||||
|
* program. Different commands are available depending on whether
|
||||||
|
* Program Flash or FlexNVM/FlexRAM is being manipulated. Although
|
||||||
|
* the commands used are quite consistent between flash blocks, the
|
||||||
|
* parameters they accept differ according to the flash granularity.
|
||||||
|
* Some Kinetis chips have different granularity between Program Flash
|
||||||
|
* and FlexNVM/FlexRAM, so flash command arguments may differ between
|
||||||
|
* blocks in the same chip.
|
||||||
|
*
|
||||||
|
* Although not documented as such by Freescale, it appears that bits
|
||||||
|
* 8:7 of the read-only SIM_SDID register reflect the granularity
|
||||||
|
* settings 0..3, so sector sizes and block counts are applicable
|
||||||
|
* according to the following table.
|
||||||
|
*/
|
||||||
|
const struct {
|
||||||
|
unsigned pflash_sector_size_bytes;
|
||||||
|
unsigned nvm_sector_size_bytes;
|
||||||
|
unsigned num_blocks;
|
||||||
|
} kinetis_flash_params[4] = {
|
||||||
|
{ 1<<10, 1<<10, 2 },
|
||||||
|
{ 2<<10, 1<<10, 2 },
|
||||||
|
{ 2<<10, 2<<10, 2 },
|
||||||
|
{ 4<<10, 4<<10, 4 }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kinetis_flash_bank {
|
||||||
|
unsigned granularity;
|
||||||
|
unsigned bank_ordinal;
|
||||||
|
uint32_t sector_size;
|
||||||
|
uint32_t protection_size;
|
||||||
|
|
||||||
|
uint32_t sim_sdid;
|
||||||
|
uint32_t sim_fcfg1;
|
||||||
|
uint32_t sim_fcfg2;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FC_AUTO = 0,
|
||||||
|
FC_PFLASH,
|
||||||
|
FC_FLEX_NVM,
|
||||||
|
FC_FLEX_RAM,
|
||||||
|
} flash_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
|
||||||
|
{
|
||||||
|
struct kinetis_flash_bank *bank_info;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 6)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
LOG_INFO("add flash_bank kinetis %s", bank->name);
|
||||||
|
|
||||||
|
bank_info = malloc(sizeof(struct kinetis_flash_bank));
|
||||||
|
|
||||||
|
memset(bank_info, 0, sizeof(struct kinetis_flash_bank));
|
||||||
|
|
||||||
|
bank->driver_priv = bank_info;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_protect(struct flash_bank *bank, int set, int first,
|
||||||
|
int last)
|
||||||
|
{
|
||||||
|
LOG_WARNING("kinetis_protect not supported yet");
|
||||||
|
/* FIXME: TODO */
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_protect_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kinfo->flash_class == FC_PFLASH) {
|
||||||
|
int result;
|
||||||
|
uint8_t buffer[4];
|
||||||
|
uint32_t fprot, psec;
|
||||||
|
int i, b;
|
||||||
|
|
||||||
|
/* read protection register FTFx_FPROT */
|
||||||
|
result = target_read_memory(bank->target, 0x40020010, 1, 4, buffer);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
fprot = target_buffer_get_u32(bank->target, buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every bit protects 1/32 of the full flash (not necessarily
|
||||||
|
* just this bank), but we enforce the bank ordinals for
|
||||||
|
* PFlash to start at zero.
|
||||||
|
*/
|
||||||
|
b = kinfo->bank_ordinal * (bank->size / kinfo->protection_size);
|
||||||
|
for (psec = 0, i = 0; i < bank->num_sectors; i++) {
|
||||||
|
if ((fprot >> b) & 1)
|
||||||
|
bank->sectors[i].is_protected = 0;
|
||||||
|
else
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
|
||||||
|
psec += bank->sectors[i].size;
|
||||||
|
|
||||||
|
if (psec >= kinfo->protection_size) {
|
||||||
|
psec = 0;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Protection checks for FlexNVM not yet supported");
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_ftfx_command(struct flash_bank *bank, uint32_t w0,
|
||||||
|
uint32_t w1, uint32_t w2, uint8_t *ftfx_fstat)
|
||||||
|
{
|
||||||
|
uint8_t buffer[12];
|
||||||
|
int result, i;
|
||||||
|
|
||||||
|
/* wait for done */
|
||||||
|
for (i = 0; i < 50; i++) {
|
||||||
|
result =
|
||||||
|
target_read_memory(bank->target, 0x40020000, 1, 1, buffer);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (buffer[0] & 0x80)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer[0] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer[0] != 0x80) {
|
||||||
|
/* reset error flags */
|
||||||
|
buffer[0] = 0x30;
|
||||||
|
result =
|
||||||
|
target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_buffer_set_u32(bank->target, buffer, w0);
|
||||||
|
target_buffer_set_u32(bank->target, buffer + 4, w1);
|
||||||
|
target_buffer_set_u32(bank->target, buffer + 8, w2);
|
||||||
|
|
||||||
|
result = target_write_memory(bank->target, 0x40020004, 4, 3, buffer);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* start command */
|
||||||
|
buffer[0] = 0x80;
|
||||||
|
result = target_write_memory(bank->target, 0x40020000, 1, 1, buffer);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* wait for done */
|
||||||
|
for (i = 0; i < 50; i++) {
|
||||||
|
result =
|
||||||
|
target_read_memory(bank->target, 0x40020000, 1, 1, ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (*ftfx_fstat & 0x80)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*ftfx_fstat & 0xf0) != 0x80) {
|
||||||
|
LOG_ERROR
|
||||||
|
("ftfx command failed FSTAT: %02X W0: %08X W1: %08X W2: %08X",
|
||||||
|
*ftfx_fstat, w0, w1, w2);
|
||||||
|
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
{
|
||||||
|
int result, i;
|
||||||
|
uint32_t w0 = 0, w1 = 0, w2 = 0;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first > bank->num_sectors) || (last > bank->num_sectors))
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: TODO: use the 'Erase Flash Block' command if the
|
||||||
|
* requested erase is PFlash or NVM and encompasses the entire
|
||||||
|
* block. Should be quicker.
|
||||||
|
*/
|
||||||
|
for (i = first; i <= last; i++) {
|
||||||
|
uint8_t ftfx_fstat;
|
||||||
|
/* set command and sector address */
|
||||||
|
w0 = (0x09 << 24) | (bank->base + bank->sectors[i].offset);
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK) {
|
||||||
|
LOG_WARNING("erase sector %d failed", i);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first == 0) {
|
||||||
|
LOG_WARNING
|
||||||
|
("flash configuration field erased, please reset the device");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_write(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
unsigned int i, result, fallback = 0;
|
||||||
|
uint8_t buf[8];
|
||||||
|
uint32_t wc, w0 = 0, w1 = 0, w2 = 0;
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kinfo->flash_class == FC_FLEX_NVM) {
|
||||||
|
uint8_t ftfx_fstat;
|
||||||
|
|
||||||
|
LOG_DEBUG("flash write into FlexNVM @%08X", offset);
|
||||||
|
|
||||||
|
/* make flex ram available */
|
||||||
|
w0 = (0x81 << 24) | 0x00ff0000;
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
|
||||||
|
/* check if ram ready */
|
||||||
|
result = target_read_memory(bank->target, 0x40020001, 1, 1, buf);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (!(buf[0] & (1 << 1))) {
|
||||||
|
/* fallback to longword write */
|
||||||
|
fallback = 1;
|
||||||
|
|
||||||
|
LOG_WARNING("ram not ready, fallback to slow longword write (FCNFG: %02X)",
|
||||||
|
buf[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("flash write into PFLASH @08%X", offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* program section command */
|
||||||
|
if (fallback == 0) {
|
||||||
|
unsigned prog_section_bytes = kinfo->sector_size >> 8;
|
||||||
|
for (i = 0; i < count; i += kinfo->sector_size) {
|
||||||
|
/*
|
||||||
|
* The largest possible Kinetis "section" is
|
||||||
|
* 16 bytes. A full Kinetis sector is always
|
||||||
|
* 256 "section"s.
|
||||||
|
*/
|
||||||
|
uint8_t residual_buffer[16];
|
||||||
|
uint8_t ftfx_fstat;
|
||||||
|
uint32_t section_count = 256;
|
||||||
|
uint32_t residual_wc = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume the word count covers an entire
|
||||||
|
* sector.
|
||||||
|
*/
|
||||||
|
wc = kinfo->sector_size / 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If bytes to be programmed are less than the
|
||||||
|
* full sector, then determine the number of
|
||||||
|
* full-words to program, and put together the
|
||||||
|
* residual buffer so that a full "section"
|
||||||
|
* may always be programmed.
|
||||||
|
*/
|
||||||
|
if ((count - i) < kinfo->sector_size) {
|
||||||
|
/* number of bytes to program beyond full section */
|
||||||
|
unsigned residual_bc = (count-i) % prog_section_bytes;
|
||||||
|
|
||||||
|
/* number of complete words to copy directly from buffer */
|
||||||
|
wc = (count - i) / 4;
|
||||||
|
|
||||||
|
/* number of total sections to write, including residual */
|
||||||
|
section_count = DIV_ROUND_UP((count-i), prog_section_bytes);
|
||||||
|
|
||||||
|
/* any residual bytes delivers a whole residual section */
|
||||||
|
residual_wc = (residual_bc ? prog_section_bytes : 0)/4;
|
||||||
|
|
||||||
|
/* clear residual buffer then populate residual bytes */
|
||||||
|
(void) memset(residual_buffer, 0xff, prog_section_bytes);
|
||||||
|
(void) memcpy(residual_buffer, &buffer[i+4*wc], residual_bc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("write section @ %08X with length %d bytes",
|
||||||
|
offset + i, (count - i));
|
||||||
|
|
||||||
|
/* write data to flexram as whole-words */
|
||||||
|
result = target_write_memory(bank->target, 0x14000000, 4, wc,
|
||||||
|
buffer + i);
|
||||||
|
|
||||||
|
if (result != ERROR_OK) {
|
||||||
|
LOG_ERROR("target_write_memory failed");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write the residual words to the flexram */
|
||||||
|
if (residual_wc) {
|
||||||
|
result = target_write_memory(bank->target,
|
||||||
|
0x14000000+4*wc,
|
||||||
|
4, residual_wc,
|
||||||
|
residual_buffer);
|
||||||
|
|
||||||
|
if (result != ERROR_OK) {
|
||||||
|
LOG_ERROR("target_write_memory failed");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* execute section-write command */
|
||||||
|
w0 = (0x0b << 24) | (bank->base + offset + i);
|
||||||
|
w1 = section_count << 16;
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* program longword command, not supported in "SF3" devices */
|
||||||
|
else if (kinfo->granularity != 3) {
|
||||||
|
for (i = 0; i < count; i += 4) {
|
||||||
|
uint8_t ftfx_fstat;
|
||||||
|
|
||||||
|
LOG_DEBUG("write longword @ %08X", offset + i);
|
||||||
|
|
||||||
|
w0 = (0x06 << 24) | (bank->base + offset + i);
|
||||||
|
if (count - i < 4) {
|
||||||
|
uint32_t padding = 0xffffffff;
|
||||||
|
memcpy(&padding, buffer + i, count - i);
|
||||||
|
w1 = buf_get_u32(&padding, 0, 32);
|
||||||
|
} else {
|
||||||
|
w1 = buf_get_u32(buffer + i, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Flash write strategy not implemented");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_read_part_info(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
int result, i;
|
||||||
|
uint8_t buf[4];
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint8_t fcfg1_nvmsize, fcfg1_pfsize, fcfg1_eesize, fcfg2_pflsh;
|
||||||
|
uint32_t nvm_size = 0, pf_size = 0, ee_size = 0;
|
||||||
|
unsigned granularity, num_blocks = 0, num_pflash_blocks = 0, num_nvm_blocks = 0,
|
||||||
|
first_nvm_bank = 0, reassign = 0;
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
result = target_read_memory(bank->target, 0x40048024, 1, 4, buf);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
kinfo->sim_sdid = target_buffer_get_u32(bank->target, buf);
|
||||||
|
granularity = (kinfo->sim_sdid >> 7) & 0x03;
|
||||||
|
result = target_read_memory(bank->target, 0x4004804c, 1, 4, buf);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
kinfo->sim_fcfg1 = target_buffer_get_u32(bank->target, buf);
|
||||||
|
result = target_read_memory(bank->target, 0x40048050, 1, 4, buf);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
kinfo->sim_fcfg2 = target_buffer_get_u32(bank->target, buf);
|
||||||
|
fcfg2_pflsh = (kinfo->sim_fcfg2 >> 23) & 0x01;
|
||||||
|
|
||||||
|
LOG_DEBUG("SDID: %08X FCFG1: %08X FCFG2: %08X", kinfo->sim_sdid,
|
||||||
|
kinfo->sim_fcfg1, kinfo->sim_fcfg2);
|
||||||
|
|
||||||
|
fcfg1_nvmsize = (uint8_t)((kinfo->sim_fcfg1 >> 28) & 0x0f);
|
||||||
|
fcfg1_pfsize = (uint8_t)((kinfo->sim_fcfg1 >> 24) & 0x0f);
|
||||||
|
fcfg1_eesize = (uint8_t)((kinfo->sim_fcfg1 >> 16) & 0x0f);
|
||||||
|
|
||||||
|
/* when the PFLSH bit is set, there is no FlexNVM/FlexRAM */
|
||||||
|
if (!fcfg2_pflsh) {
|
||||||
|
switch (fcfg1_nvmsize) {
|
||||||
|
case 0x03:
|
||||||
|
case 0x07:
|
||||||
|
case 0x09:
|
||||||
|
case 0x0b:
|
||||||
|
nvm_size = 1 << (14 + (fcfg1_nvmsize >> 1));
|
||||||
|
break;
|
||||||
|
case 0x0f:
|
||||||
|
if (granularity == 3)
|
||||||
|
nvm_size = 512<<10;
|
||||||
|
else
|
||||||
|
nvm_size = 256<<10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nvm_size = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fcfg1_eesize) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x03:
|
||||||
|
case 0x04:
|
||||||
|
case 0x05:
|
||||||
|
case 0x06:
|
||||||
|
case 0x07:
|
||||||
|
case 0x08:
|
||||||
|
case 0x09:
|
||||||
|
ee_size = (16 << (10 - fcfg1_eesize));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ee_size = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fcfg1_pfsize) {
|
||||||
|
case 0x03:
|
||||||
|
case 0x05:
|
||||||
|
case 0x07:
|
||||||
|
case 0x09:
|
||||||
|
case 0x0b:
|
||||||
|
case 0x0d:
|
||||||
|
pf_size = 1 << (14 + (fcfg1_pfsize >> 1));
|
||||||
|
break;
|
||||||
|
case 0x0f:
|
||||||
|
if (granularity == 3)
|
||||||
|
pf_size = 1024<<10;
|
||||||
|
else if (fcfg2_pflsh)
|
||||||
|
pf_size = 512<<10;
|
||||||
|
else
|
||||||
|
pf_size = 256<<10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pf_size = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("FlexNVM: %d PFlash: %d FlexRAM: %d PFLSH: %d",
|
||||||
|
nvm_size, pf_size, ee_size, fcfg2_pflsh);
|
||||||
|
|
||||||
|
num_blocks = kinetis_flash_params[granularity].num_blocks;
|
||||||
|
num_pflash_blocks = num_blocks / (2 - fcfg2_pflsh);
|
||||||
|
first_nvm_bank = num_pflash_blocks;
|
||||||
|
num_nvm_blocks = num_blocks - num_pflash_blocks;
|
||||||
|
|
||||||
|
LOG_DEBUG("%d blocks total: %d PFlash, %d FlexNVM",
|
||||||
|
num_blocks, num_pflash_blocks, num_nvm_blocks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the flash class is already assigned, verify the
|
||||||
|
* parameters.
|
||||||
|
*/
|
||||||
|
if (kinfo->flash_class != FC_AUTO) {
|
||||||
|
if (kinfo->bank_ordinal != (unsigned) bank->bank_number) {
|
||||||
|
LOG_WARNING("Flash ordinal/bank number mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (kinfo->granularity != granularity) {
|
||||||
|
LOG_WARNING("Flash granularity mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else {
|
||||||
|
switch (kinfo->flash_class) {
|
||||||
|
case FC_PFLASH:
|
||||||
|
if (kinfo->bank_ordinal >= first_nvm_bank) {
|
||||||
|
LOG_WARNING("Class mismatch, bank %d is not PFlash",
|
||||||
|
bank->bank_number);
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->size != (pf_size / num_pflash_blocks)) {
|
||||||
|
LOG_WARNING("PFlash size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->base !=
|
||||||
|
(0x00000000 + bank->size * kinfo->bank_ordinal)) {
|
||||||
|
LOG_WARNING("PFlash address range mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (kinfo->sector_size !=
|
||||||
|
kinetis_flash_params[granularity].pflash_sector_size_bytes) {
|
||||||
|
LOG_WARNING("PFlash sector size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("PFlash bank %d already configured okay",
|
||||||
|
kinfo->bank_ordinal);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FC_FLEX_NVM:
|
||||||
|
if ((kinfo->bank_ordinal >= num_blocks) ||
|
||||||
|
(kinfo->bank_ordinal < first_nvm_bank)) {
|
||||||
|
LOG_WARNING("Class mismatch, bank %d is not FlexNVM",
|
||||||
|
bank->bank_number);
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->size != (nvm_size / num_nvm_blocks)) {
|
||||||
|
LOG_WARNING("FlexNVM size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->base !=
|
||||||
|
(0x10000000 + bank->size * kinfo->bank_ordinal)) {
|
||||||
|
LOG_WARNING("FlexNVM address range mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (kinfo->sector_size !=
|
||||||
|
kinetis_flash_params[granularity].nvm_sector_size_bytes) {
|
||||||
|
LOG_WARNING("FlexNVM sector size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("FlexNVM bank %d already configured okay",
|
||||||
|
kinfo->bank_ordinal);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FC_FLEX_RAM:
|
||||||
|
if (kinfo->bank_ordinal != num_blocks) {
|
||||||
|
LOG_WARNING("Class mismatch, bank %d is not FlexRAM",
|
||||||
|
bank->bank_number);
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->size != ee_size) {
|
||||||
|
LOG_WARNING("FlexRAM size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (bank->base != 0x14000000) {
|
||||||
|
LOG_WARNING("FlexRAM address mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else if (kinfo->sector_size !=
|
||||||
|
kinetis_flash_params[granularity].nvm_sector_size_bytes) {
|
||||||
|
LOG_WARNING("FlexRAM sector size mismatch");
|
||||||
|
reassign = 1;
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("FlexRAM bank %d already configured okay",
|
||||||
|
kinfo->bank_ordinal);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_WARNING("Unknown or inconsistent flash class");
|
||||||
|
reassign = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Probing flash info for bank %d", bank->bank_number);
|
||||||
|
reassign = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reassign)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
kinfo->granularity = granularity;
|
||||||
|
|
||||||
|
if ((unsigned)bank->bank_number < num_pflash_blocks) {
|
||||||
|
/* pflash, banks start at address zero */
|
||||||
|
kinfo->flash_class = FC_PFLASH;
|
||||||
|
bank->size = (pf_size / num_pflash_blocks);
|
||||||
|
bank->base = 0x00000000 + bank->size * bank->bank_number;
|
||||||
|
kinfo->sector_size = kinetis_flash_params[granularity].pflash_sector_size_bytes;
|
||||||
|
kinfo->protection_size = pf_size / 32;
|
||||||
|
} else if ((unsigned)bank->bank_number < num_blocks) {
|
||||||
|
/* nvm, banks start at address 0x10000000 */
|
||||||
|
kinfo->flash_class = FC_FLEX_NVM;
|
||||||
|
bank->size = (nvm_size / num_nvm_blocks);
|
||||||
|
bank->base = 0x10000000 + bank->size * (bank->bank_number - first_nvm_bank);
|
||||||
|
kinfo->sector_size = kinetis_flash_params[granularity].nvm_sector_size_bytes;
|
||||||
|
kinfo->protection_size = 0; /* FIXME: TODO: depends on DEPART bits, chip */
|
||||||
|
} else if ((unsigned)bank->bank_number == num_blocks) {
|
||||||
|
LOG_ERROR("FlexRAM support not yet implemented");
|
||||||
|
return ERROR_FLASH_OPER_UNSUPPORTED;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Cannot determine parameters for bank %d, only %d banks on device",
|
||||||
|
bank->bank_number, num_blocks);
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bank->sectors) {
|
||||||
|
free(bank->sectors);
|
||||||
|
bank->sectors = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->num_sectors = bank->size / kinfo->sector_size;
|
||||||
|
assert(bank->num_sectors > 0);
|
||||||
|
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 = kinfo->sector_size;
|
||||||
|
offset += kinfo->sector_size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_WARNING("Cannot communicate... target not halted.");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kinetis_read_part_info(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_auto_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
if (kinfo->sim_sdid)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
return kinetis_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
const char *bank_class_names[] = {
|
||||||
|
"(ANY)", "PFlash", "FlexNVM", "FlexRAM"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
(void) snprintf(buf, buf_size,
|
||||||
|
"%s driver for %s flash bank %s at 0x%8.8" PRIx32 "",
|
||||||
|
bank->driver->name, bank_class_names[kinfo->flash_class],
|
||||||
|
bank->name, bank->base);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_blank_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct kinetis_flash_bank *kinfo = bank->driver_priv;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kinfo->flash_class == FC_PFLASH) {
|
||||||
|
int result;
|
||||||
|
uint32_t w0 = 0, w1 = 0, w2 = 0;
|
||||||
|
uint8_t ftfx_fstat;
|
||||||
|
|
||||||
|
/* check if whole bank is blank */
|
||||||
|
w0 = (0x00 << 24) | bank->base;
|
||||||
|
w1 = 0; /* "normal margin" */
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (ftfx_fstat & 0x01) {
|
||||||
|
/* the whole bank is not erased, check sector-by-sector */
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
|
w0 = (0x01 << 24) | (bank->base + bank->sectors[i].offset);
|
||||||
|
w1 = (0x100 << 16) | 0; /* normal margin */
|
||||||
|
|
||||||
|
result = kinetis_ftfx_command(bank, w0, w1, w2, &ftfx_fstat);
|
||||||
|
|
||||||
|
if (result == ERROR_OK) {
|
||||||
|
bank->sectors[i].is_erased = !(ftfx_fstat & 0x01);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Ignoring errored PFlash sector blank-check");
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* the whole bank is erased, update all sectors */
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARNING("kinetis_blank_check not supported yet for FlexNVM");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kinetis_flash_read(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
LOG_WARNING("kinetis_flash_read not supported yet");
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_driver kinetis_flash = {
|
||||||
|
.name = "kinetis",
|
||||||
|
.flash_bank_command = kinetis_flash_bank_command,
|
||||||
|
.erase = kinetis_erase,
|
||||||
|
.protect = kinetis_protect,
|
||||||
|
.write = kinetis_write,
|
||||||
|
.read = kinetis_flash_read,
|
||||||
|
.probe = kinetis_probe,
|
||||||
|
.auto_probe = kinetis_auto_probe,
|
||||||
|
.erase_check = kinetis_blank_check,
|
||||||
|
.protect_check = kinetis_protect_check,
|
||||||
|
.info = kinetis_info,
|
||||||
|
};
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
#include <target/arm_opcodes.h>
|
#include <target/arm_opcodes.h>
|
||||||
#include <target/armv7m.h>
|
#include <target/armv7m.h>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
* flash programming support for NXP LPC17xx and LPC2xxx devices.
|
* flash programming support for NXP LPC17xx and LPC2xxx devices.
|
||||||
@@ -62,15 +61,13 @@
|
|||||||
* - 176x (tested with LPC1768)
|
* - 176x (tested with LPC1768)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
lpc2000_v1,
|
lpc2000_v1,
|
||||||
lpc2000_v2,
|
lpc2000_v2,
|
||||||
lpc1700
|
lpc1700
|
||||||
} lpc2000_variant;
|
} lpc2000_variant;
|
||||||
|
|
||||||
struct lpc2000_flash_bank
|
struct lpc2000_flash_bank {
|
||||||
{
|
|
||||||
lpc2000_variant variant;
|
lpc2000_variant variant;
|
||||||
struct working_area *iap_working_area;
|
struct working_area *iap_working_area;
|
||||||
uint32_t cclk;
|
uint32_t cclk;
|
||||||
@@ -82,8 +79,7 @@ struct lpc2000_flash_bank
|
|||||||
int checksum_vector;
|
int checksum_vector;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lpc2000_status_codes
|
enum lpc2000_status_codes {
|
||||||
{
|
|
||||||
LPC2000_CMD_SUCCESS = 0,
|
LPC2000_CMD_SUCCESS = 0,
|
||||||
LPC2000_INVALID_COMMAND = 1,
|
LPC2000_INVALID_COMMAND = 1,
|
||||||
LPC2000_SRC_ADDR_ERROR = 2,
|
LPC2000_SRC_ADDR_ERROR = 2,
|
||||||
@@ -104,7 +100,6 @@ enum lpc2000_status_codes
|
|||||||
LPC2000_INVALID_BAUD_RATE = 17,
|
LPC2000_INVALID_BAUD_RATE = 17,
|
||||||
LPC2000_INVALID_STOP_BIT = 18,
|
LPC2000_INVALID_STOP_BIT = 18,
|
||||||
LPC2000_CRP_ENABLED = 19
|
LPC2000_CRP_ENABLED = 19
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int lpc2000_build_sector_list(struct flash_bank *bank)
|
static int lpc2000_build_sector_list(struct flash_bank *bank)
|
||||||
@@ -116,63 +111,50 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
/* default to a 4096 write buffer */
|
/* default to a 4096 write buffer */
|
||||||
lpc2000_info->cmd51_max_buffer = 4096;
|
lpc2000_info->cmd51_max_buffer = 4096;
|
||||||
|
|
||||||
if (lpc2000_info->variant == lpc2000_v1)
|
if (lpc2000_info->variant == lpc2000_v1) {
|
||||||
{
|
|
||||||
/* variant 1 has different layout for 128kb and 256kb flashes */
|
/* variant 1 has different layout for 128kb and 256kb flashes */
|
||||||
if (bank->size == 128 * 1024)
|
if (bank->size == 128 * 1024) {
|
||||||
{
|
|
||||||
bank->num_sectors = 16;
|
bank->num_sectors = 16;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * 16);
|
bank->sectors = malloc(sizeof(struct flash_sector) * 16);
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 8 * 1024;
|
bank->sectors[i].size = 8 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
}
|
} else if (bank->size == 256 * 1024) {
|
||||||
else if (bank->size == 256 * 1024)
|
|
||||||
{
|
|
||||||
bank->num_sectors = 18;
|
bank->num_sectors = 18;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * 18);
|
bank->sectors = malloc(sizeof(struct flash_sector) * 18);
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 8 * 1024;
|
bank->sectors[i].size = 8 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
for (i = 8; i < 10; i++)
|
for (i = 8; i < 10; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 64 * 1024;
|
bank->sectors[i].size = 64 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
for (i = 10; i < 18; i++)
|
for (i = 10; i < 18; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 8 * 1024;
|
bank->sectors[i].size = 8 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
} else if (lpc2000_info->variant == lpc2000_v2) {
|
||||||
else if (lpc2000_info->variant == lpc2000_v2)
|
|
||||||
{
|
|
||||||
/* variant 2 has a uniform layout, only number of sectors differs */
|
/* variant 2 has a uniform layout, only number of sectors differs */
|
||||||
switch (bank->size)
|
switch (bank->size) {
|
||||||
{
|
|
||||||
case 4 * 1024:
|
case 4 * 1024:
|
||||||
lpc2000_info->cmd51_max_buffer = 1024;
|
lpc2000_info->cmd51_max_buffer = 1024;
|
||||||
bank->num_sectors = 1;
|
bank->num_sectors = 1;
|
||||||
@@ -211,26 +193,20 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
|
|
||||||
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++) {
|
||||||
{
|
if (i < 8) {
|
||||||
if (i < 8)
|
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 4 * 1024;
|
bank->sectors[i].size = 4 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
} else if (i < 22) {
|
||||||
else if (i < 22)
|
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 32 * 1024;
|
bank->sectors[i].size = 32 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
} else if (i < 28) {
|
||||||
else if (i < 28)
|
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 4 * 1024;
|
bank->sectors[i].size = 4 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
@@ -238,11 +214,8 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (lpc2000_info->variant == lpc1700) {
|
||||||
else if (lpc2000_info->variant == lpc1700)
|
switch (bank->size) {
|
||||||
{
|
|
||||||
switch(bank->size)
|
|
||||||
{
|
|
||||||
case 32 * 1024:
|
case 32 * 1024:
|
||||||
bank->num_sectors = 8;
|
bank->num_sectors = 8;
|
||||||
break;
|
break;
|
||||||
@@ -265,18 +238,16 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
|
|
||||||
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;
|
||||||
/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
|
/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx
|
||||||
|
*devices */
|
||||||
bank->sectors[i].size = (i < 16) ? 4 * 1024 : 32 * 1024;
|
bank->sectors[i].size = (i < 16) ? 4 * 1024 : 32 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@@ -291,38 +262,37 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
* 0x20 to 0x33: command result table (1+4 words)
|
* 0x20 to 0x33: command result table (1+4 words)
|
||||||
* 0x34 to 0xb3: stack (only 128b needed)
|
* 0x34 to 0xb3: stack (only 128b needed)
|
||||||
*/
|
*/
|
||||||
static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
|
static int lpc2000_iap_call(struct flash_bank *bank,
|
||||||
|
int code,
|
||||||
|
uint32_t param_table[5],
|
||||||
|
uint32_t result_table[4])
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
struct mem_param mem_params[2];
|
struct mem_param mem_params[2];
|
||||||
struct reg_param reg_params[5];
|
struct reg_param reg_params[5];
|
||||||
struct arm_algorithm armv4_5_info; /* for LPC2000 */
|
struct arm_algorithm arm_algo; /* for LPC2000 */
|
||||||
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
|
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
|
||||||
uint32_t status_code;
|
uint32_t status_code;
|
||||||
uint32_t iap_entry_point = 0; /* to make compiler happier */
|
uint32_t iap_entry_point = 0; /* to make compiler happier */
|
||||||
|
|
||||||
/* regrab previously allocated working_area, or allocate a new one */
|
/* regrab previously allocated working_area, or allocate a new one */
|
||||||
if (!lpc2000_info->iap_working_area)
|
if (!lpc2000_info->iap_working_area) {
|
||||||
{
|
|
||||||
uint8_t jump_gate[8];
|
uint8_t jump_gate[8];
|
||||||
|
|
||||||
/* make sure we have a working area */
|
/* make sure we have a working area */
|
||||||
if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK)
|
if (target_alloc_working_area(target, 180,
|
||||||
{
|
&lpc2000_info->iap_working_area) != ERROR_OK) {
|
||||||
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
|
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write IAP code to working area */
|
/* write IAP code to working area */
|
||||||
switch(lpc2000_info->variant)
|
switch (lpc2000_info->variant) {
|
||||||
{
|
|
||||||
case lpc1700:
|
case lpc1700:
|
||||||
target_buffer_set_u32(target, jump_gate,
|
target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12));
|
||||||
ARMV4_5_T_BX(12));
|
target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0));
|
||||||
target_buffer_set_u32(target, jump_gate + 4,
|
|
||||||
ARMV5_T_BKPT(0));
|
|
||||||
break;
|
break;
|
||||||
case lpc2000_v1:
|
case lpc2000_v1:
|
||||||
case lpc2000_v2:
|
case lpc2000_v2:
|
||||||
@@ -330,19 +300,21 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
|
target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
|
retval = target_write_memory(target,
|
||||||
{
|
lpc2000_info->iap_working_area->address, 4, 2, jump_gate);
|
||||||
LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR(
|
||||||
|
"Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)",
|
||||||
|
lpc2000_info->iap_working_area->address);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(lpc2000_info->variant)
|
switch (lpc2000_info->variant) {
|
||||||
{
|
|
||||||
case lpc1700:
|
case lpc1700:
|
||||||
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 = ARMV7M_MODE_ANY;
|
||||||
@@ -350,9 +322,9 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
break;
|
break;
|
||||||
case lpc2000_v1:
|
case lpc2000_v1:
|
||||||
case lpc2000_v2:
|
case lpc2000_v2:
|
||||||
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;
|
||||||
iap_entry_point = 0x7ffffff1;
|
iap_entry_point = 0x7ffffff1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -361,7 +333,8 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* command parameter table */
|
/* command parameter table */
|
||||||
init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT);
|
init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4,
|
||||||
|
PARAM_OUT);
|
||||||
target_buffer_set_u32(target, mem_params[0].value, code);
|
target_buffer_set_u32(target, mem_params[0].value, code);
|
||||||
target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
|
target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
|
||||||
target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
|
target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
|
||||||
@@ -373,7 +346,10 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
|
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
|
||||||
|
|
||||||
/* command result table */
|
/* command result table */
|
||||||
init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN);
|
init_mem_param(&mem_params[1],
|
||||||
|
lpc2000_info->iap_working_area->address + 0x20,
|
||||||
|
5 * 4,
|
||||||
|
PARAM_IN);
|
||||||
|
|
||||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
|
buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
|
||||||
@@ -382,45 +358,55 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
|
init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
|
buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
|
||||||
|
|
||||||
switch(lpc2000_info->variant)
|
switch (lpc2000_info->variant) {
|
||||||
{
|
|
||||||
case lpc1700:
|
case lpc1700:
|
||||||
/* IAP stack */
|
/* IAP stack */
|
||||||
init_reg_param(®_params[3], "sp", 32, PARAM_OUT);
|
init_reg_param(®_params[3], "sp", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
|
buf_set_u32(reg_params[3].value, 0, 32,
|
||||||
|
lpc2000_info->iap_working_area->address + 0xb4);
|
||||||
|
|
||||||
/* return address */
|
/* return address */
|
||||||
init_reg_param(®_params[4], "lr", 32, PARAM_OUT);
|
init_reg_param(®_params[4], "lr", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
|
buf_set_u32(reg_params[4].value, 0, 32,
|
||||||
|
(lpc2000_info->iap_working_area->address + 0x04) | 1);
|
||||||
|
/* bit0 of LR = 1 to return in Thumb mode */
|
||||||
|
|
||||||
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
|
target_run_algorithm(target, 2, mem_params, 5, reg_params,
|
||||||
|
lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
|
||||||
break;
|
break;
|
||||||
case lpc2000_v1:
|
case lpc2000_v1:
|
||||||
case lpc2000_v2:
|
case lpc2000_v2:
|
||||||
/* IAP stack */
|
/* IAP stack */
|
||||||
init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT);
|
init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
|
buf_set_u32(reg_params[3].value, 0, 32,
|
||||||
|
lpc2000_info->iap_working_area->address + 0xb4);
|
||||||
|
|
||||||
/* return address */
|
/* return address */
|
||||||
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04);
|
buf_set_u32(reg_params[4].value, 0, 32,
|
||||||
|
lpc2000_info->iap_working_area->address + 0x04);
|
||||||
|
|
||||||
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
|
target_run_algorithm(target, 2, mem_params, 5, reg_params,
|
||||||
|
lpc2000_info->iap_working_area->address,
|
||||||
|
lpc2000_info->iap_working_area->address + 0x4,
|
||||||
|
10000, &arm_algo);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("BUG: unknown lpc2000->variant encountered");
|
LOG_ERROR("BUG: unknown lpc2000->variant encountered");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_code = target_buffer_get_u32(target, mem_params[1].value);
|
status_code = target_buffer_get_u32(target, mem_params[1].value);
|
||||||
result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
|
result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
|
||||||
result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
|
result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
|
||||||
result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
|
result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
|
||||||
result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);
|
result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);
|
||||||
|
|
||||||
LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32") completed with result = %8.8" PRIx32,
|
LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32
|
||||||
code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
|
", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8"
|
||||||
|
PRIx32 ") completed with result = %8.8" PRIx32,
|
||||||
|
code, param_table[0], param_table[1], param_table[2],
|
||||||
|
param_table[3], param_table[4], status_code);
|
||||||
|
|
||||||
destroy_mem_param(&mem_params[0]);
|
destroy_mem_param(&mem_params[0]);
|
||||||
destroy_mem_param(&mem_params[1]);
|
destroy_mem_param(&mem_params[1]);
|
||||||
@@ -436,7 +422,7 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
|
|
||||||
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
|
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
|
||||||
{
|
{
|
||||||
uint32_t param_table[5];
|
uint32_t param_table[5] = {0};
|
||||||
uint32_t result_table[4];
|
uint32_t result_table[4];
|
||||||
int status_code;
|
int status_code;
|
||||||
int i;
|
int i;
|
||||||
@@ -444,14 +430,12 @@ static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
|
|||||||
if ((first < 0) || (last >= bank->num_sectors))
|
if ((first < 0) || (last >= bank->num_sectors))
|
||||||
return ERROR_FLASH_SECTOR_INVALID;
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
|
|
||||||
for (i = first; i <= last; i++)
|
for (i = first; i <= last; i++) {
|
||||||
{
|
|
||||||
/* check single sector */
|
/* check single sector */
|
||||||
param_table[0] = param_table[1] = i;
|
param_table[0] = param_table[1] = i;
|
||||||
status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
|
status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
|
||||||
|
|
||||||
switch (status_code)
|
switch (status_code) {
|
||||||
{
|
|
||||||
case ERROR_FLASH_OPERATION_FAILED:
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
case LPC2000_CMD_SUCCESS:
|
case LPC2000_CMD_SUCCESS:
|
||||||
@@ -483,40 +467,30 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
|||||||
struct lpc2000_flash_bank *lpc2000_info;
|
struct lpc2000_flash_bank *lpc2000_info;
|
||||||
|
|
||||||
if (CMD_ARGC < 8)
|
if (CMD_ARGC < 8)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank lpc2000 configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
|
lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
|
||||||
bank->driver_priv = lpc2000_info;
|
bank->driver_priv = lpc2000_info;
|
||||||
|
|
||||||
if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0)
|
if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0) {
|
||||||
{
|
|
||||||
lpc2000_info->variant = lpc2000_v1;
|
lpc2000_info->variant = lpc2000_v1;
|
||||||
lpc2000_info->cmd51_dst_boundary = 512;
|
lpc2000_info->cmd51_dst_boundary = 512;
|
||||||
lpc2000_info->cmd51_can_256b = 0;
|
lpc2000_info->cmd51_can_256b = 0;
|
||||||
lpc2000_info->cmd51_can_8192b = 1;
|
lpc2000_info->cmd51_can_8192b = 1;
|
||||||
lpc2000_info->checksum_vector = 5;
|
lpc2000_info->checksum_vector = 5;
|
||||||
}
|
} else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0) {
|
||||||
else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0)
|
|
||||||
{
|
|
||||||
lpc2000_info->variant = lpc2000_v2;
|
lpc2000_info->variant = lpc2000_v2;
|
||||||
lpc2000_info->cmd51_dst_boundary = 256;
|
lpc2000_info->cmd51_dst_boundary = 256;
|
||||||
lpc2000_info->cmd51_can_256b = 1;
|
lpc2000_info->cmd51_can_256b = 1;
|
||||||
lpc2000_info->cmd51_can_8192b = 0;
|
lpc2000_info->cmd51_can_8192b = 0;
|
||||||
lpc2000_info->checksum_vector = 5;
|
lpc2000_info->checksum_vector = 5;
|
||||||
}
|
} else if (strcmp(CMD_ARGV[6], "lpc1700") == 0) {
|
||||||
else if (strcmp(CMD_ARGV[6], "lpc1700") == 0)
|
|
||||||
{
|
|
||||||
lpc2000_info->variant = lpc1700;
|
lpc2000_info->variant = lpc1700;
|
||||||
lpc2000_info->cmd51_dst_boundary = 256;
|
lpc2000_info->cmd51_dst_boundary = 256;
|
||||||
lpc2000_info->cmd51_can_256b = 1;
|
lpc2000_info->cmd51_can_256b = 1;
|
||||||
lpc2000_info->cmd51_can_8192b = 0;
|
lpc2000_info->cmd51_can_8192b = 0;
|
||||||
lpc2000_info->checksum_vector = 7;
|
lpc2000_info->checksum_vector = 7;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
|
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
|
||||||
free(lpc2000_info);
|
free(lpc2000_info);
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
@@ -527,8 +501,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
|||||||
lpc2000_info->calc_checksum = 0;
|
lpc2000_info->calc_checksum = 0;
|
||||||
lpc2000_build_sector_list(bank);
|
lpc2000_build_sector_list(bank);
|
||||||
|
|
||||||
if (CMD_ARGC >= 9)
|
if (CMD_ARGC >= 9) {
|
||||||
{
|
|
||||||
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
|
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
|
||||||
lpc2000_info->calc_checksum = 1;
|
lpc2000_info->calc_checksum = 1;
|
||||||
}
|
}
|
||||||
@@ -539,12 +512,11 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
|||||||
static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
||||||
{
|
{
|
||||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||||
uint32_t param_table[5];
|
uint32_t param_table[5] = {0};
|
||||||
uint32_t result_table[4];
|
uint32_t result_table[4];
|
||||||
int status_code;
|
int status_code;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -555,8 +527,7 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
/* Prepare sectors */
|
/* Prepare sectors */
|
||||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||||
switch (status_code)
|
switch (status_code) {
|
||||||
{
|
|
||||||
case ERROR_FLASH_OPERATION_FAILED:
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
case LPC2000_CMD_SUCCESS:
|
case LPC2000_CMD_SUCCESS:
|
||||||
@@ -571,8 +542,7 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
/* Erase sectors */
|
/* Erase sectors */
|
||||||
status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
|
status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
|
||||||
switch (status_code)
|
switch (status_code) {
|
||||||
{
|
|
||||||
case ERROR_FLASH_OPERATION_FAILED:
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
case LPC2000_CMD_SUCCESS:
|
case LPC2000_CMD_SUCCESS:
|
||||||
@@ -603,15 +573,14 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
uint32_t bytes_written = 0;
|
uint32_t bytes_written = 0;
|
||||||
int first_sector = 0;
|
int first_sector = 0;
|
||||||
int last_sector = 0;
|
int last_sector = 0;
|
||||||
uint32_t param_table[5];
|
uint32_t param_table[5] = {0};
|
||||||
uint32_t result_table[4];
|
uint32_t result_table[4];
|
||||||
int status_code;
|
int status_code;
|
||||||
int i;
|
int i;
|
||||||
struct working_area *download_area;
|
struct working_area *download_area;
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -621,55 +590,56 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
|
|
||||||
dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
|
dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
{
|
|
||||||
if (offset >= bank->sectors[i].offset)
|
if (offset >= bank->sectors[i].offset)
|
||||||
first_sector = i;
|
first_sector = i;
|
||||||
if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
|
if (offset + DIV_ROUND_UP(count, dst_min_alignment)
|
||||||
|
* dst_min_alignment > bank->sectors[i].offset)
|
||||||
last_sector = i;
|
last_sector = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
|
LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
|
||||||
|
|
||||||
/* check if exception vectors should be flashed */
|
/* check if exception vectors should be flashed */
|
||||||
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum) {
|
||||||
{
|
|
||||||
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++) {
|
||||||
{
|
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4,
|
||||||
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
buf_get_u32(buffer + (i * 4), 0, 32));
|
||||||
if (i != lpc2000_info->checksum_vector)
|
if (i != lpc2000_info->checksum_vector)
|
||||||
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
||||||
}
|
}
|
||||||
checksum = 0 - checksum;
|
checksum = 0 - checksum;
|
||||||
LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
|
LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
|
||||||
|
|
||||||
uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
|
uint32_t original_value = buf_get_u32(buffer +
|
||||||
if (original_value != checksum)
|
(lpc2000_info->checksum_vector * 4), 0, 32);
|
||||||
{
|
if (original_value != checksum) {
|
||||||
LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32 ").",
|
LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") "
|
||||||
original_value, checksum);
|
"to be written to flash is different from calculated vector "
|
||||||
LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
|
"checksum (0x%8.8" PRIx32 ").", original_value, checksum);
|
||||||
|
LOG_WARNING("To remove this warning modify build tools on developer PC "
|
||||||
|
"to inject correct LPC vector checksum.");
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
|
buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a working area */
|
/* allocate a working area */
|
||||||
if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK)
|
if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer,
|
||||||
{
|
&download_area) != ERROR_OK) {
|
||||||
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
|
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (bytes_remaining > 0)
|
while (bytes_remaining > 0) {
|
||||||
{
|
|
||||||
uint32_t thisrun_bytes;
|
uint32_t thisrun_bytes;
|
||||||
if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
|
if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
|
||||||
thisrun_bytes = lpc2000_info->cmd51_max_buffer;
|
thisrun_bytes = lpc2000_info->cmd51_max_buffer;
|
||||||
@@ -684,8 +654,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
param_table[0] = first_sector;
|
param_table[0] = first_sector;
|
||||||
param_table[1] = last_sector;
|
param_table[1] = last_sector;
|
||||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||||
switch (status_code)
|
switch (status_code) {
|
||||||
{
|
|
||||||
case ERROR_FLASH_OPERATION_FAILED:
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
break;
|
break;
|
||||||
@@ -704,24 +673,28 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (bytes_remaining >= thisrun_bytes)
|
if (bytes_remaining >= thisrun_bytes) {
|
||||||
{
|
retval = target_write_buffer(bank->target, download_area->address,
|
||||||
if ((retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written)) != ERROR_OK)
|
thisrun_bytes, buffer + bytes_written);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
uint8_t *last_buffer = malloc(thisrun_bytes);
|
uint8_t *last_buffer = malloc(thisrun_bytes);
|
||||||
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
||||||
memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
|
memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes -
|
||||||
target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
|
bytes_remaining);
|
||||||
|
target_write_buffer(bank->target,
|
||||||
|
download_area->address,
|
||||||
|
thisrun_bytes,
|
||||||
|
last_buffer);
|
||||||
free(last_buffer);
|
free(last_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32 , thisrun_bytes, bank->base + offset + bytes_written);
|
LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32,
|
||||||
|
thisrun_bytes,
|
||||||
|
bank->base + offset + bytes_written);
|
||||||
|
|
||||||
/* Write data */
|
/* Write data */
|
||||||
param_table[0] = bank->base + offset + bytes_written;
|
param_table[0] = bank->base + offset + bytes_written;
|
||||||
@@ -729,8 +702,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
param_table[2] = thisrun_bytes;
|
param_table[2] = thisrun_bytes;
|
||||||
param_table[3] = lpc2000_info->cclk;
|
param_table[3] = lpc2000_info->cclk;
|
||||||
status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
|
status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
|
||||||
switch (status_code)
|
switch (status_code) {
|
||||||
{
|
|
||||||
case ERROR_FLASH_OPERATION_FAILED:
|
case ERROR_FLASH_OPERATION_FAILED:
|
||||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||||
break;
|
break;
|
||||||
@@ -771,8 +743,7 @@ static int lpc2000_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
static int lpc2000_erase_check(struct flash_bank *bank)
|
static int lpc2000_erase_check(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -790,46 +761,44 @@ static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
|
|||||||
{
|
{
|
||||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||||
|
|
||||||
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
|
snprintf(buf,
|
||||||
|
buf_size,
|
||||||
|
"lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz",
|
||||||
|
lpc2000_info->variant,
|
||||||
|
lpc2000_info->cclk);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(lpc2000_handle_part_id_command)
|
COMMAND_HANDLER(lpc2000_handle_part_id_command)
|
||||||
{
|
{
|
||||||
uint32_t param_table[5];
|
uint32_t param_table[5] = {0};
|
||||||
uint32_t result_table[4];
|
uint32_t result_table[4];
|
||||||
int status_code;
|
int status_code;
|
||||||
|
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 1)
|
||||||
{
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
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 (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 ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
|
status_code = lpc2000_iap_call(bank, 54, param_table, result_table);
|
||||||
{
|
if (status_code != 0x0) {
|
||||||
if (status_code == ERROR_FLASH_OPERATION_FAILED)
|
if (status_code == ERROR_FLASH_OPERATION_FAILED) {
|
||||||
{
|
command_print(CMD_CTX,
|
||||||
command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
|
"no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
|
command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, result_table[0]);
|
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, result_table[0]);
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -840,6 +809,7 @@ static const struct command_registration lpc2000_exec_command_handlers[] = {
|
|||||||
.handler = lpc2000_handle_part_id_command,
|
.handler = lpc2000_handle_part_id_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.help = "print part id of lpc2000 flash bank <num>",
|
.help = "print part id of lpc2000 flash bank <num>",
|
||||||
|
.usage = "<bank>",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
@@ -848,6 +818,7 @@ static const struct command_registration lpc2000_command_handlers[] = {
|
|||||||
.name = "lpc2000",
|
.name = "lpc2000",
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_ANY,
|
||||||
.help = "lpc2000 flash command group",
|
.help = "lpc2000 flash command group",
|
||||||
|
.usage = "",
|
||||||
.chain = lpc2000_exec_command_handlers,
|
.chain = lpc2000_exec_command_handlers,
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
|
|
||||||
|
|
||||||
#define LOAD_TIMER_ERASE 0
|
#define LOAD_TIMER_ERASE 0
|
||||||
#define LOAD_TIMER_WRITE 1
|
#define LOAD_TIMER_WRITE 1
|
||||||
|
|
||||||
@@ -47,15 +46,18 @@
|
|||||||
#define F_STAT 0x80102004 /* Flash status register RO 0x45 */
|
#define F_STAT 0x80102004 /* Flash status register RO 0x45 */
|
||||||
#define F_PROG_TIME 0x80102008 /* Flash program time register R/W 0 */
|
#define F_PROG_TIME 0x80102008 /* Flash program time register R/W 0 */
|
||||||
#define F_WAIT 0x80102010 /* Flash read wait state register R/W 0xC004 */
|
#define F_WAIT 0x80102010 /* Flash read wait state register R/W 0xC004 */
|
||||||
#define F_CLK_TIME 0x8010201C /* Flash clock divider for 66 kHz generation R/W 0 */
|
#define F_CLK_TIME 0x8010201C /* Flash clock divider for 66 kHz generation R/W 0
|
||||||
|
**/
|
||||||
#define F_INTEN_CLR 0x80102FD8 /* Clear interrupt enable bits WO - */
|
#define F_INTEN_CLR 0x80102FD8 /* Clear interrupt enable bits WO - */
|
||||||
#define F_INTEN_SET 0x80102FDC /* Set interrupt enable bits WO - */
|
#define F_INTEN_SET 0x80102FDC /* Set interrupt enable bits WO - */
|
||||||
#define F_INT_STAT 0x80102FE0 /* Interrupt status bits RO 0 */
|
#define F_INT_STAT 0x80102FE0 /* Interrupt status bits RO 0 */
|
||||||
#define F_INTEN 0x80102FE4 /* Interrupt enable bits RO 0 */
|
#define F_INTEN 0x80102FE4 /* Interrupt enable bits RO 0 */
|
||||||
#define F_INT_CLR 0x80102FE8 /* Clear interrupt status bits WO */
|
#define F_INT_CLR 0x80102FE8 /* Clear interrupt status bits WO */
|
||||||
#define F_INT_SET 0x80102FEC /* Set interrupt status bits WO - */
|
#define F_INT_SET 0x80102FEC /* Set interrupt status bits WO - */
|
||||||
#define FLASH_PD 0x80005030 /* Allows turning off the Flash memory for power savings. R/W 1*/
|
#define FLASH_PD 0x80005030 /* Allows turning off the Flash memory for power
|
||||||
#define FLASH_INIT 0x80005034 /* Monitors Flash readiness, such as recovery from Power Down mode. R/W -*/
|
*savings. R/W 1*/
|
||||||
|
#define FLASH_INIT 0x80005034 /* Monitors Flash readiness, such as recovery from
|
||||||
|
*Power Down mode. R/W -*/
|
||||||
|
|
||||||
/* F_CTRL bits */
|
/* F_CTRL bits */
|
||||||
#define FC_CS 0x0001
|
#define FC_CS 0x0001
|
||||||
@@ -84,8 +86,7 @@
|
|||||||
/* F_CLK_TIME */
|
/* F_CLK_TIME */
|
||||||
#define FCT_CLK_DIV_MASK 0x0FFF
|
#define FCT_CLK_DIV_MASK 0x0FFF
|
||||||
|
|
||||||
struct lpc288x_flash_bank
|
struct lpc288x_flash_bank {
|
||||||
{
|
|
||||||
uint32_t working_area;
|
uint32_t working_area;
|
||||||
uint32_t working_area_size;
|
uint32_t working_area_size;
|
||||||
|
|
||||||
@@ -106,15 +107,13 @@ static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
|
|||||||
{
|
{
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
timeout--;
|
timeout--;
|
||||||
target_read_u32(target, F_STAT, &status);
|
target_read_u32(target, F_STAT, &status);
|
||||||
} while (((status & FS_DONE) == 0) && timeout);
|
} while (((status & FS_DONE) == 0) && timeout);
|
||||||
|
|
||||||
if (timeout == 0)
|
if (timeout == 0) {
|
||||||
{
|
|
||||||
LOG_DEBUG("Timedout!");
|
LOG_DEBUG("Timedout!");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -132,13 +131,13 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
|
|||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
|
||||||
if (lpc288x_info->cidr == 0x0102100A)
|
if (lpc288x_info->cidr == 0x0102100A)
|
||||||
return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
|
return ERROR_OK;/* already probed, multiple probes may cause memory leak, not
|
||||||
|
*allowed */
|
||||||
|
|
||||||
/* 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 != 0x0102100A)
|
if (cidr != 0x0102100A) {
|
||||||
{
|
|
||||||
LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")", cidr);
|
LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")", cidr);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -152,16 +151,14 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
|
|||||||
bank->num_sectors = 23;
|
bank->num_sectors = 23;
|
||||||
bank->sectors = malloc(sizeof(struct flash_sector) * 23);
|
bank->sectors = malloc(sizeof(struct flash_sector) * 23);
|
||||||
|
|
||||||
for (i = 0; i < 15; i++)
|
for (i = 0; i < 15; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 64 * 1024;
|
bank->sectors[i].size = 64 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
for (i = 15; i < 23; i++)
|
for (i = 15; i < 23; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 8 * 1024;
|
bank->sectors[i].size = 8 * 1024;
|
||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
@@ -183,10 +180,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
|
|||||||
struct lpc288x_flash_bank *lpc288x_info;
|
struct lpc288x_flash_bank *lpc288x_info;
|
||||||
|
|
||||||
if (CMD_ARGC < 6)
|
if (CMD_ARGC < 6)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank LPC288x configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
|
lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
|
||||||
bank->driver_priv = lpc288x_info;
|
bank->driver_priv = lpc288x_info;
|
||||||
@@ -221,25 +215,18 @@ static void lpc288x_set_flash_clk(struct flash_bank *bank)
|
|||||||
static void lpc288x_load_timer(int erase, struct target *target)
|
static void lpc288x_load_timer(int erase, struct target *target)
|
||||||
{
|
{
|
||||||
if (erase == LOAD_TIMER_ERASE)
|
if (erase == LOAD_TIMER_ERASE)
|
||||||
{
|
|
||||||
target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);
|
target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);
|
target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t lpc288x_system_ready(struct flash_bank *bank)
|
static uint32_t lpc288x_system_ready(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
||||||
if (lpc288x_info->cidr == 0)
|
if (lpc288x_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;
|
||||||
}
|
}
|
||||||
@@ -249,8 +236,7 @@ static uint32_t lpc288x_system_ready(struct flash_bank *bank)
|
|||||||
static int lpc288x_erase_check(struct flash_bank *bank)
|
static int lpc288x_erase_check(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
|
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||||
if (status != ERROR_OK)
|
if (status != ERROR_OK) {
|
||||||
{
|
|
||||||
LOG_INFO("Processor not halted/not probed");
|
LOG_INFO("Processor not halted/not probed");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -266,12 +252,9 @@ static int lpc288x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
status = lpc288x_system_ready(bank); /* probed? halted? */
|
status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||||
if (status != ERROR_OK)
|
if (status != ERROR_OK)
|
||||||
{
|
|
||||||
return status;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
|
||||||
{
|
|
||||||
LOG_INFO("Bad sector range");
|
LOG_INFO("Bad sector range");
|
||||||
return ERROR_FLASH_SECTOR_INVALID;
|
return ERROR_FLASH_SECTOR_INVALID;
|
||||||
}
|
}
|
||||||
@@ -279,12 +262,9 @@ static int lpc288x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
/* Configure the flash controller timing */
|
/* Configure the flash controller timing */
|
||||||
lpc288x_set_flash_clk(bank);
|
lpc288x_set_flash_clk(bank);
|
||||||
|
|
||||||
for (sector = first; sector <= last; sector++)
|
for (sector = first; sector <= last; sector++) {
|
||||||
{
|
|
||||||
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
lpc288x_load_timer(LOAD_TIMER_ERASE, target);
|
lpc288x_load_timer(LOAD_TIMER_ERASE, target);
|
||||||
|
|
||||||
@@ -293,9 +273,7 @@ static int lpc288x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS);
|
target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS);
|
||||||
}
|
}
|
||||||
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,39 +289,34 @@ static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
/* probed? halted? */
|
/* probed? halted? */
|
||||||
status = lpc288x_system_ready(bank);
|
status = lpc288x_system_ready(bank);
|
||||||
if (status != ERROR_OK)
|
if (status != ERROR_OK)
|
||||||
{
|
|
||||||
return status;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialise search indices */
|
/* Initialise search indices */
|
||||||
first_sector = last_sector = 0xffffffff;
|
first_sector = last_sector = 0xffffffff;
|
||||||
|
|
||||||
/* validate the write range... */
|
/* validate the write range... */
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
{
|
|
||||||
if ((offset >= bank->sectors[i].offset) &&
|
if ((offset >= bank->sectors[i].offset) &&
|
||||||
(offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&
|
(offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&
|
||||||
(first_sector == 0xffffffff))
|
(first_sector == 0xffffffff)) {
|
||||||
{
|
|
||||||
first_sector = i;
|
first_sector = i;
|
||||||
/* all writes must start on a sector boundary... */
|
/* all writes must start on a sector boundary... */
|
||||||
if (offset % bank->sectors[i].size)
|
if (offset % bank->sectors[i].size) {
|
||||||
{
|
LOG_INFO(
|
||||||
LOG_INFO("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size);
|
"offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "",
|
||||||
|
offset,
|
||||||
|
bank->sectors[i].size);
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (((offset + count) > bank->sectors[i].offset) &&
|
if (((offset + count) > bank->sectors[i].offset) &&
|
||||||
((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&
|
((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&
|
||||||
(last_sector == 0xffffffff))
|
(last_sector == 0xffffffff))
|
||||||
{
|
|
||||||
last_sector = i;
|
last_sector = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Range check... */
|
/* Range check... */
|
||||||
if (first_sector == 0xffffffff || last_sector == 0xffffffff)
|
if (first_sector == 0xffffffff || last_sector == 0xffffffff) {
|
||||||
{
|
|
||||||
LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
|
LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
|
||||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||||
}
|
}
|
||||||
@@ -355,32 +328,23 @@ static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
source_offset = 0;
|
source_offset = 0;
|
||||||
dest_offset = 0;
|
dest_offset = 0;
|
||||||
|
|
||||||
for (sector = first_sector; sector <= last_sector; sector++)
|
for (sector = first_sector; sector <= last_sector; sector++) {
|
||||||
{
|
for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++) {
|
||||||
for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++)
|
if (bytes_remaining == 0) {
|
||||||
{
|
|
||||||
if (bytes_remaining == 0)
|
|
||||||
{
|
|
||||||
count = 0;
|
count = 0;
|
||||||
memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
|
memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
|
||||||
}
|
} else if (bytes_remaining < FLASH_PAGE_SIZE) {
|
||||||
else if (bytes_remaining < FLASH_PAGE_SIZE)
|
|
||||||
{
|
|
||||||
count = bytes_remaining;
|
count = bytes_remaining;
|
||||||
memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
|
memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
|
||||||
memcpy(page_buffer, &buffer[source_offset], count);
|
memcpy(page_buffer, &buffer[source_offset], count);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
count = FLASH_PAGE_SIZE;
|
count = FLASH_PAGE_SIZE;
|
||||||
memcpy(page_buffer, &buffer[source_offset], count);
|
memcpy(page_buffer, &buffer[source_offset], count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for flash to become ready */
|
/* Wait for flash to become ready */
|
||||||
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
|
||||||
{
|
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
/* fill flash data latches with 1's */
|
/* fill flash data latches with 1's */
|
||||||
target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC);
|
target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC);
|
||||||
@@ -390,14 +354,14 @@ static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
* it seems not to be a LOT slower....
|
* it seems not to be a LOT slower....
|
||||||
* bulk_write_memory() is no quicker :(*/
|
* bulk_write_memory() is no quicker :(*/
|
||||||
#if 1
|
#if 1
|
||||||
if (target_write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)
|
if (target_write_memory(target, offset + dest_offset, 4, 128,
|
||||||
{
|
page_buffer) != ERROR_OK) {
|
||||||
LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page);
|
LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK)
|
if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE,
|
||||||
{
|
page_buffer) != ERROR_OK) {
|
||||||
LOG_INFO("Write to flash buffer failed");
|
LOG_INFO("Write to flash buffer failed");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
@@ -408,7 +372,8 @@ static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
|
|
||||||
lpc288x_load_timer(LOAD_TIMER_WRITE, target);
|
lpc288x_load_timer(LOAD_TIMER_WRITE, target);
|
||||||
|
|
||||||
target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS);
|
target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC |
|
||||||
|
FC_CS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,12 +387,9 @@ static int lpc288x_probe(struct flash_bank *bank)
|
|||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (lpc288x_info->cidr != 0)
|
if (lpc288x_info->cidr != 0)
|
||||||
{
|
|
||||||
return ERROR_OK;/* already probed */
|
return ERROR_OK;/* already 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;
|
||||||
}
|
}
|
||||||
@@ -453,32 +415,25 @@ static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last
|
|||||||
/* probed? halted? */
|
/* probed? halted? */
|
||||||
status = lpc288x_system_ready(bank);
|
status = lpc288x_system_ready(bank);
|
||||||
if (status != ERROR_OK)
|
if (status != ERROR_OK)
|
||||||
{
|
|
||||||
return status;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
||||||
lpc288x_set_flash_clk(bank);
|
lpc288x_set_flash_clk(bank);
|
||||||
|
|
||||||
for (lockregion = first; lockregion <= last; lockregion++)
|
for (lockregion = first; lockregion <= last; lockregion++) {
|
||||||
{
|
if (set) {
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
/* write an odd value to base addy to protect... */
|
/* write an odd value to base addy to protect... */
|
||||||
value = 0x01;
|
value = 0x01;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* write an even value to base addy to unprotect... */
|
/* write an even value to base addy to unprotect... */
|
||||||
value = 0x00;
|
value = 0x00;
|
||||||
}
|
}
|
||||||
target_write_u32(target, bank->sectors[lockregion].offset, value);
|
target_write_u32(target, bank->sectors[lockregion].offset, value);
|
||||||
target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC | FC_CS);
|
target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC |
|
||||||
|
FC_CS);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -27,7 +28,6 @@
|
|||||||
#include "cfi.h"
|
#include "cfi.h"
|
||||||
#include "non_cfi.h"
|
#include "non_cfi.h"
|
||||||
|
|
||||||
|
|
||||||
#define KB 1024
|
#define KB 1024
|
||||||
#define MB (1024*1024)
|
#define MB (1024*1024)
|
||||||
#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
|
#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
|
||||||
@@ -43,8 +43,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(16, 4*KB)
|
ERASE_REGION(16, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -57,8 +56,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(32, 4*KB)
|
ERASE_REGION(32, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -71,8 +69,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(64, 4*KB)
|
ERASE_REGION(64, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -85,8 +82,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(128, 4*KB)
|
ERASE_REGION(128, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -99,8 +95,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(8, 64*KB)
|
ERASE_REGION(8, 64*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -113,8 +108,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(128, 4*KB)
|
ERASE_REGION(128, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -127,8 +121,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -144,8 +137,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(7, 64*KB),
|
ERASE_REGION(7, 64*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
@@ -168,8 +160,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(512, 4*KB)
|
ERASE_REGION(512, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -182,8 +173,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1024, 4*KB)
|
ERASE_REGION(1024, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -196,8 +186,20 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
|
ERASE_REGION(512, 4*KB)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
.mfr = CFI_MFR_SST,
|
||||||
|
.id = 0x274b, /* SST39WF1601 */
|
||||||
|
.pri_id = 0x02,
|
||||||
|
.dev_size = 2*MB,
|
||||||
|
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||||
|
.max_buf_write_size = 0x0,
|
||||||
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
|
.num_erase_regions = 1,
|
||||||
|
.erase_region_info = {
|
||||||
ERASE_REGION(512, 4*KB)
|
ERASE_REGION(512, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -210,8 +212,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(512, 4*KB)
|
ERASE_REGION(512, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -224,8 +225,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1024, 4*KB)
|
ERASE_REGION(1024, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -238,8 +238,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1024, 4*KB)
|
ERASE_REGION(1024, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -252,8 +251,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
.num_erase_regions = 1,
|
.num_erase_regions = 1,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(2048, 4*KB)
|
ERASE_REGION(2048, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -266,8 +264,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -283,8 +280,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(7, 64*KB),
|
ERASE_REGION(7, 64*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
@@ -300,8 +296,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -317,8 +312,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(15, 64*KB),
|
ERASE_REGION(15, 64*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
@@ -334,8 +328,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x00,
|
.max_buf_write_size = 0x00,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -351,8 +344,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -368,8 +360,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -386,8 +377,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -403,14 +393,29 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(31, 64*KB),
|
ERASE_REGION(31, 64*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 16*KB)
|
ERASE_REGION(1, 16*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.mfr = CFI_MFR_EON,
|
||||||
|
.id = 0x225b, /* EN29LV800BB */
|
||||||
|
.pri_id = 0x02,
|
||||||
|
.dev_size = 1*MB,
|
||||||
|
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||||
|
.max_buf_write_size = 0x0,
|
||||||
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
|
.num_erase_regions = 4,
|
||||||
|
.erase_region_info = {
|
||||||
|
ERASE_REGION(1, 16*KB),
|
||||||
|
ERASE_REGION(2, 8*KB),
|
||||||
|
ERASE_REGION(1, 32*KB),
|
||||||
|
ERASE_REGION(15, 64*KB)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.mfr = CFI_MFR_ATMEL,
|
.mfr = CFI_MFR_ATMEL,
|
||||||
.id = 0x00c0, /* Atmel 49BV1614 */
|
.id = 0x00c0, /* Atmel 49BV1614 */
|
||||||
@@ -420,8 +425,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 3,
|
.num_erase_regions = 3,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(8, 8*KB),
|
ERASE_REGION(8, 8*KB),
|
||||||
ERASE_REGION(2, 32*KB),
|
ERASE_REGION(2, 32*KB),
|
||||||
ERASE_REGION(30, 64*KB)
|
ERASE_REGION(30, 64*KB)
|
||||||
@@ -436,8 +440,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 3,
|
.num_erase_regions = 3,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(30, 64*KB),
|
ERASE_REGION(30, 64*KB),
|
||||||
ERASE_REGION(2, 32*KB),
|
ERASE_REGION(2, 32*KB),
|
||||||
ERASE_REGION(8, 8*KB)
|
ERASE_REGION(8, 8*KB)
|
||||||
@@ -452,8 +455,7 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
.max_buf_write_size = 0x0,
|
.max_buf_write_size = 0x0,
|
||||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
.num_erase_regions = 4,
|
.num_erase_regions = 4,
|
||||||
.erase_region_info =
|
.erase_region_info = {
|
||||||
{
|
|
||||||
ERASE_REGION(1, 16*KB),
|
ERASE_REGION(1, 16*KB),
|
||||||
ERASE_REGION(2, 8*KB),
|
ERASE_REGION(2, 8*KB),
|
||||||
ERASE_REGION(1, 32*KB),
|
ERASE_REGION(1, 32*KB),
|
||||||
@@ -477,14 +479,11 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
|
|||||||
else
|
else
|
||||||
mask = 0xFFFF;
|
mask = 0xFFFF;
|
||||||
|
|
||||||
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
|
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++) {
|
||||||
{
|
|
||||||
if ((cfi_info->manufacturer == non_cfi->mfr)
|
if ((cfi_info->manufacturer == non_cfi->mfr)
|
||||||
&& (cfi_info->device_id == (non_cfi->id & mask)))
|
&& (cfi_info->device_id == (non_cfi->id & mask)))
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* only fixup jedec flashs found in table */
|
/* only fixup jedec flashs found in table */
|
||||||
if (!non_cfi->mfr)
|
if (!non_cfi->mfr)
|
||||||
@@ -529,8 +528,7 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
|
|||||||
non_cfi->erase_region_info, erase_region_info_size);
|
non_cfi->erase_region_info, erase_region_info_size);
|
||||||
cfi_info->dev_size = non_cfi->dev_size;
|
cfi_info->dev_size = non_cfi->dev_size;
|
||||||
|
|
||||||
if (cfi_info->pri_id == 0x2)
|
if (cfi_info->pri_id == 0x2) {
|
||||||
{
|
|
||||||
struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
|
struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
|
||||||
|
|
||||||
pri_ext->pri[0] = 'P';
|
pri_ext->pri[0] = 'P';
|
||||||
@@ -558,8 +556,7 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
|
|||||||
pri_ext->_reversed_geometry = 0;
|
pri_ext->_reversed_geometry = 0;
|
||||||
|
|
||||||
cfi_info->pri_ext = pri_ext;
|
cfi_info->pri_ext = pri_ext;
|
||||||
} else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
|
} else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3)) {
|
||||||
{
|
|
||||||
LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
|
LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
* 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 NON_CFI_H
|
#ifndef NON_CFI_H
|
||||||
#define NON_CFI_H
|
#define NON_CFI_H
|
||||||
|
|
||||||
struct non_cfi
|
struct non_cfi {
|
||||||
{
|
|
||||||
uint16_t mfr;
|
uint16_t mfr;
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint16_t pri_id;
|
uint16_t pri_id;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -25,9 +26,7 @@
|
|||||||
#include "ocl.h"
|
#include "ocl.h"
|
||||||
#include <target/embeddedice.h>
|
#include <target/embeddedice.h>
|
||||||
|
|
||||||
|
struct ocl_priv {
|
||||||
struct ocl_priv
|
|
||||||
{
|
|
||||||
struct arm_jtag *jtag_info;
|
struct arm_jtag *jtag_info;
|
||||||
unsigned int buflen;
|
unsigned int buflen;
|
||||||
unsigned int bufalign;
|
unsigned int bufalign;
|
||||||
@@ -50,10 +49,7 @@ FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
|
|||||||
struct ocl_priv *ocl;
|
struct ocl_priv *ocl;
|
||||||
|
|
||||||
if (CMD_ARGC < 6)
|
if (CMD_ARGC < 6)
|
||||||
{
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
LOG_WARNING("incomplete flash_bank ocl configuration");
|
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
arm7_9 = target_to_arm7_9(bank->target);
|
arm7_9 = target_to_arm7_9(bank->target);
|
||||||
if (!is_arm7_9(arm7_9))
|
if (!is_arm7_9(arm7_9))
|
||||||
@@ -77,39 +73,36 @@ static int ocl_erase(struct flash_bank *bank, int first, int last)
|
|||||||
if (bank->num_sectors == 0)
|
if (bank->num_sectors == 0)
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_RUNNING)
|
if (bank->target->state != TARGET_RUNNING) {
|
||||||
{
|
|
||||||
LOG_ERROR("target has to be running to communicate with the loader");
|
LOG_ERROR("target has to be running to communicate with the loader");
|
||||||
return ERROR_TARGET_NOT_RUNNING;
|
return ERROR_TARGET_NOT_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((first == 0) && (last == bank->num_sectors - 1))
|
if ((first == 0) && (last == bank->num_sectors - 1)) {
|
||||||
{
|
|
||||||
dcc_buffer[0] = OCL_ERASE_ALL;
|
dcc_buffer[0] = OCL_ERASE_ALL;
|
||||||
if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
dcc_buffer[0] = OCL_ERASE_BLOCK;
|
dcc_buffer[0] = OCL_ERASE_BLOCK;
|
||||||
dcc_buffer[1] = first;
|
dcc_buffer[1] = first;
|
||||||
dcc_buffer[2] = last;
|
dcc_buffer[2] = last;
|
||||||
if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3) != ERROR_OK))
|
retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
|
||||||
{
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
/* receive response */
|
/* receive response */
|
||||||
if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1) != ERROR_OK))
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (dcc_buffer[1] != OCL_CMD_DONE)
|
if (dcc_buffer[1] != OCL_CMD_DONE) {
|
||||||
{
|
|
||||||
if (dcc_buffer[0] == OCL_ERASE_ALL)
|
if (dcc_buffer[0] == OCL_ERASE_ALL)
|
||||||
LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
|
LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
|
||||||
else
|
else
|
||||||
@@ -141,8 +134,7 @@ static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
if (ocl->buflen == 0 || ocl->bufalign == 0)
|
if (ocl->buflen == 0 || ocl->bufalign == 0)
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
|
|
||||||
if (bank->target->state != TARGET_RUNNING)
|
if (bank->target->state != TARGET_RUNNING) {
|
||||||
{
|
|
||||||
LOG_ERROR("target has to be running to communicate with the loader");
|
LOG_ERROR("target has to be running to communicate with the loader");
|
||||||
return ERROR_TARGET_NOT_RUNNING;
|
return ERROR_TARGET_NOT_RUNNING;
|
||||||
}
|
}
|
||||||
@@ -150,8 +142,7 @@ static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
/* allocate buffer for max. ocl buffer + overhead */
|
/* allocate buffer for max. ocl buffer + overhead */
|
||||||
dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
|
dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
|
||||||
|
|
||||||
while (count)
|
while (count) {
|
||||||
{
|
|
||||||
if (count + (offset % ocl->bufalign) > ocl->buflen)
|
if (count + (offset % ocl->bufalign) > ocl->buflen)
|
||||||
runlen = ocl->buflen - (offset % ocl->bufalign);
|
runlen = ocl->buflen - (offset % ocl->bufalign);
|
||||||
else
|
else
|
||||||
@@ -166,10 +157,8 @@ static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
chksum = OCL_CHKS_INIT;
|
chksum = OCL_CHKS_INIT;
|
||||||
|
|
||||||
/* copy data to DCC buffer in proper byte order and properly aligned */
|
/* copy data to DCC buffer in proper byte order and properly aligned */
|
||||||
for (i = 0; i < runlen; i++)
|
for (i = 0; i < runlen; i++) {
|
||||||
{
|
switch (byteofs++) {
|
||||||
switch (byteofs++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
*dcc_bufptr &= *(buffer++) | 0xffffff00;
|
*dcc_bufptr &= *(buffer++) | 0xffffff00;
|
||||||
break;
|
break;
|
||||||
@@ -195,28 +184,27 @@ static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
*(dcc_bufptr++) = chksum;
|
*(dcc_bufptr++) = chksum;
|
||||||
|
|
||||||
/* send the data */
|
/* send the data */
|
||||||
if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer)) != ERROR_OK)
|
retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
free(dcc_buffer);
|
free(dcc_buffer);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
free(dcc_buffer);
|
free(dcc_buffer);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* receive response */
|
/* receive response */
|
||||||
if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
{
|
if (retval != ERROR_OK) {
|
||||||
free(dcc_buffer);
|
free(dcc_buffer);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dcc_buffer[0] != OCL_CMD_DONE)
|
if (dcc_buffer[0] != OCL_CMD_DONE) {
|
||||||
{
|
|
||||||
LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
|
LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
|
||||||
free(dcc_buffer);
|
free(dcc_buffer);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
@@ -242,50 +230,61 @@ static int ocl_probe(struct flash_bank *bank)
|
|||||||
embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
|
||||||
dcc_buffer[0] = OCL_PROBE;
|
dcc_buffer[0] = OCL_PROBE;
|
||||||
if ((retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000);
|
||||||
{
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
/* receive response */
|
/* receive response */
|
||||||
if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (dcc_buffer[0] != OCL_CMD_DONE)
|
if (dcc_buffer[0] != OCL_CMD_DONE) {
|
||||||
{
|
|
||||||
LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
|
LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* receive and fill in parameters, detection of loader is important, receive it one by one */
|
/* receive and fill in parameters, detection of loader is important, receive it one by one */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
|
||||||
|| (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
bank->base = dcc_buffer[0];
|
bank->base = dcc_buffer[0];
|
||||||
|
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
|
||||||
|| (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
bank->size = dcc_buffer[0];
|
bank->size = dcc_buffer[0];
|
||||||
|
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
|
||||||
|| (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
bank->num_sectors = dcc_buffer[0];
|
bank->num_sectors = dcc_buffer[0];
|
||||||
|
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0) != ERROR_OK)
|
retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0);
|
||||||
|| (retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1) != ERROR_OK))
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
ocl->buflen = dcc_buffer[0] & 0xffff;
|
ocl->buflen = dcc_buffer[0] & 0xffff;
|
||||||
ocl->bufalign = dcc_buffer[0] >> 16;
|
ocl->bufalign = dcc_buffer[0] >> 16;
|
||||||
|
|
||||||
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
|
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
|
||||||
if (bank->num_sectors == 0)
|
if (bank->num_sectors == 0) {
|
||||||
{
|
|
||||||
LOG_ERROR("number of sectors shall be non zero value");
|
LOG_ERROR("number of sectors shall be non zero value");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
@@ -294,8 +293,7 @@ static int ocl_probe(struct flash_bank *bank)
|
|||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
sectsize = bank->size / bank->num_sectors;
|
sectsize = bank->size / bank->num_sectors;
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++) {
|
||||||
{
|
|
||||||
bank->sectors[i].offset = i * sectsize;
|
bank->sectors[i].offset = i * sectsize;
|
||||||
bank->sectors[i].size = sectsize;
|
bank->sectors[i].size = sectsize;
|
||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
@@ -305,20 +303,17 @@ static int ocl_probe(struct flash_bank *bank)
|
|||||||
if (ocl->bufalign == 0)
|
if (ocl->bufalign == 0)
|
||||||
ocl->bufalign = 1;
|
ocl->bufalign = 1;
|
||||||
|
|
||||||
if (ocl->buflen == 0)
|
if (ocl->buflen == 0) {
|
||||||
{
|
|
||||||
LOG_ERROR("buflen shall be non zero value");
|
LOG_ERROR("buflen shall be non zero value");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign))
|
if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign)) {
|
||||||
{
|
|
||||||
LOG_ERROR("buflen is not multiple of bufalign");
|
LOG_ERROR("buflen is not multiple of bufalign");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocl->buflen % 4)
|
if (ocl->buflen % 4) {
|
||||||
{
|
|
||||||
LOG_ERROR("buflen shall be divisible by 4");
|
LOG_ERROR("buflen shall be divisible by 4");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user