forked from auracaster/openocd
Compare commits
749 Commits
v0.5.0-rc1
...
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 | ||
|
|
d4cd6f0320 | ||
|
|
89fa8ce2d8 | ||
|
|
bad3ee87ac | ||
|
|
f6026a8295 | ||
|
|
d567df02b9 | ||
|
|
2482244b07 | ||
|
|
e4c054cada |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -79,6 +79,7 @@ NOTES
|
||||
|
||||
# coexist with quilt
|
||||
patches
|
||||
*.patch
|
||||
|
||||
# Eclipse stuff
|
||||
.project
|
||||
@@ -88,5 +89,8 @@ patches
|
||||
# Emacs temp files
|
||||
*~
|
||||
|
||||
# Emacs TAGS file
|
||||
TAGS
|
||||
|
||||
# CScope database files
|
||||
*cscope.out
|
||||
|
||||
4
BUGS
4
BUGS
@@ -4,7 +4,7 @@
|
||||
Please report bugs by subscribing to the OpenOCD mailing list and
|
||||
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
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
Attach all files directly to your posting. The mailing list knows to
|
||||
|
||||
2
COPYING
2
COPYING
@@ -2,7 +2,7 @@
|
||||
Version 2, June 1991
|
||||
|
||||
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
|
||||
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
|
||||
# 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)
|
||||
# defined locally in source files will be included in the documentation.
|
||||
@@ -567,7 +567,7 @@ WARN_LOGFILE =
|
||||
INPUT = @srcdir@/doc/manual \
|
||||
@srcdir@/TODO \
|
||||
@srcdir@/BUGS \
|
||||
@srcdir@/PATCHES.txt \
|
||||
@srcdir@/HACKING \
|
||||
@srcdir@/src \
|
||||
@builddir@/config.h
|
||||
|
||||
|
||||
165
HACKING
165
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
|
||||
you have figured out how to clone the OpenOCD git
|
||||
repository.
|
||||
@b NB! If you're behind a corporate wall with http only access to the
|
||||
world, you can still use these instructions!
|
||||
|
||||
Below is a basic workflow and specific instructions
|
||||
to get you going with git and patches.
|
||||
@b NB2! You can't send patches to the mailing list anymore at all. Nowadays
|
||||
you are expected to send patches to the OpenOCD Gerrit GIT server for a
|
||||
review.
|
||||
|
||||
0. Clone the git repository, rather than just
|
||||
download the source.
|
||||
@section gerrit Submitting patches to the OpenOCD Gerrit server
|
||||
|
||||
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
||||
OpenOCD is to some extent a "self service" open source project, so to
|
||||
contribute, you must follow the standard procedures to have the best
|
||||
possible chance to get your changes accepted.
|
||||
|
||||
or if you have problems with the "git:" protocol, use
|
||||
the slower http protocol:
|
||||
The procedure to create a patch is essentially:
|
||||
|
||||
git clone http://repo.or.cz/r/openocd.git
|
||||
- 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
|
||||
|
||||
1. Set up git with your name and email:
|
||||
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
|
||||
@endcode
|
||||
or if you have problems with the "git:" protocol, use
|
||||
the slower http protocol:
|
||||
@code
|
||||
git clone http://repo.or.cz/r/openocd.git
|
||||
@endcode
|
||||
-# 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.email "john@smith.org"
|
||||
|
||||
2. Work on your patches. Split the work into
|
||||
multiple small patches that can be reviewed and
|
||||
applied seperately and safely to the OpenOCD
|
||||
repository.
|
||||
|
||||
@endcode
|
||||
-# Work on your patches. Split the work into
|
||||
multiple small patches that can be reviewed and
|
||||
applied seperately and safely to the OpenOCD
|
||||
repository.
|
||||
@code
|
||||
while(!done) {
|
||||
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.
|
||||
}
|
||||
|
||||
TIP! use "git add ." before commit to add new files.
|
||||
|
||||
@endcode
|
||||
@b TIP! use "git add ." before commit to add new files.
|
||||
@code
|
||||
--- example comment, notice the short first line w/topic ---
|
||||
topic: short comment
|
||||
<blank line>
|
||||
longer comments over several
|
||||
lines...
|
||||
<blank line>
|
||||
Signed-off-by: ...
|
||||
-----
|
||||
@endcode
|
||||
-# Next you need to make sure that your patches
|
||||
are on top of the latest stuff on the server and
|
||||
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
|
||||
|
||||
3. Next you need to make sure that your patches
|
||||
are on top of the latest stuff on the server and
|
||||
that there are no conflicts.
|
||||
Further reading: http://www.coreboot.org/Git
|
||||
|
||||
git pull --rebase
|
||||
@section timeline When can I expect my contribution to be committed?
|
||||
|
||||
4. Generate the patch files. This will generate
|
||||
patches for all commits that are on top of
|
||||
the latest stuff on the server:
|
||||
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.
|
||||
|
||||
git format-patch origin/master
|
||||
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.
|
||||
|
||||
5. Email the patches to openocd-development@lists.berlios.de
|
||||
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
|
||||
|
||||
# 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 = \
|
||||
contrib/libdcc/dcc_stdio.c \
|
||||
@@ -24,7 +24,6 @@ EXTRA_DIST = \
|
||||
BUGS \
|
||||
HACKING \
|
||||
NEWTAPS \
|
||||
PATCHES.txt \
|
||||
README.Win32 \
|
||||
Doxyfile.in \
|
||||
tools/logger.pl \
|
||||
@@ -64,10 +63,13 @@ $(THE_MANUAL): %.pdf: %.tex
|
||||
|
||||
TCL_PATH = tcl
|
||||
# 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),,'
|
||||
|
||||
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 \
|
||||
j="$(distdir)/$(TCL_PATH)/$$i" && \
|
||||
mkdir -p "$$(dirname $$j)" && \
|
||||
|
||||
76
NEWS
76
NEWS
@@ -1,63 +1,44 @@
|
||||
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.
|
||||
OpenOCD 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.
|
||||
New STLINK V1/V2 JTAG/SWD adapter support.
|
||||
New OSJTAG adapter support.
|
||||
New Tincantools Flyswatter2 support.
|
||||
Improved ULINK driver.
|
||||
Improved RLINK driver.
|
||||
Support for adapters based on FT232H chips.
|
||||
New experimental driver for FTDI based adapters, using libusb-1.0 in asynchronous mode.
|
||||
|
||||
Boundary Scan:
|
||||
|
||||
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.
|
||||
New Cortex-M0 support.
|
||||
New Cortex-M4 support.
|
||||
Improved Working area algorithm.
|
||||
New RTOS support. Currently linux, FreeRTOS, ThreadX and eCos.
|
||||
Connecting under reset to Cortex-Mx and MIPS chips.
|
||||
|
||||
Flash Layer:
|
||||
New "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.
|
||||
New SST39WF1601 support.
|
||||
New EN29LV800BB support.
|
||||
New async algorithm support for selected targets, stm32, stellaris and pic32.
|
||||
New Atmel SAM3S, SAM3N support.
|
||||
New ST STM32L support.
|
||||
New Microchip PIC32MX1xx/2xx support.
|
||||
New Freescale Kinetis K40 support.
|
||||
|
||||
Board, Target, and Interface Configuration Scripts:
|
||||
Support 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.
|
||||
Support Dangerous Prototypes Bus Blaster.
|
||||
Support ST SPEAr Family.
|
||||
Support Gumstix Verdex boards.
|
||||
Support TI Beaglebone.
|
||||
|
||||
Documentation:
|
||||
Improved HACKING info for submitting patches.
|
||||
Fixed numerous broken links.
|
||||
|
||||
Build and Release:
|
||||
|
||||
@@ -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
|
||||
features and device support, please read the new Developer Manual (or
|
||||
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
|
||||
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:
|
||||
|
||||
OpenOCD User's Guide:
|
||||
http://openocd.berlios.de/doc/html/index.html
|
||||
http://openocd.sourceforge.net/doc/html/index.html
|
||||
|
||||
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
|
||||
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
|
||||
by subscribing to the OpenOCD developer mailing list:
|
||||
|
||||
openocd-development@lists.berlios.de
|
||||
openocd-devel@lists.sourceforge.net
|
||||
|
||||
Building the OpenOCD Documentation
|
||||
----------------------------------
|
||||
@@ -210,53 +210,84 @@ options may be available there:
|
||||
|
||||
--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
|
||||
using the libftdi driver, opensource alternate of
|
||||
FTD2XX
|
||||
--enable-ft2232_ftd2xx Enable building support for FT2232 based devices
|
||||
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
|
||||
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
|
||||
using the libftdi driver
|
||||
--enable-presto_ftd2xx Enable building support for ASIX Presto Programmer
|
||||
using the FTD2XX driver
|
||||
|
||||
--enable-amtjtagaccel Enable building the Amontec JTAG-Accelerator driver
|
||||
--enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW
|
||||
--enable-usbprog Enable building support for the usbprog JTAG
|
||||
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
|
||||
Programmer
|
||||
|
||||
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
||||
Programmer
|
||||
|
||||
--enable-rlink Enable building support for the Raisonance RLink
|
||||
JTAG Programmer
|
||||
--enable-ulink Enable building support for the Keil ULINK JTAG
|
||||
Programmer
|
||||
--enable-usbprog Enable building support for the usbprog JTAG
|
||||
Programmer
|
||||
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
||||
--enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW
|
||||
Programmer
|
||||
|
||||
--enable-oocd_trace Enable building support for the OpenOCD+trace ETM
|
||||
capture device
|
||||
--enable-buspirate Enable building support for the Buspirate
|
||||
|
||||
--enable-ep93xx Enable building support for EP93xx based SBCs
|
||||
--enable-at91rm9200 Enable building support for AT91RM9200 based SBCs
|
||||
--enable-stlink Enable building support for the ST-Link JTAG
|
||||
Programmer
|
||||
|
||||
--enable-ecosboard Enable building support for eCos based JTAG debugger
|
||||
--enable-zy1000 Enable ZY1000 interface
|
||||
--enable-osbdm Enable building support for the OSBDM (JTAG only)
|
||||
Programmer
|
||||
|
||||
--enable-opendous Enable building support for the estick/opendous JTAG
|
||||
Programmer
|
||||
|
||||
--enable-minidriver-dummy
|
||||
Enable the dummy minidriver.
|
||||
|
||||
--enable-ioutil Enable ioutil functions - useful for standalone
|
||||
OpenOCD implementations
|
||||
--disable-internal-jimtcl
|
||||
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.
|
||||
--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:
|
||||
- avr
|
||||
- ecosflash
|
||||
- pic32mx
|
||||
- ocl
|
||||
- str9xpec
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# common flags used in openocd build
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||
-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";
|
||||
|
||||
$struct_header = "static struct {
|
||||
uint32_t partno;
|
||||
uint8_t class;
|
||||
uint8_t partno;
|
||||
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";
|
||||
-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);
|
||||
closedir(DIR);
|
||||
|
||||
@short_files = sort(grep(/lm3s...\.h/, @files));
|
||||
@long_files = sort(grep(/lm3s....\.h/, @files));
|
||||
@header_files = sort(grep(/lm.+\.h/, @files));
|
||||
|
||||
$ver = 0;
|
||||
$new_struct = $struct_header;
|
||||
process_file(@short_files);
|
||||
process_file(@long_files);
|
||||
process_file(@header_files);
|
||||
$new_struct .= $struct_footer;
|
||||
|
||||
$dump = "$comment $ver\n$new_struct";
|
||||
@@ -51,7 +49,7 @@ close(OUTPUT);
|
||||
|
||||
sub process_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);
|
||||
local($/, *FILE);
|
||||
open(FILE, "$dir/$h_file");
|
||||
@@ -66,22 +64,39 @@ sub process_file {
|
||||
$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 {
|
||||
print STDERR "$h_file is missing SYSCTL_DID1_VER\n";
|
||||
$did1_ver = 255;
|
||||
$invalid = 1;
|
||||
# attempt another way to get class
|
||||
if ($content =~ /\s(\S+)-class/) {
|
||||
$class = getclass($1);
|
||||
if ($class eq 0xFF) {
|
||||
print STDERR "$h_file unknown class\n";
|
||||
$invalid = 1;
|
||||
}
|
||||
} else {
|
||||
print STDERR "$h_file is missing SYSCTL_DID0_CLASS_\n";
|
||||
$class = 0;
|
||||
$invalid = 1;
|
||||
}
|
||||
}
|
||||
if ($content =~ /SYSCTL_DID1_PRTNO_$base\s+0x(\S+)/) {
|
||||
|
||||
if ($content =~ /SYSCTL_DID1_PRTNO_$base.+0x(\S+)/) {
|
||||
$prtno = hex($1);
|
||||
$base = "LM3S" . $base;
|
||||
} else {
|
||||
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
|
||||
$prtno = 0;
|
||||
$invalid = 1;
|
||||
# LM4F have a changed header
|
||||
if ($content =~ /SYSCTL_DID1_PRTNO_LM4F$base.+?0x(\S+)/s) {
|
||||
$prtno = hex($1);
|
||||
$base = "LM4F" . $base;
|
||||
} else {
|
||||
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
|
||||
$prtno = 0;
|
||||
$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) {
|
||||
#$new_struct .= "\t//$new_member\t// Invalid\n";
|
||||
} 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_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[15:8] is used by target for write buffer
|
||||
* DCRDR[23:16] is used for by host for status
|
||||
|
||||
@@ -26,41 +26,46 @@
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.arch armv7-m
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
|
||||
.align 2
|
||||
|
||||
_start:
|
||||
main:
|
||||
main:
|
||||
mov r2, r0
|
||||
mov r0, #0xffffffff /* crc */
|
||||
movs r0, #0
|
||||
mvns r0, r0
|
||||
ldr r6, CRC32XOR
|
||||
mov r3, r1
|
||||
mov r4, #0
|
||||
movs r4, #0
|
||||
b ncomp
|
||||
nbyte:
|
||||
ldrb r1, [r2, r4]
|
||||
|
||||
ldr r7, CRC32XOR
|
||||
eor r0, r0, r1, asl #24
|
||||
mov r5, #0
|
||||
lsls r1, r1, #24
|
||||
eors r0, r0, r1
|
||||
movs r5, #0
|
||||
loop:
|
||||
cmp r0, #0
|
||||
mov r6, r0, asl #1
|
||||
add r5, r5, #1
|
||||
mov r0, r6
|
||||
it lt
|
||||
eorlt r0, r6, r7
|
||||
bge notset
|
||||
lsls r0, r0, #1
|
||||
eors r0, r0, r6
|
||||
b cont
|
||||
notset:
|
||||
lsls r0, r0, #1
|
||||
cont:
|
||||
adds r5, r5, #1
|
||||
cmp r5, #8
|
||||
bne loop
|
||||
|
||||
add r4, r4, #1
|
||||
adds r4, r4, #1
|
||||
ncomp:
|
||||
cmp r4, r3
|
||||
bne nbyte
|
||||
bkpt #0
|
||||
|
||||
.align 2
|
||||
|
||||
CRC32XOR: .word 0x04c11db7
|
||||
|
||||
.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. *
|
||||
***************************************************************************/
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m3
|
||||
.thumb
|
||||
.thumb_func
|
||||
.global write
|
||||
|
||||
/*
|
||||
r0 - source address
|
||||
r1 - target address
|
||||
r2 - count (halfword-16bit)
|
||||
r3 - sector offet in : result out
|
||||
r4 - flash base
|
||||
parameters:
|
||||
r0 - address in
|
||||
r1 - byte count
|
||||
r2 - mask - result out
|
||||
*/
|
||||
|
||||
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
||||
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
.thumb_func
|
||||
|
||||
write:
|
||||
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
|
||||
.align 2
|
||||
|
||||
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,41 +26,53 @@
|
||||
.cpu cortex-m3
|
||||
.thumb
|
||||
.thumb_func
|
||||
.align 2
|
||||
|
||||
/*
|
||||
Call with :
|
||||
r0 = buffer address
|
||||
r1 = destination address
|
||||
r2 = bytecount (in) - endaddr (work)
|
||||
|
||||
Used registers:
|
||||
r3 = pFLASH_CTRL_BASE
|
||||
r4 = FLASHWRITECMD
|
||||
r5 = #1
|
||||
r6 = bytes written
|
||||
r7 = temp reg
|
||||
*/
|
||||
* Params :
|
||||
* r0 = workarea start
|
||||
* r1 = workarea end
|
||||
* r2 = target address
|
||||
* r3 = count (32bit words)
|
||||
*
|
||||
* Clobbered:
|
||||
* r4 = pFLASH_CTRL_BASE
|
||||
* r5 = FLASHWRITECMD
|
||||
* r7 - rp
|
||||
* r8 - wp, tmp
|
||||
*/
|
||||
|
||||
write:
|
||||
ldr r3,pFLASH_CTRL_BASE
|
||||
ldr r4,FLASHWRITECMD
|
||||
movs r5, 1
|
||||
movs r6, #0
|
||||
ldr r4, pFLASH_CTRL_BASE
|
||||
ldr r5, FLASHWRITECMD
|
||||
|
||||
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:
|
||||
str r1, [r3, #0]
|
||||
ldr r7, [r0, r6]
|
||||
str r7, [r3, #4]
|
||||
str r4, [r3, #8]
|
||||
waitloop:
|
||||
ldr r7, [r3, #8]
|
||||
tst r7, r5
|
||||
bne waitloop
|
||||
adds r1, r1, #4
|
||||
adds r6, r6, #4
|
||||
cmp r6, r2
|
||||
bne mainloop
|
||||
bkpt #0
|
||||
str r2, [r4, #0] /* FMA - write address */
|
||||
add r2, r2, #4 /* increment target address */
|
||||
ldr r8, [r7], #4
|
||||
str r8, [r4, #4] /* FMD - write data */
|
||||
str r5, [r4, #8] /* FMC - enable write */
|
||||
busy:
|
||||
ldr r8, [r4, #8]
|
||||
tst r8, #1
|
||||
bne busy
|
||||
|
||||
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 word count */
|
||||
cbz r3, exit /* loop if not done */
|
||||
b wait_fifo
|
||||
exit:
|
||||
bkpt #0
|
||||
|
||||
pFLASH_CTRL_BASE: .word 0x400FD000
|
||||
FLASHWRITECMD: .word 0xA4420001
|
||||
|
||||
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 *
|
||||
* 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 *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* 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
|
||||
.syntax unified
|
||||
.cpu cortex-m3
|
||||
@@ -31,33 +34,30 @@
|
||||
.global write
|
||||
|
||||
/*
|
||||
r0 - source address
|
||||
r1 - target address
|
||||
r2 - count (halfword-16bit)
|
||||
r3 - result out
|
||||
r4 - flash base
|
||||
r0 - destination address
|
||||
r1 - source address
|
||||
r2 - count
|
||||
*/
|
||||
|
||||
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
||||
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
||||
// Set 0 to r3
|
||||
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:
|
||||
ldr r3, STM32_PROG16
|
||||
str r3, [r4, #STM32_FLASH_CR_OFFSET]
|
||||
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, #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:
|
||||
test_done:
|
||||
// Compare r3 and r2
|
||||
cmp r3, r2
|
||||
// Loop if not zero
|
||||
bcc.n write_word
|
||||
|
||||
// Set breakpoint to exit
|
||||
bkpt #0x00
|
||||
|
||||
|
||||
STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/
|
||||
@@ -1,10 +1,12 @@
|
||||
ACTION!="add|change", GOTO="openocd_rules_end"
|
||||
SUBSYSTEM!="usb", GOTO="openocd_rules_end"
|
||||
ENV{DEVTYPE}!="usb_device", GOTO="openocd_rules_end"
|
||||
SUBSYSTEM!="usb|tty", GOTO="openocd_rules_end"
|
||||
|
||||
# Olimex ARM-USB-OCD
|
||||
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
|
||||
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
|
||||
# OOCD-Link
|
||||
# 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"
|
||||
|
||||
# Calao Systems USB-A9260-C02
|
||||
# Bus Pirate
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
||||
|
||||
# IAR J-Link USB
|
||||
@@ -67,5 +71,19 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
||||
# Hilscher NXHX Boards
|
||||
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
|
||||
associated with the fundamental technologies used by OpenOCD.
|
||||
|
||||
- @subpage primerpatches
|
||||
- @subpage primerdocs
|
||||
- @subpage primerautotools
|
||||
- @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.
|
||||
|
||||
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>:
|
||||
|
||||
@code
|
||||
tools/release/version.sh version tag add foo
|
||||
@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
|
||||
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
|
||||
@@ -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
|
||||
if a significant and longstanding bug is fixed late in the RC phase).
|
||||
-# 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 versions are named properly.):
|
||||
-# 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
|
||||
-# Commit that version change, with a good descriptive comment.
|
||||
-# 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):
|
||||
@verbatim
|
||||
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.
|
||||
-# Produce the release files, using the local clone of the source
|
||||
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.
|
||||
-# Run <code>tools/release.sh package</code> to produce the
|
||||
source archives. This automatically bootstraps and
|
||||
configures the process.
|
||||
-# Run <code>tools/release.sh stage</code> to create an @c archives
|
||||
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
|
||||
configuring its contents, using them to build a copy of OpenOCD,
|
||||
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
|
||||
- For openocd.pdf just associate it with the right release notes.
|
||||
-# 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
|
||||
downloading them from the websites and making sure there are no
|
||||
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
|
||||
instantiate a shell.sourceforge.net instance and set up symlinks
|
||||
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.
|
||||
-# 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.
|
||||
-# Submit updates to news feeds (e.g. Digg, Reddit, etc.).
|
||||
-# Resume normal development on mainline, by opening the merge window for
|
||||
the next major or minor release cycle. (You might want to do this
|
||||
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.
|
||||
- For a new minor release cycle, increment the release's minor 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
|
||||
minor release 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.
|
||||
(Always be sure mainline has the fix first, so it's hard
|
||||
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
|
||||
- @c // comments -- in new code, prefer these for single-line comments
|
||||
- trailing comma allowed in enum declarations
|
||||
- designated initializers (@{ .field = value @})
|
||||
- designated initializers ( .field = value )
|
||||
- variables declarations should occur at the point of first use
|
||||
- new block scopes for selection and iteration statements
|
||||
- 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.
|
||||
|
||||
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...
|
||||
- Use good judgement.
|
||||
|
||||
|
||||
735
doc/openocd.texi
735
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
## Software Foundation; either version 2 or (at your option) any later version.
|
||||
##
|
||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
## for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along
|
||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
##
|
||||
## As a special exception, if other files instantiate templates or use macros
|
||||
## or inline functions from this file, or you compile this file and link it
|
||||
## with other works to produce a work based on this file, this file does not
|
||||
## by itself cause the resulting work to be covered by the GNU General Public
|
||||
## License. However the source code for this file must still be made available
|
||||
## in accordance with section (3) of the GNU General Public License.
|
||||
##
|
||||
## This exception does not invalidate any other reasons why a work based on
|
||||
## this file might be covered by the GNU General Public License.
|
||||
## -------------------------------------------
|
||||
#####ECOSGPLCOPYRIGHTEND####
|
||||
|
||||
# Create OpenOCD eCos flash driver
|
||||
# Syntax: make INSTALL_DIR=ecosinstalldir OUTPUT=outputname
|
||||
|
||||
include $(INSTALL_DIR)/include/pkgconf/ecos.mak
|
||||
|
||||
all:
|
||||
$(ECOS_COMMAND_PREFIX)gcc $(ECOS_GLOBAL_CFLAGS) $(ECOS_GLOBAL_LDFLAGS) -g -o debug_$(OUTPUT).elf -nostdlib flash.S flash.c -Wl,--gc-sections -I$(INSTALL_DIR)/include -Wl,$(INSTALL_DIR)/lib/libtarget.a -Wl,-Map,flash.map
|
||||
cp debug_$(OUTPUT).elf $(OUTPUT).elf
|
||||
$(ECOS_COMMAND_PREFIX)strip $(OUTPUT).elf
|
||||
echo Flash driver $(OUTPUT).elf
|
||||
|
||||
Binary file not shown.
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
## Software Foundation; either version 2 or (at your option) any later version.
|
||||
##
|
||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
## for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along
|
||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
##
|
||||
## As a special exception, if other files instantiate templates or use macros
|
||||
## or inline functions from this file, or you compile this file and link it
|
||||
## with other works to produce a work based on this file, this file does not
|
||||
## by itself cause the resulting work to be covered by the GNU General Public
|
||||
## License. However the source code for this file must still be made available
|
||||
## in accordance with section (3) of the GNU General Public License.
|
||||
##
|
||||
## This exception does not invalidate any other reasons why a work based on
|
||||
## this file might be covered by the GNU General Public License.
|
||||
## -------------------------------------------
|
||||
#####ECOSGPLCOPYRIGHTEND####
|
||||
*/
|
||||
|
||||
/*
|
||||
Jump table for flash driver
|
||||
|
||||
Registers in ARM callling convention is to place args in registers
|
||||
starting at r0.
|
||||
|
||||
So for:
|
||||
|
||||
void foo(int a, int b, int c).
|
||||
|
||||
a=r0
|
||||
b=r1
|
||||
c=r2
|
||||
|
||||
|
||||
*/
|
||||
.global _stack_base
|
||||
.global _stack_start
|
||||
.global _workarea
|
||||
.global _start
|
||||
.global _start_bss_clear
|
||||
_start:
|
||||
// offset=0
|
||||
// int erase(void *address, int len)
|
||||
ldr sp,=_stack_start
|
||||
bl erase
|
||||
nop // Stop CPU here using hw breakpoint
|
||||
|
||||
// offset=0xc
|
||||
// int program(void *buffer, void *address, int len)
|
||||
ldr sp,=_stack_start
|
||||
bl program
|
||||
nop // Stop CPU here using hw breakpoint
|
||||
|
||||
// offset=0x18
|
||||
ldr r0,=_workarea
|
||||
nop // Stop CPU here using hw breakpoint
|
||||
|
||||
// offset=0x20
|
||||
// int init() - returns error message if the flash chip can't be detected
|
||||
ldr sp,=_stack_start
|
||||
bl init
|
||||
nop // Stop CPU here using hw breakpoint
|
||||
|
||||
.section ".bss"
|
||||
.balign 4
|
||||
_stack_base:
|
||||
.rept 4096
|
||||
.byte 0
|
||||
.endr
|
||||
_stack_start:
|
||||
.balign 4
|
||||
_workarea:
|
||||
.rept 8192
|
||||
.byte 0
|
||||
.endr
|
||||
// NB!!! we clear bss while the stack is in use, so we start BSS clearing here !!! :-)
|
||||
_start_bss_clear:
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
## Software Foundation; either version 2 or (at your option) any later version.
|
||||
##
|
||||
## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
## for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along
|
||||
## with eCos; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
##
|
||||
## As a special exception, if other files instantiate templates or use macros
|
||||
## or inline functions from this file, or you compile this file and link it
|
||||
## with other works to produce a work based on this file, this file does not
|
||||
## by itself cause the resulting work to be covered by the GNU General Public
|
||||
## License. However the source code for this file must still be made available
|
||||
## in accordance with section (3) of the GNU General Public License.
|
||||
##
|
||||
## This exception does not invalidate any other reasons why a work based on
|
||||
## this file might be covered by the GNU General Public License.
|
||||
## -------------------------------------------
|
||||
#####ECOSGPLCOPYRIGHTEND####
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#define _FLASH_PRIVATE_
|
||||
#include <cyg/io/flash.h>
|
||||
|
||||
|
||||
|
||||
int myprintf(char *format, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern char _start_bss_clear;
|
||||
extern char __bss_end__;
|
||||
|
||||
int init()
|
||||
{
|
||||
// set up runtime environment
|
||||
char *t;
|
||||
for (t=&_start_bss_clear; t<&__bss_end__; t++)
|
||||
{
|
||||
*t=0;
|
||||
}
|
||||
return flash_init((_printf *)&myprintf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int checkFlash(void *addr, int len)
|
||||
{
|
||||
// Return error for illegal addresses
|
||||
if ((addr<flash_info.start)||(addr>flash_info.end))
|
||||
return FLASH_ERR_INVALID;
|
||||
if ((((cyg_uint8 *)addr)+len)>(cyg_uint8 *)flash_info.end)
|
||||
return FLASH_ERR_INVALID;
|
||||
return FLASH_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
int erase(void *address, int len)
|
||||
{
|
||||
int retval;
|
||||
void *failAddress;
|
||||
|
||||
retval=checkFlash(address, len);
|
||||
if (retval!=0)
|
||||
return retval;
|
||||
|
||||
retval=init();
|
||||
if (retval!=0)
|
||||
return retval;
|
||||
return flash_erase(address, len, &failAddress);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern char _end;
|
||||
|
||||
// Data follows immediately after program, long word aligned.
|
||||
int program(void *buffer, void *address, int len)
|
||||
{
|
||||
int retval;
|
||||
void *failAddress;
|
||||
retval=checkFlash(address, len);
|
||||
if (retval!=0)
|
||||
return retval;
|
||||
|
||||
retval=init();
|
||||
if (retval!=0)
|
||||
return retval;
|
||||
//int flash_program(void *_addr, void *_data, int len, void **err_addr)
|
||||
return flash_program(address, buffer, len, &failAddress);
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
Archive member included because of file (symbol)
|
||||
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
/ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o (flash_init)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (flash_hwr_init)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (memcpy)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
/tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o) (memcmp)
|
||||
|
||||
Memory Configuration
|
||||
|
||||
Name Origin Length Attributes
|
||||
*default* 0x00000000 0xffffffff
|
||||
|
||||
Linker script and memory map
|
||||
|
||||
LOAD /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
LOAD /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
LOAD /tmp/ecosboard/ecos/install/lib/libtarget.a
|
||||
0x00008000 PROVIDE (__executable_start, 0x8000)
|
||||
0x00008000 . = 0x8000
|
||||
|
||||
.interp
|
||||
*(.interp)
|
||||
|
||||
.hash
|
||||
*(.hash)
|
||||
|
||||
.dynsym
|
||||
*(.dynsym)
|
||||
|
||||
.dynstr
|
||||
*(.dynstr)
|
||||
|
||||
.gnu.version
|
||||
*(.gnu.version)
|
||||
|
||||
.gnu.version_d
|
||||
*(.gnu.version_d)
|
||||
|
||||
.gnu.version_r
|
||||
*(.gnu.version_r)
|
||||
|
||||
.rel.dyn
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
|
||||
.rela.dyn
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
|
||||
.rel.plt
|
||||
*(.rel.plt)
|
||||
|
||||
.rela.plt
|
||||
*(.rela.plt)
|
||||
|
||||
.init
|
||||
*(.init)
|
||||
|
||||
.plt
|
||||
*(.plt)
|
||||
|
||||
.text 0x00008000 0x6f8
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
.text 0x00008000 0x34 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
0x00008000 _start
|
||||
.text.myprintf
|
||||
0x00008034 0x10 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
0x00008034 myprintf
|
||||
.text.init 0x00008044 0x50 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
0x00008044 init
|
||||
.text.erase 0x00008094 0xc0 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
0x00008094 erase
|
||||
.text.program 0x00008154 0xc8 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
0x00008154 program
|
||||
.text.flash_init
|
||||
0x0000821c 0x6c /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x0000821c flash_init
|
||||
.text.flash_dev_query
|
||||
0x00008288 0x20 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x00008288 flash_dev_query
|
||||
.text.flash_erase
|
||||
0x000082a8 0x140 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x000082a8 flash_erase
|
||||
.text.flash_program
|
||||
0x000083e8 0x154 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x000083e8 flash_program
|
||||
.text.flash_hwr_init
|
||||
0x0000853c 0xa4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x0000853c flash_hwr_init
|
||||
.text.flash_hwr_map_error
|
||||
0x000085e0 0x4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x000085e0 flash_hwr_map_error
|
||||
.text.__memcmp
|
||||
0x000085e4 0x114 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
0x000085e4 memcmp
|
||||
0x000085e4 __memcmp
|
||||
*(.gnu.warning)
|
||||
*(.glue_7t)
|
||||
*(.glue_7)
|
||||
|
||||
.2ram.flash_query
|
||||
0x000086f8 0x54
|
||||
.2ram.flash_query
|
||||
0x000086f8 0x54 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x000086f8 flash_query
|
||||
|
||||
.2ram.flash_erase_block
|
||||
0x0000874c 0x230
|
||||
.2ram.flash_erase_block
|
||||
0x0000874c 0x230 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x0000874c flash_erase_block
|
||||
|
||||
.2ram.flash_program_buf
|
||||
0x0000897c 0xe8
|
||||
.2ram.flash_program_buf
|
||||
0x0000897c 0xe8 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x0000897c flash_program_buf
|
||||
|
||||
.fini
|
||||
*(.fini)
|
||||
0x00008a64 PROVIDE (__etext, .)
|
||||
0x00008a64 PROVIDE (_etext, .)
|
||||
0x00008a64 PROVIDE (etext, .)
|
||||
|
||||
.rodata 0x00008a64 0x318
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
.rodata.str1.4
|
||||
0x00008a64 0x1fb /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x1fc (size before relaxing)
|
||||
*fill* 0x00008c5f 0x1 00
|
||||
.rodata.supported_devices
|
||||
0x00008c60 0x11c /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
|
||||
.rodata1
|
||||
*(.rodata1)
|
||||
|
||||
.eh_frame_hdr
|
||||
*(.eh_frame_hdr)
|
||||
0x00008e7c . = (ALIGN (0x100) + (. & 0xff))
|
||||
0x00008e7c . = ALIGN (0x4)
|
||||
0x00008e7c PROVIDE (__preinit_array_start, .)
|
||||
|
||||
.preinit_array
|
||||
*(.preinit_array)
|
||||
0x00008e7c PROVIDE (__preinit_array_end, .)
|
||||
0x00008e7c PROVIDE (__init_array_start, .)
|
||||
|
||||
.init_array
|
||||
*(.init_array)
|
||||
0x00008e7c PROVIDE (__init_array_end, .)
|
||||
0x00008e7c PROVIDE (__fini_array_start, .)
|
||||
|
||||
.fini_array
|
||||
*(.fini_array)
|
||||
0x00008e7c PROVIDE (__fini_array_end, .)
|
||||
|
||||
.data 0x00008e7c 0x0
|
||||
0x00008e7c __data_start = .
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
|
||||
.data1
|
||||
*(.data1)
|
||||
|
||||
.tdata
|
||||
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||
|
||||
.tbss
|
||||
*(.tbss .tbss.* .gnu.linkonce.tb.*)
|
||||
*(.tcommon)
|
||||
|
||||
.eh_frame
|
||||
*(.eh_frame)
|
||||
|
||||
.gcc_except_table
|
||||
*(.gcc_except_table)
|
||||
|
||||
.dynamic
|
||||
*(.dynamic)
|
||||
|
||||
.ctors
|
||||
*crtbegin*.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend*.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
.dtors
|
||||
*crtbegin*.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend*.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
.jcr
|
||||
*(.jcr)
|
||||
|
||||
.got
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
0x00008e7c _edata = .
|
||||
0x00008e7c PROVIDE (edata, .)
|
||||
0x00008e7c __bss_start = .
|
||||
0x00008e7c __bss_start__ = .
|
||||
|
||||
.bss 0x00008e7c 0x3024
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
.bss 0x00008e7c 0x3000 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
0x00008e7c _stack_base
|
||||
0x0000be7c _start_bss_clear
|
||||
0x00009e7c _workarea
|
||||
0x00009e7c _stack_start
|
||||
.bss.flash_info
|
||||
0x0000be7c 0x20 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x0000be7c flash_info
|
||||
.bss.flash_dev_info
|
||||
0x0000be9c 0x4 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
*(COMMON)
|
||||
0x0000bea0 . = ALIGN (0x4)
|
||||
0x0000bea0 . = ALIGN (0x4)
|
||||
0x0000bea0 _end = .
|
||||
0x0000bea0 _bss_end__ = .
|
||||
0x0000bea0 __bss_end__ = .
|
||||
0x0000bea0 __end__ = .
|
||||
0x0000bea0 PROVIDE (end, .)
|
||||
|
||||
.stab
|
||||
*(.stab)
|
||||
|
||||
.stabstr
|
||||
*(.stabstr)
|
||||
|
||||
.stab.excl
|
||||
*(.stab.excl)
|
||||
|
||||
.stab.exclstr
|
||||
*(.stab.exclstr)
|
||||
|
||||
.stab.index
|
||||
*(.stab.index)
|
||||
|
||||
.stab.indexstr
|
||||
*(.stab.indexstr)
|
||||
|
||||
.comment
|
||||
*(.comment)
|
||||
|
||||
.debug
|
||||
*(.debug)
|
||||
|
||||
.line
|
||||
*(.line)
|
||||
|
||||
.debug_srcinfo
|
||||
*(.debug_srcinfo)
|
||||
|
||||
.debug_sfnames
|
||||
*(.debug_sfnames)
|
||||
|
||||
.debug_aranges 0x00000000 0x170
|
||||
*(.debug_aranges)
|
||||
.debug_aranges
|
||||
0x00000000 0x20 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
.debug_aranges
|
||||
0x00000020 0x48 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_aranges
|
||||
0x00000068 0x68 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_aranges
|
||||
0x000000d0 0x50 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_aranges
|
||||
0x00000120 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_aranges
|
||||
0x00000148 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_pubnames
|
||||
0x00000000 0x1e5
|
||||
*(.debug_pubnames)
|
||||
.debug_pubnames
|
||||
0x00000000 0x4d /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_pubnames
|
||||
0x0000004d 0xca /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_pubnames
|
||||
0x00000117 0x91 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_pubnames
|
||||
0x000001a8 0x1e /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_pubnames
|
||||
0x000001c6 0x1f /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_info 0x00000000 0x1122
|
||||
*(.debug_info .gnu.linkonce.wi.*)
|
||||
.debug_info 0x00000000 0x6e /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
.debug_info 0x0000006e 0x322 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_info 0x00000390 0x4f6 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_info 0x00000886 0x5b2 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_info 0x00000e38 0x1c7 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_info 0x00000fff 0x123 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_abbrev 0x00000000 0x67c
|
||||
*(.debug_abbrev)
|
||||
.debug_abbrev 0x00000000 0x14 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
.debug_abbrev 0x00000014 0x17d /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_abbrev 0x00000191 0x15f /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_abbrev 0x000002f0 0x238 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_abbrev 0x00000528 0xb4 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_abbrev 0x000005dc 0xa0 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_line 0x00000000 0x8de
|
||||
*(.debug_line)
|
||||
.debug_line 0x00000000 0x3e /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/cccPBW5f.o
|
||||
.debug_line 0x0000003e 0xf6 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_line 0x00000134 0x255 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_line 0x00000389 0x287 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_line 0x00000610 0x16c /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_line 0x0000077c 0x162 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_frame 0x00000000 0x2c0
|
||||
*(.debug_frame)
|
||||
.debug_frame 0x00000000 0xa4 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
.debug_frame 0x000000a4 0x110 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_frame 0x000001b4 0xac /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_frame 0x00000260 0x38 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_frame 0x00000298 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
|
||||
.debug_str 0x00000000 0x508
|
||||
*(.debug_str)
|
||||
.debug_str 0x00000000 0x131 /ecos-c/DOCUME~1/oyvind/LOCALS~1/Temp/ccM8Ftqt.o
|
||||
0x191 (size before relaxing)
|
||||
.debug_str 0x00000131 0x152 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
0x24e (size before relaxing)
|
||||
.debug_str 0x00000283 0x194 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
0x2c5 (size before relaxing)
|
||||
.debug_str 0x00000417 0x7e /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
0x11e (size before relaxing)
|
||||
.debug_str 0x00000495 0x73 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
0x119 (size before relaxing)
|
||||
|
||||
.debug_loc
|
||||
*(.debug_loc)
|
||||
|
||||
.debug_macinfo
|
||||
*(.debug_macinfo)
|
||||
|
||||
.debug_weaknames
|
||||
*(.debug_weaknames)
|
||||
|
||||
.debug_funcnames
|
||||
*(.debug_funcnames)
|
||||
|
||||
.debug_typenames
|
||||
*(.debug_typenames)
|
||||
|
||||
.debug_varnames
|
||||
*(.debug_varnames)
|
||||
|
||||
.stack 0x00080000 0x0
|
||||
0x00080000 _stack = .
|
||||
*(.stack)
|
||||
|
||||
.note.gnu.arm.ident
|
||||
*(.note.gnu.arm.ident)
|
||||
|
||||
/DISCARD/
|
||||
*(.note.GNU-stack)
|
||||
OUTPUT(debug_eb40a.elf elf32-littlearm)
|
||||
|
||||
.debug_ranges 0x00000000 0xb8
|
||||
.debug_ranges 0x00000000 0x18 /tmp/ecosboard/ecos/install/lib/libtarget.a(io_flash_flash.o)
|
||||
.debug_ranges 0x00000018 0x48 /tmp/ecosboard/ecos/install/lib/libtarget.a(devs_flash_arm_eb40a_eb40a_flash.o)
|
||||
.debug_ranges 0x00000060 0x30 /tmp/ecosboard/ecos/install/lib/libtarget.a(infra_memcpy.o)
|
||||
.debug_ranges 0x00000090 0x28 /tmp/ecosboard/ecos/install/lib/libtarget.a(language_c_libc_string_memcmp.o)
|
||||
@@ -1,6 +0,0 @@
|
||||
Some of these binaries are build & linked using eCos.
|
||||
|
||||
For source for the flash drivers, see:
|
||||
|
||||
http://ecos.sourceware.org/
|
||||
|
||||
2
jimtcl
2
jimtcl
Submodule jimtcl updated: 60dfb023c4...43d0866133
@@ -15,11 +15,7 @@ SUBDIRS = \
|
||||
lib_LTLIBRARIES = libopenocd.la
|
||||
bin_PROGRAMS = openocd
|
||||
|
||||
if ECOSBOARD
|
||||
MAINFILE = ecosboard.c
|
||||
else
|
||||
MAINFILE = main.c
|
||||
endif
|
||||
|
||||
openocd_SOURCES = $(MAINFILE)
|
||||
openocd_LDADD = libopenocd.la
|
||||
@@ -30,6 +26,10 @@ else
|
||||
openocd_LDADD += -ljim
|
||||
endif
|
||||
|
||||
if ULINK
|
||||
openocd_LDADD += -lm
|
||||
endif
|
||||
|
||||
libopenocd_la_SOURCES = \
|
||||
hello.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"
|
||||
if RELEASE
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
||||
libopenocd_la_CPPFLAGS += -DGITVERSION=\"\"
|
||||
else
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||
endif
|
||||
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
||||
endif
|
||||
|
||||
# add default CPPFLAGS
|
||||
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||
@@ -76,26 +77,13 @@ 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 =
|
||||
if USE_LIBUSB1
|
||||
LIBUSB += -lusb-1.0
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_LIBUSB0
|
||||
LIBUSB += -lusb
|
||||
endif
|
||||
|
||||
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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -32,17 +33,17 @@ unsigned get_flash_name_index(const char *name)
|
||||
return ~0U;
|
||||
unsigned 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;
|
||||
}
|
||||
|
||||
bool flash_driver_name_matches(const char *name, const char *expected)
|
||||
{
|
||||
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)
|
||||
return false;
|
||||
|
||||
// ...then check that name terminates at this spot.
|
||||
/* ...then check that name terminates at this spot. */
|
||||
return expected[blen] == '.' || expected[blen] == '\0';
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FLASH_COMMON_H
|
||||
#define FLASH_COMMON_H
|
||||
|
||||
@@ -36,14 +37,14 @@ unsigned get_flash_name_index(const char *name);
|
||||
*/
|
||||
bool flash_driver_name_matches(const char *name, const char *expected);
|
||||
|
||||
#define ERROR_FLASH_BANK_INVALID (-900)
|
||||
#define ERROR_FLASH_SECTOR_INVALID (-901)
|
||||
#define ERROR_FLASH_OPERATION_FAILED (-902)
|
||||
#define ERROR_FLASH_DST_OUT_OF_BANK (-903)
|
||||
#define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
|
||||
#define ERROR_FLASH_BUSY (-905)
|
||||
#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
|
||||
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
||||
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
|
||||
#define ERROR_FLASH_BANK_INVALID (-900)
|
||||
#define ERROR_FLASH_SECTOR_INVALID (-901)
|
||||
#define ERROR_FLASH_OPERATION_FAILED (-902)
|
||||
#define ERROR_FLASH_DST_OUT_OF_BANK (-903)
|
||||
#define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
|
||||
#define ERROR_FLASH_BUSY (-905)
|
||||
#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
|
||||
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
||||
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
|
||||
|
||||
#endif // FLASH_COMMON_H
|
||||
#endif /* FLASH_COMMON_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,17 +26,15 @@ typedef unsigned long mg_io_uint32;
|
||||
typedef unsigned short mg_io_uint16;
|
||||
typedef unsigned char mg_io_uint8;
|
||||
|
||||
struct mflash_gpio_num
|
||||
{
|
||||
struct mflash_gpio_num {
|
||||
char port[2];
|
||||
signed short num;
|
||||
};
|
||||
|
||||
struct mflash_gpio_drv
|
||||
{
|
||||
struct mflash_gpio_drv {
|
||||
const char *name;
|
||||
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_to_output)(struct mflash_gpio_num gpio);
|
||||
int (*set_gpio_output_val)(struct mflash_gpio_num gpio, uint8_t val);
|
||||
};
|
||||
|
||||
typedef struct _mg_io_type_drv_info {
|
||||
@@ -48,50 +46,50 @@ typedef struct _mg_io_type_drv_info {
|
||||
mg_io_uint16 unformatted_bytes_per_track; /* 04 */
|
||||
mg_io_uint16 unformatted_bytes_per_sector; /* 05 */
|
||||
mg_io_uint16 sectors_per_track; /* 06 */
|
||||
mg_io_uint16 vendor_unique1[3]; /* 07/08/09 */
|
||||
mg_io_uint16 vendor_unique1[3]; /* 07/08/09 */
|
||||
|
||||
mg_io_uint8 serial_number[20]; /* 10~19 */
|
||||
mg_io_uint8 serial_number[20]; /* 10~19 */
|
||||
|
||||
mg_io_uint16 buffer_type; /* 20 */
|
||||
mg_io_uint16 buffer_sector_size; /* 21 */
|
||||
mg_io_uint16 number_of_ecc_bytes; /* 22 */
|
||||
|
||||
mg_io_uint8 firmware_revision[8]; /* 23~26 */
|
||||
mg_io_uint8 model_number[40]; /* 27 */
|
||||
mg_io_uint8 firmware_revision[8]; /* 23~26 */
|
||||
mg_io_uint8 model_number[40]; /* 27 */
|
||||
|
||||
mg_io_uint8 maximum_block_transfer; /* 47 low byte */
|
||||
mg_io_uint8 vendor_unique2; /* 47 high byte */
|
||||
mg_io_uint8 maximum_block_transfer; /* 47 low byte */
|
||||
mg_io_uint8 vendor_unique2; /* 47 high byte */
|
||||
mg_io_uint16 dword_io; /* 48 */
|
||||
|
||||
mg_io_uint16 capabilities; /* 49 */
|
||||
mg_io_uint16 reserved2; /* 50 */
|
||||
|
||||
mg_io_uint8 vendor_unique3; /* 51 low byte */
|
||||
mg_io_uint8 pio_cycle_timing_mode; /* 51 high byte */
|
||||
mg_io_uint8 vendor_unique4; /* 52 low byte */
|
||||
mg_io_uint8 dma_cycle_timing_mode; /* 52 high byte */
|
||||
mg_io_uint8 vendor_unique3; /* 51 low byte */
|
||||
mg_io_uint8 pio_cycle_timing_mode; /* 51 high byte */
|
||||
mg_io_uint8 vendor_unique4; /* 52 low byte */
|
||||
mg_io_uint8 dma_cycle_timing_mode; /* 52 high byte */
|
||||
mg_io_uint16 translation_fields_valid; /* 53 (low bit) */
|
||||
mg_io_uint16 number_of_current_cylinders; /* 54 */
|
||||
mg_io_uint16 number_of_current_heads; /* 55 */
|
||||
mg_io_uint16 current_sectors_per_track; /* 56 */
|
||||
mg_io_uint16 current_sector_capacity_lo; /* 57 & 58 */
|
||||
mg_io_uint16 current_sector_capacity_hi; /* 57 & 58 */
|
||||
mg_io_uint8 multi_sector_count; /* 59 low */
|
||||
mg_io_uint8 multi_sector_setting_valid; /* 59 high (low bit) */
|
||||
mg_io_uint8 multi_sector_count; /* 59 low */
|
||||
mg_io_uint8 multi_sector_setting_valid; /* 59 high (low bit) */
|
||||
|
||||
mg_io_uint16 total_user_addressable_sectors_lo; /* 60 & 61 */
|
||||
mg_io_uint16 total_user_addressable_sectors_hi; /* 60 & 61 */
|
||||
|
||||
mg_io_uint8 single_dma_modes_supported; /* 62 low byte */
|
||||
mg_io_uint8 single_dma_transfer_active; /* 62 high byte */
|
||||
mg_io_uint8 multi_dma_modes_supported; /* 63 low byte */
|
||||
mg_io_uint8 multi_dma_transfer_active; /* 63 high byte */
|
||||
mg_io_uint8 single_dma_modes_supported; /* 62 low byte */
|
||||
mg_io_uint8 single_dma_transfer_active; /* 62 high byte */
|
||||
mg_io_uint8 multi_dma_modes_supported; /* 63 low byte */
|
||||
mg_io_uint8 multi_dma_transfer_active; /* 63 high byte */
|
||||
mg_io_uint16 adv_pio_mode;
|
||||
mg_io_uint16 min_dma_cyc;
|
||||
mg_io_uint16 recommend_dma_cyc;
|
||||
mg_io_uint16 min_pio_cyc_no_iordy;
|
||||
mg_io_uint16 min_pio_cyc_with_iordy;
|
||||
mg_io_uint8 reserved3[22];
|
||||
mg_io_uint8 reserved3[22];
|
||||
mg_io_uint16 major_ver_num;
|
||||
mg_io_uint16 minor_ver_num;
|
||||
mg_io_uint16 feature_cmd_set_suprt0;
|
||||
@@ -106,23 +104,22 @@ typedef struct _mg_io_type_drv_info {
|
||||
mg_io_uint16 adv_pwr_mgm_lvl_val;
|
||||
mg_io_uint16 reserved5;
|
||||
mg_io_uint16 re_of_hw_rst;
|
||||
mg_io_uint8 reserved6[68];
|
||||
mg_io_uint8 reserved6[68];
|
||||
mg_io_uint16 security_stas;
|
||||
mg_io_uint8 vendor_uniq_bytes[62];
|
||||
mg_io_uint8 vendor_uniq_bytes[62];
|
||||
mg_io_uint16 cfa_pwr_mode;
|
||||
mg_io_uint8 reserved7[186];
|
||||
mg_io_uint8 reserved7[186];
|
||||
|
||||
mg_io_uint16 scts_per_secure_data_unit;
|
||||
mg_io_uint16 integrity_word;
|
||||
|
||||
} mg_io_type_drv_info;
|
||||
|
||||
typedef struct _mg_pll_t
|
||||
{
|
||||
unsigned int lock_cyc;
|
||||
typedef struct _mg_pll_t {
|
||||
unsigned int lock_cyc;
|
||||
unsigned short feedback_div; /* 9bit divider */
|
||||
unsigned char input_div; /* 5bit divider */
|
||||
unsigned char output_div; /* 2bit divider */
|
||||
unsigned char input_div; /* 5bit divider */
|
||||
unsigned char output_div; /* 2bit divider */
|
||||
} mg_pll_t;
|
||||
|
||||
struct mg_drv_info {
|
||||
@@ -130,8 +127,7 @@ struct mg_drv_info {
|
||||
uint32_t tot_sects;
|
||||
};
|
||||
|
||||
struct mflash_bank
|
||||
{
|
||||
struct mflash_bank {
|
||||
uint32_t base;
|
||||
|
||||
struct mflash_gpio_num rst_pin;
|
||||
@@ -143,34 +139,34 @@ struct mflash_bank
|
||||
|
||||
int mflash_register_commands(struct command_context *cmd_ctx);
|
||||
|
||||
#define MG_MFLASH_SECTOR_SIZE (0x200) /* 512Bytes = 2^9 */
|
||||
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)
|
||||
#define MG_MFLASH_SECTOR_SIZE_SHIFT (9)
|
||||
#define MG_MFLASH_SECTOR_SIZE (0x200) /* 512Bytes = 2^9 */
|
||||
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)
|
||||
#define MG_MFLASH_SECTOR_SIZE_SHIFT (9)
|
||||
|
||||
#define MG_BUFFER_OFFSET 0x8000
|
||||
#define MG_REG_OFFSET 0xC000
|
||||
#define MG_REG_FEATURE 0x2 /* write case */
|
||||
#define MG_REG_ERROR 0x2 /* read case */
|
||||
#define MG_REG_SECT_CNT 0x4
|
||||
#define MG_REG_SECT_NUM 0x6
|
||||
#define MG_REG_CYL_LOW 0x8
|
||||
#define MG_REG_CYL_HIGH 0xA
|
||||
#define MG_REG_DRV_HEAD 0xC
|
||||
#define MG_REG_COMMAND 0xE /* write case */
|
||||
#define MG_REG_STATUS 0xE /* read case */
|
||||
#define MG_REG_DRV_CTRL 0x10
|
||||
#define MG_REG_BURST_CTRL 0x12
|
||||
#define MG_BUFFER_OFFSET 0x8000
|
||||
#define MG_REG_OFFSET 0xC000
|
||||
#define MG_REG_FEATURE 0x2 /* write case */
|
||||
#define MG_REG_ERROR 0x2 /* read case */
|
||||
#define MG_REG_SECT_CNT 0x4
|
||||
#define MG_REG_SECT_NUM 0x6
|
||||
#define MG_REG_CYL_LOW 0x8
|
||||
#define MG_REG_CYL_HIGH 0xA
|
||||
#define MG_REG_DRV_HEAD 0xC
|
||||
#define MG_REG_COMMAND 0xE /* write case */
|
||||
#define MG_REG_STATUS 0xE /* read case */
|
||||
#define MG_REG_DRV_CTRL 0x10
|
||||
#define MG_REG_BURST_CTRL 0x12
|
||||
|
||||
#define MG_OEM_DISK_WAIT_TIME_LONG 15000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_SHORT 1000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_LONG 15000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_SHORT 1000 /* msec */
|
||||
|
||||
#define MG_PLL_CLK_OUT 66000000.0 /* 66Mhz */
|
||||
#define MG_PLL_CLK_OUT 66000000.0 /* 66Mhz */
|
||||
#define MG_PLL_MAX_FEEDBACKDIV_VAL 512
|
||||
#define MG_PLL_MAX_INPUTDIV_VAL 32
|
||||
#define MG_PLL_MAX_OUTPUTDIV_VAL 4
|
||||
|
||||
#define MG_PLL_STD_INPUTCLK 12000000.0 /* 12Mhz */
|
||||
#define MG_PLL_STD_INPUTCLK 12000000.0 /* 12Mhz */
|
||||
#define MG_PLL_STD_LOCKCYCLE 10000
|
||||
|
||||
#define MG_UNLOCK_OTP_AREA 0xFF
|
||||
@@ -184,7 +180,7 @@ int mflash_register_commands(struct command_context *cmd_ctx);
|
||||
#define ERROR_MG_INVALID_OSC (-1605)
|
||||
#define ERROR_MG_UNSUPPORTED_SOC (-1606)
|
||||
|
||||
typedef enum _mg_io_type_wait{
|
||||
typedef enum _mg_io_type_wait {
|
||||
|
||||
mg_io_wait_bsy = 1,
|
||||
mg_io_wait_not_bsy = 2,
|
||||
@@ -196,20 +192,20 @@ typedef enum _mg_io_type_wait{
|
||||
} mg_io_type_wait;
|
||||
|
||||
/*= "Status Register" bit masks. */
|
||||
typedef enum _mg_io_type_rbit_status{
|
||||
typedef enum _mg_io_type_rbit_status {
|
||||
|
||||
mg_io_rbit_status_error = 0x01, /* error bit in status register */
|
||||
mg_io_rbit_status_corrected_error = 0x04, /* corrected error in status register */
|
||||
mg_io_rbit_status_data_req = 0x08, /* data request bit in status register */
|
||||
mg_io_rbit_status_seek_done = 0x10, /* DSC - Drive Seek Complete */
|
||||
mg_io_rbit_status_write_fault = 0x20, /* DWF - Drive Write Fault */
|
||||
mg_io_rbit_status_error = 0x01, /* error bit in status register */
|
||||
mg_io_rbit_status_corrected_error = 0x04, /* corrected error in status register */
|
||||
mg_io_rbit_status_data_req = 0x08, /* data request bit in status register */
|
||||
mg_io_rbit_status_seek_done = 0x10, /* DSC - Drive Seek Complete */
|
||||
mg_io_rbit_status_write_fault = 0x20, /* DWF - Drive Write Fault */
|
||||
mg_io_rbit_status_ready = 0x40,
|
||||
mg_io_rbit_status_busy = 0x80
|
||||
|
||||
} mg_io_type_rbit_status;
|
||||
|
||||
/*= "Error Register" bit masks. */
|
||||
typedef enum _mg_io_type_rbit_error{
|
||||
typedef enum _mg_io_type_rbit_error {
|
||||
|
||||
mg_io_rbit_err_general = 0x01,
|
||||
mg_io_rbit_err_aborted = 0x04,
|
||||
@@ -220,7 +216,7 @@ typedef enum _mg_io_type_rbit_error{
|
||||
} mg_io_type_rbit_error;
|
||||
|
||||
/* = "Device Control Register" bit. */
|
||||
typedef enum _mg_io_type_rbit_devc{
|
||||
typedef enum _mg_io_type_rbit_devc {
|
||||
|
||||
mg_io_rbit_devc_intr = 0x02, /* interrupt enable bit (1:disable, 0:enable) */
|
||||
mg_io_rbit_devc_srst = 0x04 /* softwrae reset bit (1:assert, 0:de-assert) */
|
||||
@@ -228,73 +224,68 @@ typedef enum _mg_io_type_rbit_devc{
|
||||
} mg_io_type_rbit_devc;
|
||||
|
||||
/* "Drive Select/Head Register" values. */
|
||||
typedef enum _mg_io_type_rval_dev{
|
||||
typedef enum _mg_io_type_rval_dev {
|
||||
|
||||
mg_io_rval_dev_must_be_on = 0x80, /* These 1 bits are always on */
|
||||
mg_io_rval_dev_drv_master = (0x00 | mg_io_rval_dev_must_be_on), /* Master */
|
||||
mg_io_rval_dev_drv_slave0 = (0x10 | mg_io_rval_dev_must_be_on), /* Slave0 */
|
||||
mg_io_rval_dev_drv_slave1 = (0x20 | mg_io_rval_dev_must_be_on), /* Slave1 */
|
||||
mg_io_rval_dev_drv_slave2 = (0x30 | mg_io_rval_dev_must_be_on), /* Slave2 */
|
||||
mg_io_rval_dev_lba_mode = (0x40 | mg_io_rval_dev_must_be_on)
|
||||
mg_io_rval_dev_must_be_on = 0x80, /* These 1 bits are always on */
|
||||
mg_io_rval_dev_drv_master = (0x00 | mg_io_rval_dev_must_be_on), /* Master */
|
||||
mg_io_rval_dev_drv_slave0 = (0x10 | mg_io_rval_dev_must_be_on), /* Slave0 */
|
||||
mg_io_rval_dev_drv_slave1 = (0x20 | mg_io_rval_dev_must_be_on), /* Slave1 */
|
||||
mg_io_rval_dev_drv_slave2 = (0x30 | mg_io_rval_dev_must_be_on), /* Slave2 */
|
||||
mg_io_rval_dev_lba_mode = (0x40 | mg_io_rval_dev_must_be_on)
|
||||
|
||||
} mg_io_type_rval_dev;
|
||||
|
||||
typedef enum _mg_io_type_cmd
|
||||
{
|
||||
mg_io_cmd_read =0x20,
|
||||
mg_io_cmd_write =0x30,
|
||||
typedef enum _mg_io_type_cmd {
|
||||
mg_io_cmd_read = 0x20,
|
||||
mg_io_cmd_write = 0x30,
|
||||
|
||||
mg_io_cmd_setmul =0xC6,
|
||||
mg_io_cmd_readmul =0xC4,
|
||||
mg_io_cmd_writemul =0xC5,
|
||||
mg_io_cmd_setmul = 0xC6,
|
||||
mg_io_cmd_readmul = 0xC4,
|
||||
mg_io_cmd_writemul = 0xC5,
|
||||
|
||||
mg_io_cmd_idle =0x97, /* 0xE3 */
|
||||
mg_io_cmd_idle_immediate =0x95, /* 0xE1 */
|
||||
mg_io_cmd_idle = 0x97, /* 0xE3 */
|
||||
mg_io_cmd_idle_immediate = 0x95, /* 0xE1 */
|
||||
|
||||
mg_io_cmd_setsleep =0x99, /* 0xE6 */
|
||||
mg_io_cmd_stdby =0x96, /* 0xE2 */
|
||||
mg_io_cmd_stdby_immediate =0x94, /* 0xE0 */
|
||||
mg_io_cmd_setsleep = 0x99, /* 0xE6 */
|
||||
mg_io_cmd_stdby = 0x96, /* 0xE2 */
|
||||
mg_io_cmd_stdby_immediate = 0x94, /* 0xE0 */
|
||||
|
||||
mg_io_cmd_identify =0xEC,
|
||||
mg_io_cmd_set_feature =0xEF,
|
||||
mg_io_cmd_identify = 0xEC,
|
||||
mg_io_cmd_set_feature = 0xEF,
|
||||
|
||||
mg_io_cmd_confirm_write =0x3C,
|
||||
mg_io_cmd_confirm_read =0x40,
|
||||
mg_io_cmd_wakeup =0xC3
|
||||
mg_io_cmd_confirm_write = 0x3C,
|
||||
mg_io_cmd_confirm_read = 0x40,
|
||||
mg_io_cmd_wakeup = 0xC3
|
||||
|
||||
} mg_io_type_cmd;
|
||||
|
||||
typedef enum _mg_feature_id
|
||||
{
|
||||
typedef enum _mg_feature_id {
|
||||
mg_feature_id_transmode = 0x3
|
||||
} mg_feature_id;
|
||||
|
||||
typedef enum _mg_feature_val
|
||||
{
|
||||
typedef enum _mg_feature_val {
|
||||
mg_feature_val_trans_default = 0x0,
|
||||
mg_feature_val_trans_vcmd = 0x3,
|
||||
mg_feature_val_trand_vcmds = 0x2
|
||||
} mg_feature_val;
|
||||
|
||||
typedef enum _mg_vcmd
|
||||
{
|
||||
mg_vcmd_update_xipinfo = 0xFA, /* 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_prep_fwpatch = 0xFD, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_exe_fwpatch = 0xFE, /* FWPATCH commmand through IOM I/O */
|
||||
typedef enum _mg_vcmd {
|
||||
mg_vcmd_update_xipinfo = 0xFA, /* 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_prep_fwpatch = 0xFD, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_exe_fwpatch = 0xFE, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_wr_pll = 0x8B,
|
||||
mg_vcmd_purge_nand = 0x8C, /* Only for Seagle */
|
||||
mg_vcmd_purge_nand = 0x8C, /* Only for Seagle */
|
||||
mg_vcmd_lock_otp = 0x8D,
|
||||
mg_vcmd_rd_otp = 0x8E,
|
||||
mg_vcmd_wr_otp = 0x8F
|
||||
} mg_vcmd;
|
||||
|
||||
typedef enum _mg_opmode
|
||||
{
|
||||
mg_op_mode_xip = 1, /* TRUE XIP */
|
||||
mg_op_mode_snd = 2, /* BOOT + Storage */
|
||||
mg_op_mode_stg = 0 /* Only Storage */
|
||||
typedef enum _mg_opmode {
|
||||
mg_op_mode_xip = 1, /* TRUE XIP */
|
||||
mg_op_mode_snd = 2, /* BOOT + Storage */
|
||||
mg_op_mode_stg = 0 /* Only Storage */
|
||||
} mg_opmode;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@ NAND_DRIVERS = \
|
||||
davinci.c \
|
||||
lpc3180.c \
|
||||
lpc32xx.c \
|
||||
mx2.c \
|
||||
mxc.c \
|
||||
mx3.c \
|
||||
orion.c \
|
||||
s3c24xx.c \
|
||||
@@ -37,7 +37,7 @@ noinst_HEADERS = \
|
||||
imp.h \
|
||||
lpc3180.h \
|
||||
lpc32xx.h \
|
||||
mx2.h \
|
||||
mxc.h \
|
||||
mx3.h \
|
||||
s3c24xx.h \
|
||||
s3c24xx_regs.h \
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <target/arm.h>
|
||||
#include <target/algorithm.h>
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -44,8 +43,8 @@
|
||||
* @return Success or failure of the operation
|
||||
*/
|
||||
static int arm_code_to_working_area(struct target *target,
|
||||
const uint32_t *code, unsigned code_size,
|
||||
unsigned additional, struct working_area **area)
|
||||
const uint32_t *code, unsigned code_size,
|
||||
unsigned additional, struct working_area **area)
|
||||
{
|
||||
uint8_t code_buf[code_size];
|
||||
unsigned i;
|
||||
@@ -61,7 +60,7 @@ static int arm_code_to_working_area(struct target *target,
|
||||
if (NULL == *area) {
|
||||
retval = target_alloc_working_area(target, size, area);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -95,13 +94,13 @@ static int arm_code_to_working_area(struct target *target,
|
||||
*/
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
||||
{
|
||||
struct target *target = nand->target;
|
||||
struct arm_algorithm algo;
|
||||
struct arm *armv4_5 = target->arch_info;
|
||||
struct reg_param reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit_var = 0;
|
||||
int retval;
|
||||
struct target *target = nand->target;
|
||||
struct arm_algorithm algo;
|
||||
struct arm *arm = target->arch_info;
|
||||
struct reg_param reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit_var = 0;
|
||||
int retval;
|
||||
|
||||
/* Inputs:
|
||||
* r0 NAND data address (byte wide)
|
||||
@@ -121,9 +120,8 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
||||
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
|
||||
retval = arm_code_to_working_area(target, code, sizeof(code),
|
||||
nand->chunk_size, &nand->copy_area);
|
||||
if (retval != ERROR_OK) {
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 arm_algorithm algo;
|
||||
struct arm *armv4_5 = target->arch_info;
|
||||
struct arm *arm = target->arch_info;
|
||||
struct reg_param reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit_var = 0;
|
||||
@@ -206,9 +204,8 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
||||
if (nand->op != ARM_NAND_READ || !nand->copy_area) {
|
||||
retval = arm_code_to_working_area(target, code, sizeof(code),
|
||||
nand->chunk_size, &nand->copy_area);
|
||||
if (retval != ERROR_OK) {
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
nand->op = ARM_NAND_READ;
|
||||
@@ -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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
* Available operational states the arm_nand_data struct can be in.
|
||||
*/
|
||||
enum arm_nand_op {
|
||||
ARM_NAND_NONE, /**< No operation performed. */
|
||||
ARM_NAND_READ, /**< Read operation performed. */
|
||||
ARM_NAND_WRITE, /**< Write operation performed. */
|
||||
ARM_NAND_NONE, /**< No operation performed. */
|
||||
ARM_NAND_READ, /**< Read operation performed. */
|
||||
ARM_NAND_WRITE, /**< Write operation performed. */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ struct arm_nand_data {
|
||||
struct target *target;
|
||||
|
||||
/** The copy area holds code loop and data for I/O operations. */
|
||||
struct working_area *copy_area;
|
||||
struct working_area *copy_area;
|
||||
|
||||
/** The chunk size is the page size or ECC chunk. */
|
||||
unsigned chunk_size;
|
||||
@@ -54,4 +54,4 @@ struct arm_nand_data {
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size);
|
||||
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size);
|
||||
|
||||
#endif /* __ARM_NANDIO_H */
|
||||
#endif /* __ARM_NANDIO_H */
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -26,13 +27,13 @@
|
||||
#include "imp.h"
|
||||
#include "arm_io.h"
|
||||
|
||||
#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */
|
||||
#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */
|
||||
#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */
|
||||
#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */
|
||||
#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */
|
||||
#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */
|
||||
#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */
|
||||
#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */
|
||||
#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */
|
||||
#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */
|
||||
#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */
|
||||
#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */
|
||||
#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */
|
||||
#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */
|
||||
|
||||
/**
|
||||
* Representation of a pin on an AT91SAM9 chip.
|
||||
@@ -97,9 +98,8 @@ static int at91sam9_init(struct nand_device *nand)
|
||||
{
|
||||
struct target *target = nand->target;
|
||||
|
||||
if (!at91sam9_halted(target, "init")) {
|
||||
if (!at91sam9_halted(target, "init"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 target *target = nand->target;
|
||||
|
||||
if (!at91sam9_halted(target, "command")) {
|
||||
if (!at91sam9_halted(target, "command"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!at91sam9_halted(nand->target, "reset")) {
|
||||
if (!at91sam9_halted(nand->target, "reset"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 target *target = nand->target;
|
||||
|
||||
if (!at91sam9_halted(nand->target, "address")) {
|
||||
if (!at91sam9_halted(nand->target, "address"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 target *target = nand->target;
|
||||
|
||||
if (!at91sam9_halted(nand->target, "read data")) {
|
||||
if (!at91sam9_halted(nand->target, "read data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 target *target = nand->target;
|
||||
|
||||
if (!at91sam9_halted(target, "write data")) {
|
||||
if (!at91sam9_halted(target, "write data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t status;
|
||||
|
||||
if (!at91sam9_halted(target, "nand ready")) {
|
||||
if (!at91sam9_halted(target, "nand ready"))
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
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;
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
} 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;
|
||||
int status;
|
||||
|
||||
if (!at91sam9_halted(nand->target, "read block")) {
|
||||
if (!at91sam9_halted(nand->target, "read block"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
io->chunk_size = nand->page_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;
|
||||
int status;
|
||||
|
||||
if (!at91sam9_halted(nand->target, "write block")) {
|
||||
if (!at91sam9_halted(nand->target, "write block"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
io->chunk_size = nand->page_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;
|
||||
}
|
||||
|
||||
// reset ECC parity registers
|
||||
/* reset ECC parity registers */
|
||||
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
|
||||
}
|
||||
|
||||
@@ -335,19 +326,19 @@ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
|
||||
* @param size Size of the OOB.
|
||||
* @return Pointer to an area to store OOB data.
|
||||
*/
|
||||
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) {
|
||||
// user doesn't want OOB, allocate it
|
||||
if (nand->page_size == 512) {
|
||||
/* user doesn't want OOB, allocate it */
|
||||
if (nand->page_size == 512)
|
||||
*size = 16;
|
||||
} else if (nand->page_size == 2048) {
|
||||
else if (nand->page_size == 2048)
|
||||
*size = 64;
|
||||
}
|
||||
|
||||
oob = malloc(*size);
|
||||
if (!oob) {
|
||||
LOG_ERROR("Unable to allocate space for OOB");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(oob, 0xFF, *size);
|
||||
@@ -370,7 +361,7 @@ static uint8_t * at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint3
|
||||
* @return Success or failure of reading the NAND page.
|
||||
*/
|
||||
static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int retval;
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
@@ -379,20 +370,17 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
||||
uint32_t status;
|
||||
|
||||
retval = at91sam9_ecc_init(target, info);
|
||||
if (ERROR_OK != retval) {
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
|
||||
if (ERROR_OK != retval) {
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
retval = nand_read_data_page(nand, data, data_size);
|
||||
if (ERROR_OK != retval) {
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
||||
@@ -401,33 +389,33 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
||||
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
|
||||
if (status & 1) {
|
||||
LOG_ERROR("Error detected!");
|
||||
if (status & 4) {
|
||||
if (status & 4)
|
||||
LOG_ERROR("Multiple errors encountered; unrecoverable!");
|
||||
} else {
|
||||
// attempt recovery
|
||||
else {
|
||||
/* attempt recovery */
|
||||
uint32_t parity;
|
||||
|
||||
target_read_u32(target,
|
||||
info->ecc + AT91C_ECCx_PR,
|
||||
&parity);
|
||||
info->ecc + AT91C_ECCx_PR,
|
||||
&parity);
|
||||
uint32_t word = (parity & 0x0000FFF0) >> 4;
|
||||
uint32_t bit = parity & 0x0F;
|
||||
|
||||
data[word] ^= (0x1) << bit;
|
||||
LOG_INFO("Data word %d, bit %d corrected.",
|
||||
(unsigned) word,
|
||||
(unsigned) bit);
|
||||
(unsigned) word,
|
||||
(unsigned) bit);
|
||||
}
|
||||
}
|
||||
|
||||
if (status & 2) {
|
||||
// we could write back correct ECC data
|
||||
/* we could write back correct ECC data */
|
||||
LOG_ERROR("Error in ECC bytes detected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!oob) {
|
||||
// if it wasn't asked for, free it
|
||||
/* if it wasn't asked for, free it */
|
||||
free(oob_data);
|
||||
}
|
||||
|
||||
@@ -448,7 +436,7 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
||||
* @return Success or failure of the page write.
|
||||
*/
|
||||
static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = nand->target;
|
||||
@@ -457,14 +445,12 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
||||
uint32_t parity, nparity;
|
||||
|
||||
retval = at91sam9_ecc_init(target, info);
|
||||
if (ERROR_OK != retval) {
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
||||
if (ERROR_OK != retval) {
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
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);
|
||||
|
||||
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_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);
|
||||
|
||||
if (!oob) {
|
||||
if (!oob)
|
||||
free(oob_data);
|
||||
}
|
||||
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("Unable to write OOB data to NAND");
|
||||
@@ -593,9 +578,8 @@ COMMAND_HANDLER(handle_at91sam9_ale_command)
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, address_line;
|
||||
|
||||
if (CMD_ARGC != 2) {
|
||||
if (CMD_ARGC != 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
@@ -622,9 +606,8 @@ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command)
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, base_pioc, pin_num;
|
||||
|
||||
if (CMD_ARGC != 3) {
|
||||
if (CMD_ARGC != 3)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
@@ -654,9 +637,8 @@ COMMAND_HANDLER(handle_at91sam9_ce_command)
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, base_pioc, pin_num;
|
||||
|
||||
if (CMD_ARGC != 3) {
|
||||
if (CMD_ARGC != 3)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
@@ -715,6 +697,7 @@ static const struct command_registration at91sam9_command_handler[] = {
|
||||
.name = "at91sam9",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "AT91SAM9 NAND flash controller commands",
|
||||
.usage = "",
|
||||
.chain = at91sam9_sub_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -27,13 +28,14 @@
|
||||
#include "imp.h"
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (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;
|
||||
} else
|
||||
nand_devices = c;
|
||||
@@ -50,94 +52,94 @@ void nand_device_add(struct nand_device *c)
|
||||
* 256 256 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 */
|
||||
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "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"},
|
||||
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS,
|
||||
"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 */
|
||||
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
|
||||
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"},
|
||||
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"},
|
||||
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
|
||||
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"},
|
||||
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"},
|
||||
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||
|
||||
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"},
|
||||
/* end "museum" IDs */
|
||||
|
||||
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"},
|
||||
|
||||
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"},
|
||||
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"},
|
||||
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"},
|
||||
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"},
|
||||
|
||||
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||
|
||||
{0, 0, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
/* Manufacturer ID list
|
||||
*/
|
||||
static struct nand_manufacturer nand_manuf_ids[] =
|
||||
{
|
||||
static struct nand_manufacturer nand_manuf_ids[] = {
|
||||
{0x0, "unknown"},
|
||||
{NAND_MFR_TOSHIBA, "Toshiba"},
|
||||
{NAND_MFR_SAMSUNG, "Samsung"},
|
||||
@@ -162,7 +164,8 @@ static struct nand_ecclayout nand_oob_8 = {
|
||||
{.offset = 3,
|
||||
.length = 2},
|
||||
{.offset = 6,
|
||||
.length = 2}}
|
||||
.length = 2}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -179,8 +182,7 @@ static struct nand_device *get_nand_device_by_name(const char *name)
|
||||
unsigned found = 0;
|
||||
|
||||
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)
|
||||
return nand;
|
||||
if (!flash_driver_name_matches(nand->controller->name, name))
|
||||
@@ -197,19 +199,16 @@ struct nand_device *get_nand_device_by_num(int num)
|
||||
struct nand_device *p;
|
||||
int i = 0;
|
||||
|
||||
for (p = nand_devices; p; p = p->next)
|
||||
{
|
||||
for (p = nand_devices; p; p = p->next) {
|
||||
if (i++ == num)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||
struct nand_device **nand)
|
||||
struct nand_device **nand)
|
||||
{
|
||||
const char *str = CMD_ARGV[name_index];
|
||||
*nand = get_nand_device_by_name(str);
|
||||
@@ -221,7 +220,7 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||
*nand = get_nand_device_by_num(num);
|
||||
if (!*nand) {
|
||||
command_print(CMD_CTX, "NAND flash device '%s' not found", str);
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -241,23 +240,18 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
|
||||
last = nand->num_blocks - 1;
|
||||
|
||||
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);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|
||||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
||||
((nand->page_size == 2048) && (oob[0] != 0xff))))
|
||||
{
|
||||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
||||
((nand->page_size == 2048) && (oob[0] != 0xff)))) {
|
||||
LOG_WARNING("bad block: %i", i);
|
||||
nand->blocks[i].is_bad = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
nand->blocks[i].is_bad = 0;
|
||||
}
|
||||
|
||||
page += pages_per_block;
|
||||
}
|
||||
@@ -276,16 +270,12 @@ int nand_read_status(struct nand_device *nand, uint8_t *status)
|
||||
alive_sleep(1);
|
||||
|
||||
/* read status */
|
||||
if (nand->device->options & NAND_BUSWIDTH_16)
|
||||
{
|
||||
if (nand->device->options & NAND_BUSWIDTH_16) {
|
||||
uint16_t data;
|
||||
nand->controller->read_data(nand, &data);
|
||||
*status = data & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
nand->controller->read_data(nand, status);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -300,9 +290,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout)
|
||||
uint16_t data;
|
||||
nand->controller->read_data(nand, &data);
|
||||
status = data & 0xff;
|
||||
} else {
|
||||
} else
|
||||
nand->controller->read_data(nand, &status);
|
||||
}
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
alive_sleep(1);
|
||||
@@ -329,15 +318,15 @@ int nand_probe(struct nand_device *nand)
|
||||
nand->erase_size = 0;
|
||||
|
||||
/* initialize controller (device parameters are zero, use controller default) */
|
||||
if ((retval = nand->controller->init(nand) != ERROR_OK))
|
||||
{
|
||||
switch (retval)
|
||||
{
|
||||
retval = nand->controller->init(nand);
|
||||
if (retval != ERROR_OK) {
|
||||
switch (retval) {
|
||||
case ERROR_NAND_OPERATION_FAILED:
|
||||
LOG_DEBUG("controller initialization failed");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
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;
|
||||
default:
|
||||
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->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, &device_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint16_t data_buf;
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
manufacturer_id = data_buf & 0xff;
|
||||
@@ -365,36 +351,32 @@ int nand_probe(struct nand_device *nand)
|
||||
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 &&
|
||||
(nand_flash_ids[i].mfr_id == manufacturer_id ||
|
||||
nand_flash_ids[i].mfr_id == 0 ))
|
||||
{
|
||||
(nand_flash_ids[i].mfr_id == manufacturer_id ||
|
||||
nand_flash_ids[i].mfr_id == 0)) {
|
||||
nand->device = &nand_flash_ids[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; nand_manuf_ids[i].name; i++)
|
||||
{
|
||||
if (nand_manuf_ids[i].id == manufacturer_id)
|
||||
{
|
||||
for (i = 0; nand_manuf_ids[i].name; i++) {
|
||||
if (nand_manuf_ids[i].id == manufacturer_id) {
|
||||
nand->manufacturer = &nand_manuf_ids[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nand->manufacturer)
|
||||
{
|
||||
if (!nand->manufacturer) {
|
||||
nand->manufacturer = &nand_manuf_ids[0];
|
||||
nand->manufacturer->id = manufacturer_id;
|
||||
}
|
||||
|
||||
if (!nand->device)
|
||||
{
|
||||
LOG_ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
|
||||
manufacturer_id, device_id);
|
||||
if (!nand->device) {
|
||||
LOG_ERROR(
|
||||
"unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
|
||||
manufacturer_id,
|
||||
device_id);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -410,16 +392,12 @@ int nand_probe(struct nand_device *nand)
|
||||
|
||||
/* Do we need extended device probe information? */
|
||||
if (nand->device->page_size == 0 ||
|
||||
nand->device->erase_size == 0)
|
||||
{
|
||||
if (nand->bus_width == 8)
|
||||
{
|
||||
nand->device->erase_size == 0) {
|
||||
if (nand->bus_width == 8) {
|
||||
nand->controller->read_data(nand, id_buff + 3);
|
||||
nand->controller->read_data(nand, id_buff + 4);
|
||||
nand->controller->read_data(nand, id_buff + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint16_t data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
@@ -435,81 +413,68 @@ int nand_probe(struct nand_device *nand)
|
||||
|
||||
/* page size */
|
||||
if (nand->device->page_size == 0)
|
||||
{
|
||||
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");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
nand->page_size = nand->device->page_size;
|
||||
}
|
||||
|
||||
/* number of address cycles */
|
||||
if (nand->page_size <= 512)
|
||||
{
|
||||
if (nand->page_size <= 512) {
|
||||
/* small page devices */
|
||||
if (nand->device->chip_size <= 32)
|
||||
nand->address_cycles = 3;
|
||||
else if (nand->device->chip_size <= 8*1024)
|
||||
nand->address_cycles = 4;
|
||||
else
|
||||
{
|
||||
else {
|
||||
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
|
||||
nand->address_cycles = 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* large page devices */
|
||||
if (nand->device->chip_size <= 128)
|
||||
nand->address_cycles = 4;
|
||||
else if (nand->device->chip_size <= 32*1024)
|
||||
nand->address_cycles = 5;
|
||||
else
|
||||
{
|
||||
else {
|
||||
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
|
||||
nand->address_cycles = 6;
|
||||
}
|
||||
}
|
||||
|
||||
/* erase size */
|
||||
if (nand->device->erase_size == 0)
|
||||
{
|
||||
if (nand->device->erase_size == 0) {
|
||||
switch ((id_buff[4] >> 4) & 3) {
|
||||
case 0:
|
||||
nand->erase_size = 64 << 10;
|
||||
break;
|
||||
case 1:
|
||||
nand->erase_size = 128 << 10;
|
||||
break;
|
||||
case 2:
|
||||
nand->erase_size = 256 << 10;
|
||||
break;
|
||||
case 3:
|
||||
nand->erase_size =512 << 10;
|
||||
break;
|
||||
case 0:
|
||||
nand->erase_size = 64 << 10;
|
||||
break;
|
||||
case 1:
|
||||
nand->erase_size = 128 << 10;
|
||||
break;
|
||||
case 2:
|
||||
nand->erase_size = 256 << 10;
|
||||
break;
|
||||
case 3:
|
||||
nand->erase_size = 512 << 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
nand->erase_size = nand->device->erase_size;
|
||||
}
|
||||
|
||||
/* initialize controller, but leave parameters at the controllers default */
|
||||
if ((retval = nand->controller->init(nand) != ERROR_OK))
|
||||
{
|
||||
switch (retval)
|
||||
{
|
||||
retval = nand->controller->init(nand);
|
||||
if (retval != ERROR_OK) {
|
||||
switch (retval) {
|
||||
case ERROR_NAND_OPERATION_FAILED:
|
||||
LOG_DEBUG("controller initialization failed");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
|
||||
LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
|
||||
nand->bus_width, nand->address_cycles, nand->page_size);
|
||||
LOG_ERROR(
|
||||
"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;
|
||||
default:
|
||||
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->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].offset = i * nand->erase_size;
|
||||
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;
|
||||
|
||||
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 */
|
||||
for (i = first_block; i <= last_block; i++)
|
||||
{
|
||||
if (nand->blocks[i].is_bad == -1)
|
||||
{
|
||||
for (i = first_block; i <= last_block; i++) {
|
||||
if (nand->blocks[i].is_bad == -1) {
|
||||
nand_build_bbt(nand, i, last_block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = first_block; i <= last_block; i++)
|
||||
{
|
||||
for (i = first_block; i <= last_block; i++) {
|
||||
/* Send erase setup command */
|
||||
nand->controller->command(nand, NAND_CMD_ERASE1);
|
||||
|
||||
page = i * (nand->erase_size / nand->page_size);
|
||||
|
||||
/* Send page address */
|
||||
if (nand->page_size <= 512)
|
||||
{
|
||||
if (nand->page_size <= 512) {
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 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 */
|
||||
if (nand->address_cycles >= 5)
|
||||
nand->controller->address(nand, (page >> 24) & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 0xff);
|
||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||
@@ -591,25 +549,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
||||
nand->controller->command(nand, NAND_CMD_ERASE2);
|
||||
|
||||
retval = nand->controller->nand_ready ?
|
||||
nand->controller->nand_ready(nand, 1000) :
|
||||
nand_poll_ready(nand, 1000);
|
||||
nand->controller->nand_ready(nand, 1000) :
|
||||
nand_poll_ready(nand, 1000);
|
||||
if (!retval) {
|
||||
LOG_ERROR("timeout waiting for NAND flash block erase to complete");
|
||||
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");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (status & 0x1)
|
||||
{
|
||||
if (status & 0x1) {
|
||||
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
|
||||
(nand->blocks[i].is_bad == 1)
|
||||
? "bad " : "",
|
||||
i, status);
|
||||
(nand->blocks[i].is_bad == 1)
|
||||
? "bad " : "",
|
||||
i, status);
|
||||
/* continue; other blocks might still be erasable */
|
||||
}
|
||||
|
||||
@@ -620,23 +577,24 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
if (address % nand->page_size)
|
||||
{
|
||||
if (address % nand->page_size) {
|
||||
LOG_ERROR("reads need to be page aligned");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 page_address;
|
||||
|
||||
@@ -657,23 +615,24 @@ static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *
|
||||
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;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
if (address % nand->page_size)
|
||||
{
|
||||
if (address % nand->page_size) {
|
||||
LOG_ERROR("writes need to be page aligned");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
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 page_address;
|
||||
|
||||
@@ -696,8 +655,8 @@ static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t
|
||||
#endif
|
||||
|
||||
int nand_write_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
uint32_t block;
|
||||
|
||||
@@ -715,8 +674,8 @@ int nand_write_page(struct nand_device *nand, uint32_t page,
|
||||
}
|
||||
|
||||
int nand_read_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -728,7 +687,7 @@ int nand_read_page(struct nand_device *nand, uint32_t page,
|
||||
}
|
||||
|
||||
int nand_page_command(struct nand_device *nand, uint32_t page,
|
||||
uint8_t cmd, bool oob_only)
|
||||
uint8_t cmd, bool oob_only)
|
||||
{
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -813,8 +772,8 @@ int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
|
||||
}
|
||||
|
||||
int nand_read_page_raw(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -869,8 +828,8 @@ int nand_write_finish(struct nand_device *nand)
|
||||
nand->controller->command(nand, NAND_CMD_PAGEPROG);
|
||||
|
||||
retval = nand->controller->nand_ready ?
|
||||
nand->controller->nand_ready(nand, 100) :
|
||||
nand_poll_ready(nand, 100);
|
||||
nand->controller->nand_ready(nand, 100) :
|
||||
nand_poll_ready(nand, 100);
|
||||
if (!retval)
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
|
||||
@@ -882,7 +841,7 @@ int nand_write_finish(struct nand_device *nand)
|
||||
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
LOG_ERROR("write operation didn't pass, status: 0x%2.2x",
|
||||
status);
|
||||
status);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -890,8 +849,8 @@ int nand_write_finish(struct nand_device *nand)
|
||||
}
|
||||
|
||||
int nand_write_page_raw(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -917,4 +876,3 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page,
|
||||
|
||||
return nand_write_finish(nand);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FLASH_NAND_CORE_H
|
||||
#define FLASH_NAND_CORE_H
|
||||
|
||||
@@ -30,8 +31,7 @@
|
||||
/**
|
||||
* Representation of a single NAND block in a NAND device.
|
||||
*/
|
||||
struct nand_block
|
||||
{
|
||||
struct nand_block {
|
||||
/** Offset to the block. */
|
||||
uint32_t offset;
|
||||
|
||||
@@ -57,8 +57,7 @@ struct nand_ecclayout {
|
||||
struct nand_oobfree oobfree[2];
|
||||
};
|
||||
|
||||
struct nand_device
|
||||
{
|
||||
struct nand_device {
|
||||
const char *name;
|
||||
struct target *target;
|
||||
struct nand_flash_controller *controller;
|
||||
@@ -77,8 +76,7 @@ struct nand_device
|
||||
|
||||
/* NAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
NAND_MFR_TOSHIBA = 0x98,
|
||||
NAND_MFR_SAMSUNG = 0xec,
|
||||
NAND_MFR_FUJITSU = 0x04,
|
||||
@@ -89,14 +87,12 @@ enum
|
||||
NAND_MFR_MICRON = 0x2c,
|
||||
};
|
||||
|
||||
struct nand_manufacturer
|
||||
{
|
||||
struct nand_manufacturer {
|
||||
int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct nand_info
|
||||
{
|
||||
struct nand_info {
|
||||
int mfr_id;
|
||||
int id;
|
||||
int page_size;
|
||||
@@ -152,8 +148,7 @@ enum {
|
||||
LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16),
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
/* Standard NAND flash commands */
|
||||
NAND_CMD_READ0 = 0x0,
|
||||
NAND_CMD_READ1 = 0x1,
|
||||
@@ -161,7 +156,7 @@ enum
|
||||
NAND_CMD_PAGEPROG = 0x10,
|
||||
NAND_CMD_READOOB = 0x50,
|
||||
NAND_CMD_ERASE1 = 0x60,
|
||||
NAND_CMD_STATUS = 0x70,
|
||||
NAND_CMD_STATUS = 0x70,
|
||||
NAND_CMD_STATUS_MULTI = 0x71,
|
||||
NAND_CMD_SEQIN = 0x80,
|
||||
NAND_CMD_RNDIN = 0x85,
|
||||
@@ -176,8 +171,7 @@ enum
|
||||
};
|
||||
|
||||
/* Status bits */
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
NAND_STATUS_FAIL = 0x01,
|
||||
NAND_STATUS_FAIL_N1 = 0x02,
|
||||
NAND_STATUS_TRUE_READY = 0x20,
|
||||
@@ -186,14 +180,14 @@ enum
|
||||
};
|
||||
|
||||
/* OOB (spare) data formats */
|
||||
enum oob_formats
|
||||
{
|
||||
enum oob_formats {
|
||||
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_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_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */
|
||||
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
|
||||
NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */
|
||||
NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
|
||||
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
|
||||
};
|
||||
@@ -202,40 +196,39 @@ enum oob_formats
|
||||
struct nand_device *get_nand_device_by_num(int num);
|
||||
|
||||
int nand_page_command(struct nand_device *nand, uint32_t page,
|
||||
uint8_t cmd, bool oob_only);
|
||||
uint8_t cmd, bool oob_only);
|
||||
|
||||
int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size);
|
||||
int nand_write_data_page(struct nand_device *nand,
|
||||
uint8_t *data, uint32_t size);
|
||||
uint8_t *data, uint32_t size);
|
||||
|
||||
int nand_write_finish(struct nand_device *nand);
|
||||
|
||||
int nand_read_page_raw(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int nand_write_page_raw(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
|
||||
int nand_read_status(struct nand_device *nand, uint8_t *status);
|
||||
|
||||
int nand_calculate_ecc(struct nand_device *nand,
|
||||
const uint8_t *dat, uint8_t *ecc_code);
|
||||
const uint8_t *dat, uint8_t *ecc_code);
|
||||
int nand_calculate_ecc_kw(struct nand_device *nand,
|
||||
const uint8_t *dat, uint8_t *ecc_code);
|
||||
const uint8_t *dat, uint8_t *ecc_code);
|
||||
|
||||
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,
|
||||
struct nand_device **nand);
|
||||
struct nand_device **nand);
|
||||
|
||||
|
||||
#define ERROR_NAND_DEVICE_INVALID (-1100)
|
||||
#define ERROR_NAND_OPERATION_FAILED (-1101)
|
||||
#define ERROR_NAND_OPERATION_TIMEOUT (-1102)
|
||||
#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103)
|
||||
#define ERROR_NAND_DEVICE_NOT_PROBED (-1104)
|
||||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
||||
#define ERROR_NAND_NO_BUFFER (-1106)
|
||||
|
||||
#endif // FLASH_NAND_CORE_H
|
||||
#define ERROR_NAND_DEVICE_INVALID (-1100)
|
||||
#define ERROR_NAND_OPERATION_FAILED (-1101)
|
||||
#define ERROR_NAND_OPERATION_TIMEOUT (-1102)
|
||||
#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103)
|
||||
#define ERROR_NAND_DEVICE_NOT_PROBED (-1104)
|
||||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
||||
#define ERROR_NAND_NO_BUFFER (-1106)
|
||||
|
||||
#endif /* FLASH_NAND_CORE_H */
|
||||
|
||||
@@ -39,34 +39,34 @@ enum ecc {
|
||||
};
|
||||
|
||||
struct davinci_nand {
|
||||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
||||
uint8_t eccmode;
|
||||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
||||
uint8_t eccmode;
|
||||
|
||||
/* Async EMIF controller base */
|
||||
uint32_t aemif;
|
||||
uint32_t aemif;
|
||||
|
||||
/* NAND chip addresses */
|
||||
uint32_t data; /* without CLE or ALE */
|
||||
uint32_t cmd; /* with CLE */
|
||||
uint32_t addr; /* with ALE */
|
||||
uint32_t data; /* without CLE or ALE */
|
||||
uint32_t cmd; /* with CLE */
|
||||
uint32_t addr; /* with ALE */
|
||||
|
||||
/* write acceleration */
|
||||
struct arm_nand_data io;
|
||||
struct arm_nand_data io;
|
||||
|
||||
/* page i/o for the relevant flavor of hardware ECC */
|
||||
int (*read_page)(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
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);
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
};
|
||||
|
||||
#define NANDFCR 0x60 /* flash control register */
|
||||
#define NANDFSR 0x64 /* flash status register */
|
||||
#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */
|
||||
#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */
|
||||
#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */
|
||||
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */
|
||||
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */
|
||||
#define NANDFCR 0x60 /* flash control register */
|
||||
#define NANDFSR 0x64 /* flash status register */
|
||||
#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */
|
||||
#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */
|
||||
#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */
|
||||
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */
|
||||
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */
|
||||
|
||||
static int halted(struct target *target, const char *label)
|
||||
{
|
||||
@@ -181,7 +181,7 @@ static int davinci_read_data(struct nand_device *nand, void *data)
|
||||
/* REVISIT a bit of native code should let block reads be MUCH faster */
|
||||
|
||||
static int davinci_read_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size)
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
struct target *target = nand->target;
|
||||
@@ -214,7 +214,7 @@ static int davinci_read_block_data(struct nand_device *nand,
|
||||
}
|
||||
|
||||
static int davinci_write_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size)
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
struct target *target = nand->target;
|
||||
@@ -250,7 +250,7 @@ static int davinci_write_block_data(struct nand_device *nand,
|
||||
}
|
||||
|
||||
static int davinci_write_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
uint8_t *ooballoc = NULL;
|
||||
@@ -269,17 +269,17 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
|
||||
|
||||
/* If we're not given OOB, write 0xff where we don't write ECC codes. */
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
oob_size = 16;
|
||||
break;
|
||||
case 2048:
|
||||
oob_size = 64;
|
||||
break;
|
||||
case 4096:
|
||||
oob_size = 128;
|
||||
break;
|
||||
default:
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
case 512:
|
||||
oob_size = 16;
|
||||
break;
|
||||
case 2048:
|
||||
oob_size = 64;
|
||||
break;
|
||||
case 4096:
|
||||
oob_size = 128;
|
||||
break;
|
||||
default:
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
if (!oob) {
|
||||
ooballoc = malloc(oob_size);
|
||||
@@ -301,7 +301,7 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
|
||||
}
|
||||
|
||||
static int davinci_read_page(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
|
||||
@@ -358,7 +358,7 @@ static int davinci_seek_column(struct nand_device *nand, uint16_t column)
|
||||
}
|
||||
|
||||
static int davinci_writepage_tail(struct nand_device *nand,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
struct target *target = nand->target;
|
||||
@@ -390,7 +390,7 @@ static int davinci_writepage_tail(struct nand_device *nand,
|
||||
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
|
||||
*/
|
||||
static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
unsigned oob_offset;
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
@@ -404,15 +404,15 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
|
||||
* for 16-bit OOB, those extra bytes are discontiguous.
|
||||
*/
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
oob_offset = 0;
|
||||
break;
|
||||
case 2048:
|
||||
oob_offset = 40;
|
||||
break;
|
||||
default:
|
||||
oob_offset = 80;
|
||||
break;
|
||||
case 512:
|
||||
oob_offset = 0;
|
||||
break;
|
||||
case 2048:
|
||||
oob_offset = 40;
|
||||
break;
|
||||
default:
|
||||
oob_offset = 80;
|
||||
break;
|
||||
}
|
||||
|
||||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
|
||||
@@ -457,10 +457,10 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
|
||||
* manufacturer bad block markers are safe. Contrast: old "infix" style.
|
||||
*/
|
||||
static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
static const uint8_t ecc512[] = {
|
||||
0, 1, 2, 3, 4, /* 5== mfr badblock */
|
||||
0, 1, 2, 3, 4, /* 5== mfr badblock */
|
||||
6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15,
|
||||
};
|
||||
static const uint8_t ecc2048[] = {
|
||||
@@ -470,12 +470,12 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
};
|
||||
static const uint8_t ecc4096[] = {
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
|
||||
78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
|
||||
78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
|
||||
118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
};
|
||||
@@ -495,15 +495,15 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
||||
* the standard ECC logic can't handle.
|
||||
*/
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
l = ecc512;
|
||||
break;
|
||||
case 2048:
|
||||
l = ecc2048;
|
||||
break;
|
||||
default:
|
||||
l = ecc4096;
|
||||
break;
|
||||
case 512:
|
||||
l = ecc512;
|
||||
break;
|
||||
case 2048:
|
||||
l = ecc2048;
|
||||
break;
|
||||
default:
|
||||
l = ecc4096;
|
||||
break;
|
||||
}
|
||||
|
||||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
|
||||
@@ -533,11 +533,11 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
||||
raw_ecc[i] &= 0x03ff03ff;
|
||||
}
|
||||
for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
|
||||
oob[*l++] = p[0] & 0xff;
|
||||
oob[*l++] = p[0] & 0xff;
|
||||
oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
|
||||
oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
|
||||
oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
|
||||
oob[*l++] = (p[1] >> 18) & 0xff;
|
||||
oob[*l++] = (p[1] >> 18) & 0xff;
|
||||
}
|
||||
|
||||
} while (data_size);
|
||||
@@ -559,7 +559,7 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
||||
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
|
||||
*/
|
||||
static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
struct target *target = nand->target;
|
||||
@@ -597,11 +597,11 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
||||
|
||||
/* skip 6 bytes of prepad, then pack 10 packed ecc bytes */
|
||||
for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) {
|
||||
*l++ = p[0] & 0xff;
|
||||
*l++ = p[0] & 0xff;
|
||||
*l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
|
||||
*l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
|
||||
*l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
|
||||
*l++ = (p[1] >> 18) & 0xff;
|
||||
*l++ = (p[1] >> 18) & 0xff;
|
||||
}
|
||||
|
||||
/* write this "out-of-band" data -- infix */
|
||||
@@ -616,7 +616,7 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
||||
}
|
||||
|
||||
static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int read_size;
|
||||
int want_col, at_col;
|
||||
@@ -688,12 +688,8 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||
* - aemif address
|
||||
* Plus someday, optionally, ALE and CLE masks.
|
||||
*/
|
||||
if (CMD_ARGC < 5) {
|
||||
LOG_ERROR("parameters: %s target "
|
||||
"chip_addr hwecc_mode aemif_addr",
|
||||
CMD_ARGV[0]);
|
||||
goto fail;
|
||||
}
|
||||
if (CMD_ARGC < 5)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||
if (chip == 0) {
|
||||
@@ -723,9 +719,9 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||
* AEMIF controller address.
|
||||
*/
|
||||
if (aemif == 0x01e00000 /* dm6446, dm357 */
|
||||
|| aemif == 0x01e10000 /* dm335, dm355 */
|
||||
|| aemif == 0x01d10000 /* dm365 */
|
||||
) {
|
||||
|| aemif == 0x01e10000 /* dm335, dm355 */
|
||||
|| aemif == 0x01d10000 /* dm365 */
|
||||
) {
|
||||
if (chip < 0x02000000 || chip >= 0x0a000000) {
|
||||
LOG_ERROR("NAND address %08lx out of range?", chip);
|
||||
goto fail;
|
||||
@@ -760,19 +756,19 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||
info->read_page = nand_read_page_raw;
|
||||
|
||||
switch (eccmode) {
|
||||
case HWECC1:
|
||||
/* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc1;
|
||||
break;
|
||||
case HWECC4:
|
||||
/* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc4;
|
||||
break;
|
||||
case HWECC4_INFIX:
|
||||
/* Same 4-bit ECC HW, with problematic page/ecc layout */
|
||||
info->read_page = davinci_read_page_ecc4infix;
|
||||
info->write_page = davinci_write_page_ecc4infix;
|
||||
break;
|
||||
case HWECC1:
|
||||
/* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc1;
|
||||
break;
|
||||
case HWECC4:
|
||||
/* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc4;
|
||||
break;
|
||||
case HWECC4_INFIX:
|
||||
/* Same 4-bit ECC HW, with problematic page/ecc layout */
|
||||
info->read_page = davinci_read_page_ecc4infix;
|
||||
info->write_page = davinci_write_page_ecc4infix;
|
||||
break;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -782,17 +778,18 @@ fail:
|
||||
}
|
||||
|
||||
struct nand_flash_controller davinci_nand_controller = {
|
||||
.name = "davinci",
|
||||
.nand_device_command = davinci_nand_device_command,
|
||||
.init = davinci_init,
|
||||
.reset = davinci_reset,
|
||||
.command = davinci_command,
|
||||
.address = davinci_address,
|
||||
.write_data = davinci_write_data,
|
||||
.read_data = davinci_read_data,
|
||||
.write_page = davinci_write_page,
|
||||
.read_page = davinci_read_page,
|
||||
.write_block_data = davinci_write_block_data,
|
||||
.read_block_data = davinci_read_block_data,
|
||||
.nand_ready = davinci_nand_ready,
|
||||
.name = "davinci",
|
||||
.usage = "chip_addr hwecc_mode aemif_addr",
|
||||
.nand_device_command = davinci_nand_device_command,
|
||||
.init = davinci_init,
|
||||
.reset = davinci_reset,
|
||||
.command = davinci_command,
|
||||
.address = davinci_address,
|
||||
.write_data = davinci_write_data,
|
||||
.read_data = davinci_read_data,
|
||||
.write_page = davinci_write_page,
|
||||
.read_page = davinci_read_page,
|
||||
.write_block_data = davinci_write_block_data,
|
||||
.read_block_data = davinci_read_block_data,
|
||||
.nand_ready = davinci_nand_ready,
|
||||
};
|
||||
|
||||
@@ -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 s3c2443_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 at91sam9_nand_controller;
|
||||
extern struct nand_flash_controller nuc910_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,
|
||||
&davinci_nand_controller,
|
||||
&lpc3180_nand_controller,
|
||||
@@ -57,7 +56,7 @@ static struct nand_flash_controller *nand_flash_controllers[] =
|
||||
&s3c2440_nand_controller,
|
||||
&s3c2443_nand_controller,
|
||||
&s3c6400_nand_controller,
|
||||
&imx27_nand_flash_controller,
|
||||
&mxc_nand_flash_controller,
|
||||
&imx31_nand_flash_controller,
|
||||
&at91sam9_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)
|
||||
{
|
||||
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];
|
||||
if (strcmp(name, controller->name) == 0)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,25 +19,28 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FLASH_NAND_DRIVER_H
|
||||
#define FLASH_NAND_DRIVER_H
|
||||
|
||||
struct nand_device;
|
||||
|
||||
#define __NAND_DEVICE_COMMAND(name) \
|
||||
COMMAND_HELPER(name, struct nand_device *nand)
|
||||
COMMAND_HELPER(name, struct nand_device *nand)
|
||||
|
||||
/**
|
||||
* Interface for NAND flash controllers. Not all of these functions are
|
||||
* required for full functionality of the NAND driver, but better performance
|
||||
* 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. */
|
||||
const char *name;
|
||||
|
||||
const struct command_registration *commands;
|
||||
/** Usage of flash command registration. */
|
||||
const char *usage;
|
||||
|
||||
const struct command_registration *commands;
|
||||
|
||||
/** NAND device command called when driver is instantiated during configuration. */
|
||||
__NAND_DEVICE_COMMAND((*nand_device_command));
|
||||
@@ -67,10 +70,12 @@ struct nand_flash_controller
|
||||
int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size);
|
||||
|
||||
/** 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. */
|
||||
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. */
|
||||
int (*nand_ready)(struct nand_device *nand, int timeout);
|
||||
@@ -85,8 +90,8 @@ struct nand_flash_controller
|
||||
*/
|
||||
struct nand_flash_controller *nand_driver_find_by_name(const char *name);
|
||||
|
||||
/// Signature for callback functions passed to nand_driver_walk
|
||||
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void*);
|
||||
/** Signature for callback functions passed to nand_driver_walk */
|
||||
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *);
|
||||
/**
|
||||
* Walk the list of drivers, encapsulating the data structure type.
|
||||
* Application state/context can be passed through the @c x pointer.
|
||||
@@ -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);
|
||||
|
||||
#endif // FLASH_NAND_DRIVER_H
|
||||
#endif /* FLASH_NAND_DRIVER_H */
|
||||
|
||||
@@ -125,7 +125,7 @@ static inline int countbits(uint32_t b)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
for (;b; b >>= 1)
|
||||
for (; b; b >>= 1)
|
||||
res += b & 0x01;
|
||||
return res;
|
||||
}
|
||||
@@ -134,7 +134,7 @@ static inline int countbits(uint32_t b)
|
||||
* nand_correct_data - Detect and correct a 1 bit error for 256 byte block
|
||||
*/
|
||||
int nand_correct_data(struct nand_device *nand, u_char *dat,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
uint8_t s0, s1, s2;
|
||||
|
||||
@@ -151,9 +151,9 @@ int nand_correct_data(struct nand_device *nand, u_char *dat,
|
||||
return 0;
|
||||
|
||||
/* Check for a single bit error */
|
||||
if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
|
||||
((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
|
||||
((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
|
||||
if (((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
|
||||
((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
|
||||
((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
|
||||
|
||||
uint32_t byteoffs, bitnum;
|
||||
|
||||
@@ -176,7 +176,7 @@ int nand_correct_data(struct nand_device *nand, u_char *dat,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
|
||||
if (countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 << 16)) == 1)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
* For multiplication, a discrete log/exponent table is used, with
|
||||
* primitive element x (F is a primitive field, so x is primitive).
|
||||
*/
|
||||
#define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */
|
||||
#define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */
|
||||
|
||||
/*
|
||||
* Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in
|
||||
@@ -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;
|
||||
int i;
|
||||
static int tables_initialized = 0;
|
||||
static int tables_initialized;
|
||||
|
||||
if (!tables_initialized) {
|
||||
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];
|
||||
r7 = data[511];
|
||||
|
||||
|
||||
/*
|
||||
* Shift bytes 503..0 (in that order) into r0, followed
|
||||
* by eight zero bytes, while reducing the polynomial by the
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -32,18 +33,21 @@ static struct nand_ecclayout nand_oob_16 = {
|
||||
.eccpos = {0, 1, 2, 3, 6, 7},
|
||||
.oobfree = {
|
||||
{.offset = 8,
|
||||
. length = 8}}
|
||||
.length = 8}
|
||||
}
|
||||
};
|
||||
|
||||
static struct nand_ecclayout nand_oob_64 = {
|
||||
.eccbytes = 24,
|
||||
.eccpos = {
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63},
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63
|
||||
},
|
||||
.oobfree = {
|
||||
{.offset = 2,
|
||||
.length = 38}}
|
||||
.length = 38}
|
||||
}
|
||||
};
|
||||
|
||||
void nand_fileio_init(struct nand_fileio_state *state)
|
||||
@@ -53,45 +57,37 @@ void nand_fileio_init(struct nand_fileio_state *state)
|
||||
}
|
||||
|
||||
int nand_fileio_start(struct command_context *cmd_ctx,
|
||||
struct nand_device *nand, const char *filename, int filemode,
|
||||
struct nand_fileio_state *state)
|
||||
struct nand_device *nand, const char *filename, int filemode,
|
||||
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");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
duration_start(&state->bench);
|
||||
|
||||
if (NULL != filename)
|
||||
{
|
||||
if (NULL != filename) {
|
||||
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";
|
||||
command_print(cmd_ctx, "failed to open '%s' for %s access",
|
||||
filename, msg);
|
||||
filename, msg);
|
||||
return retval;
|
||||
}
|
||||
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 = malloc(nand->page_size);
|
||||
}
|
||||
|
||||
if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
|
||||
{
|
||||
if (nand->page_size == 512)
|
||||
{
|
||||
if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW)) {
|
||||
if (nand->page_size == 512) {
|
||||
state->oob_size = 16;
|
||||
state->eccpos = nand_oob_16.eccpos;
|
||||
}
|
||||
else if (nand->page_size == 2048)
|
||||
{
|
||||
} else if (nand->page_size == 2048) {
|
||||
state->oob_size = 64;
|
||||
state->eccpos = nand_oob_64.eccpos;
|
||||
}
|
||||
@@ -105,13 +101,11 @@ int nand_fileio_cleanup(struct nand_fileio_state *state)
|
||||
if (state->file_opened)
|
||||
fileio_close(&state->fileio);
|
||||
|
||||
if (state->oob)
|
||||
{
|
||||
if (state->oob) {
|
||||
free(state->oob);
|
||||
state->oob = NULL;
|
||||
}
|
||||
if (state->page)
|
||||
{
|
||||
if (state->page) {
|
||||
free(state->page);
|
||||
state->page = NULL;
|
||||
}
|
||||
@@ -124,8 +118,8 @@ int nand_fileio_finish(struct nand_fileio_state *state)
|
||||
}
|
||||
|
||||
COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
||||
struct nand_device **dev, enum fileio_access filemode,
|
||||
bool need_size, bool sw_ecc)
|
||||
struct nand_device **dev, enum fileio_access filemode,
|
||||
bool need_size, bool sw_ecc)
|
||||
{
|
||||
nand_fileio_init(state);
|
||||
|
||||
@@ -138,27 +132,22 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (NULL == nand->device)
|
||||
{
|
||||
if (NULL == nand->device) {
|
||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
|
||||
if (need_size)
|
||||
{
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
|
||||
if (state->size % nand->page_size)
|
||||
{
|
||||
command_print(CMD_CTX, "only page-aligned sizes are supported");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
if (need_size) {
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
|
||||
if (state->size % nand->page_size) {
|
||||
command_print(CMD_CTX, "only page-aligned sizes are supported");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (CMD_ARGC > minargs)
|
||||
{
|
||||
for (unsigned i = minargs; i < CMD_ARGC; i++)
|
||||
{
|
||||
if (CMD_ARGC > minargs) {
|
||||
for (unsigned i = minargs; i < CMD_ARGC; i++) {
|
||||
if (!strcmp(CMD_ARGV[i], "oob_raw"))
|
||||
state->oob_format |= NAND_OOB_RAW;
|
||||
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;
|
||||
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
|
||||
state->oob_format |= NAND_OOB_SW_ECC_KW;
|
||||
else
|
||||
{
|
||||
else {
|
||||
command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
@@ -179,8 +167,7 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (!need_size)
|
||||
{
|
||||
if (!need_size) {
|
||||
int filesize;
|
||||
retval = fileio_size(&state->fileio, &filesize);
|
||||
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 one_read;
|
||||
|
||||
if (NULL != s->page)
|
||||
{
|
||||
if (NULL != s->page) {
|
||||
fileio_read(&s->fileio, s->page_size, s->page, &one_read);
|
||||
if (one_read < s->page_size)
|
||||
memset(s->page + one_read, 0xff, s->page_size - 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];
|
||||
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);
|
||||
s->oob[s->eccpos[j++]] = ecc[0];
|
||||
s->oob[s->eccpos[j++]] = ecc[1];
|
||||
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
|
||||
* 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;
|
||||
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);
|
||||
ecc += 10;
|
||||
}
|
||||
}
|
||||
else if (NULL != s->oob)
|
||||
{
|
||||
} else if (NULL != s->oob) {
|
||||
fileio_read(&s->fileio, s->oob_size, s->oob, &one_read);
|
||||
if (one_read < s->oob_size)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FLASH_NAND_FILEIO_H
|
||||
#define FLASH_NAND_FILEIO_H
|
||||
|
||||
@@ -49,9 +50,9 @@ int nand_fileio_cleanup(struct nand_fileio_state *state);
|
||||
int nand_fileio_finish(struct nand_fileio_state *state);
|
||||
|
||||
COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
||||
struct nand_device **dev, enum fileio_access filemode,
|
||||
bool need_size, bool sw_ecc);
|
||||
struct nand_device **dev, enum fileio_access filemode,
|
||||
bool need_size, bool sw_ecc);
|
||||
|
||||
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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef 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_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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef LPC3180_NAND_CONTROLLER_H
|
||||
#define LPC3180_NAND_CONTROLLER_H
|
||||
|
||||
enum lpc3180_selected_controller
|
||||
{
|
||||
enum lpc3180_selected_controller {
|
||||
LPC3180_NO_CONTROLLER,
|
||||
LPC3180_MLC_CONTROLLER,
|
||||
LPC3180_SLC_CONTROLLER,
|
||||
};
|
||||
|
||||
struct lpc3180_nand_controller
|
||||
{
|
||||
struct lpc3180_nand_controller {
|
||||
int osc_freq;
|
||||
enum lpc3180_selected_controller selected_controller;
|
||||
int is_bulk;
|
||||
@@ -37,4 +36,4 @@ struct lpc3180_nand_controller
|
||||
uint32_t sw_wp_upper_bound;
|
||||
};
|
||||
|
||||
#endif /*LPC3180_NAND_CONTROLLER_H */
|
||||
#endif /*LPC3180_NAND_CONTROLLER_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,18 +17,17 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef LPC32xx_NAND_CONTROLLER_H
|
||||
#define LPC32xx_NAND_CONTROLLER_H
|
||||
|
||||
enum lpc32xx_selected_controller
|
||||
{
|
||||
enum lpc32xx_selected_controller {
|
||||
LPC32xx_NO_CONTROLLER,
|
||||
LPC32xx_MLC_CONTROLLER,
|
||||
LPC32xx_SLC_CONTROLLER,
|
||||
};
|
||||
|
||||
struct lpc32xx_nand_controller
|
||||
{
|
||||
struct lpc32xx_nand_controller {
|
||||
int osc_freq;
|
||||
enum lpc32xx_selected_controller selected_controller;
|
||||
int sw_write_protection;
|
||||
@@ -36,4 +35,4 @@ struct lpc32xx_nand_controller
|
||||
uint32_t sw_wp_upper_bound;
|
||||
};
|
||||
|
||||
#endif /*LPC32xx_NAND_CONTROLLER_H */
|
||||
#endif /*LPC32xx_NAND_CONTROLLER_H */
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
1052
src/flash/nand/mx3.c
1052
src/flash/nand/mx3.c
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Alexei Babich *
|
||||
* Rezonans plc., Chelyabinsk, Russia *
|
||||
@@ -26,80 +25,77 @@
|
||||
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||
*/
|
||||
|
||||
#define MX3_NF_BASE_ADDR 0xb8000000
|
||||
#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00)
|
||||
#define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04)
|
||||
#define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06)
|
||||
#define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08)
|
||||
#define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a)
|
||||
#define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c)
|
||||
#define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e)
|
||||
#define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10)
|
||||
#define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12)
|
||||
#define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14)
|
||||
#define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16)
|
||||
#define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18)
|
||||
/*
|
||||
* all bits not marked as self-clearing bit
|
||||
*/
|
||||
#define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a)
|
||||
#define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c)
|
||||
#define MX3_NF_BASE_ADDR 0xb8000000
|
||||
#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00)
|
||||
#define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04)
|
||||
#define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06)
|
||||
#define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08)
|
||||
#define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a)
|
||||
#define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c)
|
||||
#define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e)
|
||||
#define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10)
|
||||
#define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12)
|
||||
#define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14)
|
||||
#define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16)
|
||||
#define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18)
|
||||
/*
|
||||
* all bits not marked as self-clearing bit
|
||||
*/
|
||||
#define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a)
|
||||
#define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c)
|
||||
|
||||
#define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000)
|
||||
#define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200)
|
||||
#define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400)
|
||||
#define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600)
|
||||
#define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800)
|
||||
#define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810)
|
||||
#define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820)
|
||||
#define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830)
|
||||
#define MX3_NF_MAIN_BUFFER_LEN 512
|
||||
#define MX3_NF_SPARE_BUFFER_LEN 16
|
||||
#define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2)
|
||||
#define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000)
|
||||
#define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200)
|
||||
#define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400)
|
||||
#define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600)
|
||||
#define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800)
|
||||
#define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810)
|
||||
#define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820)
|
||||
#define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830)
|
||||
#define MX3_NF_MAIN_BUFFER_LEN 512
|
||||
#define MX3_NF_SPARE_BUFFER_LEN 16
|
||||
#define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2)
|
||||
|
||||
/* bits in MX3_NF_CFG1 register */
|
||||
#define MX3_NF_BIT_SPARE_ONLY_EN (1<<2)
|
||||
#define MX3_NF_BIT_ECC_EN (1<<3)
|
||||
#define MX3_NF_BIT_INT_DIS (1<<4)
|
||||
#define MX3_NF_BIT_BE_EN (1<<5)
|
||||
#define MX3_NF_BIT_RESET_EN (1<<6)
|
||||
#define MX3_NF_BIT_FORCE_CE (1<<7)
|
||||
#define MX3_NF_BIT_SPARE_ONLY_EN (1<<2)
|
||||
#define MX3_NF_BIT_ECC_EN (1<<3)
|
||||
#define MX3_NF_BIT_INT_DIS (1<<4)
|
||||
#define MX3_NF_BIT_BE_EN (1<<5)
|
||||
#define MX3_NF_BIT_RESET_EN (1<<6)
|
||||
#define MX3_NF_BIT_FORCE_CE (1<<7)
|
||||
|
||||
/* bits in MX3_NF_CFG2 register */
|
||||
|
||||
/*Flash Command Input*/
|
||||
#define MX3_NF_BIT_OP_FCI (1<<0)
|
||||
/*
|
||||
* Flash Address Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FAI (1<<1)
|
||||
/*
|
||||
* Flash Data Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FDI (1<<2)
|
||||
#define MX3_NF_BIT_OP_FCI (1<<0)
|
||||
/*
|
||||
* Flash Address Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FAI (1<<1)
|
||||
/*
|
||||
* Flash Data Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FDI (1<<2)
|
||||
|
||||
/* see "enum mx_dataout_type" below */
|
||||
#define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
||||
#define MX3_NF_BIT_OP_DONE (1<<15)
|
||||
#define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
||||
#define MX3_NF_BIT_OP_DONE (1<<15)
|
||||
|
||||
#define MX3_CCM_CGR2 0x53f80028
|
||||
#define MX3_GPR 0x43fac008
|
||||
#define MX3_PCSR 0x53f8000c
|
||||
#define MX3_CCM_CGR2 0x53f80028
|
||||
#define MX3_GPR 0x43fac008
|
||||
#define MX3_PCSR 0x53f8000c
|
||||
|
||||
enum mx_dataout_type
|
||||
{
|
||||
enum mx_dataout_type {
|
||||
MX3_NF_DATAOUT_PAGE = 1,
|
||||
MX3_NF_DATAOUT_NANDID = 2,
|
||||
MX3_NF_DATAOUT_NANDSTATUS = 4,
|
||||
};
|
||||
enum mx_nf_finalize_action
|
||||
{
|
||||
enum mx_nf_finalize_action {
|
||||
MX3_NF_FIN_NONE,
|
||||
MX3_NF_FIN_DATAOUT,
|
||||
};
|
||||
|
||||
struct mx3_nf_flags
|
||||
{
|
||||
struct mx3_nf_flags {
|
||||
unsigned host_little_endian:1;
|
||||
unsigned target_little_endian:1;
|
||||
unsigned nand_readonly:1;
|
||||
@@ -107,8 +103,7 @@ struct mx3_nf_flags
|
||||
unsigned hw_ecc_enabled:1;
|
||||
};
|
||||
|
||||
struct mx3_nf_controller
|
||||
{
|
||||
struct mx3_nf_controller {
|
||||
enum mx_dataout_type optype;
|
||||
enum mx_nf_finalize_action fin;
|
||||
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 "hello.h"
|
||||
|
||||
|
||||
static int nonce_nand_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
@@ -62,16 +61,15 @@ static int nonce_nand_init(struct nand_device *nand)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct nand_flash_controller nonce_nand_controller =
|
||||
{
|
||||
.name = "nonce",
|
||||
.commands = hello_command_handlers,
|
||||
.nand_device_command = &nonce_nand_device_command,
|
||||
.init = &nonce_nand_init,
|
||||
.reset = &nonce_nand_reset,
|
||||
.command = &nonce_nand_command,
|
||||
.address = &nonce_nand_address,
|
||||
.read_data = &nonce_nand_read,
|
||||
.write_data = &nonce_nand_write,
|
||||
.write_block_data = &nonce_nand_fast_block_write,
|
||||
struct nand_flash_controller nonce_nand_controller = {
|
||||
.name = "nonce",
|
||||
.commands = hello_command_handlers,
|
||||
.nand_device_command = &nonce_nand_device_command,
|
||||
.init = &nonce_nand_init,
|
||||
.reset = &nonce_nand_reset,
|
||||
.command = &nonce_nand_command,
|
||||
.address = &nonce_nand_address,
|
||||
.read_data = &nonce_nand_read,
|
||||
.write_data = &nonce_nand_write,
|
||||
.write_block_data = &nonce_nand_fast_block_write,
|
||||
};
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
#include "arm_io.h"
|
||||
#include <target/arm.h>
|
||||
|
||||
struct nuc910_nand_controller
|
||||
{
|
||||
struct nuc910_nand_controller {
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
nuc910_nand->io.chunk_size = nand->page_size;
|
||||
@@ -154,9 +159,8 @@ static int nuc910_nand_ready(struct nand_device *nand, int timeout)
|
||||
|
||||
do {
|
||||
target_read_u32(target, NUC910_SMISR, &status);
|
||||
if (status & NUC910_SMISR_RB_) {
|
||||
if (status & NUC910_SMISR_RB_)
|
||||
return 1;
|
||||
}
|
||||
alive_sleep(1);
|
||||
} while (timeout-- > 0);
|
||||
|
||||
@@ -184,12 +188,12 @@ static int nuc910_nand_init(struct nand_device *nand)
|
||||
int bus_width = nand->bus_width ? : 8;
|
||||
int result;
|
||||
|
||||
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||
result = validate_target_state(nand);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
/* 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);
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -210,8 +214,7 @@ static int nuc910_nand_init(struct nand_device *nand)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct nand_flash_controller nuc910_nand_controller =
|
||||
{
|
||||
struct nand_flash_controller nuc910_nand_controller = {
|
||||
.name = "nuc910",
|
||||
.command = nuc910_nand_command,
|
||||
.address = nuc910_nand_address,
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
#include "arm_io.h"
|
||||
#include <target/arm.h>
|
||||
|
||||
|
||||
struct orion_nand_controller
|
||||
{
|
||||
struct orion_nand_controller {
|
||||
struct arm_nand_data io;
|
||||
|
||||
uint32_t cmd;
|
||||
@@ -120,10 +118,8 @@ NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
||||
uint32_t base;
|
||||
uint8_t ale, cle;
|
||||
|
||||
if (CMD_ARGC != 3) {
|
||||
LOG_ERROR("arguments must be: <target_id> <NAND_address>");
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
if (CMD_ARGC != 3)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
hw = calloc(1, sizeof(*hw));
|
||||
if (!hw) {
|
||||
@@ -153,16 +149,15 @@ static int orion_nand_init(struct nand_device *nand)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct nand_flash_controller orion_nand_controller =
|
||||
{
|
||||
.name = "orion",
|
||||
.command = orion_nand_command,
|
||||
.address = orion_nand_address,
|
||||
.read_data = orion_nand_read,
|
||||
.write_data = orion_nand_write,
|
||||
.write_block_data = orion_nand_fast_block_write,
|
||||
.reset = orion_nand_reset,
|
||||
.nand_device_command = orion_nand_device_command,
|
||||
.init = orion_nand_init,
|
||||
struct nand_flash_controller orion_nand_controller = {
|
||||
.name = "orion",
|
||||
.usage = "<target_id> <NAND_address>",
|
||||
.command = orion_nand_command,
|
||||
.address = orion_nand_address,
|
||||
.read_data = orion_nand_read,
|
||||
.write_data = orion_nand_write,
|
||||
.write_block_data = orion_nand_fast_block_write,
|
||||
.reset = orion_nand_reset,
|
||||
.nand_device_command = orion_nand_device_command,
|
||||
.init = orion_nand_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -104,15 +104,15 @@ static int s3c2410_nand_ready(struct nand_device *nand, int timeout)
|
||||
}
|
||||
|
||||
struct nand_flash_controller s3c2410_nand_controller = {
|
||||
.name = "s3c2410",
|
||||
.nand_device_command = &s3c2410_nand_device_command,
|
||||
.init = &s3c2410_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c2410_write_data,
|
||||
.read_data = &s3c2410_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.nand_ready = &s3c2410_nand_ready,
|
||||
};
|
||||
.name = "s3c2410",
|
||||
.nand_device_command = &s3c2410_nand_device_command,
|
||||
.init = &s3c2410_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c2410_write_data,
|
||||
.read_data = &s3c2410_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.nand_ready = &s3c2410_nand_ready,
|
||||
};
|
||||
|
||||
@@ -61,17 +61,17 @@ static int s3c2412_init(struct nand_device *nand)
|
||||
}
|
||||
|
||||
struct nand_flash_controller s3c2412_nand_controller = {
|
||||
.name = "s3c2412",
|
||||
.nand_device_command = &s3c2412_nand_device_command,
|
||||
.init = &s3c2412_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
.name = "s3c2412",
|
||||
.nand_device_command = &s3c2412_nand_device_command,
|
||||
.init = &s3c2412_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command)
|
||||
{
|
||||
struct s3c24xx_nand_controller *info;
|
||||
@@ -153,17 +152,17 @@ int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_s
|
||||
}
|
||||
|
||||
struct nand_flash_controller s3c2440_nand_controller = {
|
||||
.name = "s3c2440",
|
||||
.nand_device_command = &s3c2440_nand_device_command,
|
||||
.init = &s3c2440_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
.name = "s3c2440",
|
||||
.nand_device_command = &s3c2440_nand_device_command,
|
||||
.init = &s3c2440_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command)
|
||||
{
|
||||
struct s3c24xx_nand_controller *info;
|
||||
@@ -62,17 +61,17 @@ static int s3c2443_init(struct nand_device *nand)
|
||||
}
|
||||
|
||||
struct nand_flash_controller s3c2443_nand_controller = {
|
||||
.name = "s3c2443",
|
||||
.nand_device_command = &s3c2443_nand_device_command,
|
||||
.init = &s3c2443_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
.name = "s3c2443",
|
||||
.nand_device_command = &s3c2443_nand_device_command,
|
||||
.init = &s3c2443_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
S3C24XX_DEVICE_COMMAND()
|
||||
{
|
||||
*info = NULL;
|
||||
@@ -77,7 +76,6 @@ int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
#include "s3c24xx_regs.h"
|
||||
#include <target/target.h>
|
||||
|
||||
struct s3c24xx_nand_controller
|
||||
{
|
||||
struct s3c24xx_nand_controller {
|
||||
/* register addresses */
|
||||
uint32_t cmd;
|
||||
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,
|
||||
uint8_t *data, int data_size);
|
||||
|
||||
#endif // S3C24xx_NAND_H
|
||||
#endif /* S3C24xx_NAND_H */
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
@@ -58,17 +58,17 @@ static int s3c6400_init(struct nand_device *nand)
|
||||
}
|
||||
|
||||
struct nand_flash_controller s3c6400_nand_controller = {
|
||||
.name = "s3c6400",
|
||||
.nand_device_command = &s3c6400_nand_device_command,
|
||||
.init = &s3c6400_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
.name = "s3c6400",
|
||||
.nand_device_command = &s3c6400_nand_device_command,
|
||||
.init = &s3c6400_init,
|
||||
.reset = &s3c24xx_reset,
|
||||
.command = &s3c24xx_command,
|
||||
.address = &s3c24xx_address,
|
||||
.write_data = &s3c24xx_write_data,
|
||||
.read_data = &s3c24xx_read_data,
|
||||
.write_page = s3c24xx_write_page,
|
||||
.read_page = s3c24xx_read_page,
|
||||
.write_block_data = &s3c2440_write_block_data,
|
||||
.read_block_data = &s3c2440_read_block_data,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -29,7 +30,7 @@
|
||||
#include "fileio.h"
|
||||
#include <target/target.h>
|
||||
|
||||
// to be removed
|
||||
/* to be removed */
|
||||
extern struct nand_device *nand_devices;
|
||||
|
||||
COMMAND_HANDLER(handle_nand_list_command)
|
||||
@@ -37,14 +38,12 @@ COMMAND_HANDLER(handle_nand_list_command)
|
||||
struct nand_device *p;
|
||||
int i;
|
||||
|
||||
if (!nand_devices)
|
||||
{
|
||||
if (!nand_devices) {
|
||||
command_print(CMD_CTX, "no NAND flash devices configured");
|
||||
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)
|
||||
command_print(CMD_CTX, "#%i: %s (%s) "
|
||||
"pagesize: %i, buswidth: %i,\n\t"
|
||||
@@ -67,21 +66,21 @@ COMMAND_HANDLER(handle_nand_info_command)
|
||||
int last = -1;
|
||||
|
||||
switch (CMD_ARGC) {
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
case 1:
|
||||
first = 0;
|
||||
last = INT32_MAX;
|
||||
break;
|
||||
case 2:
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i);
|
||||
first = last = i;
|
||||
i = 0;
|
||||
break;
|
||||
case 3:
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
case 1:
|
||||
first = 0;
|
||||
last = INT32_MAX;
|
||||
break;
|
||||
case 2:
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i);
|
||||
first = last = i;
|
||||
i = 0;
|
||||
break;
|
||||
case 3:
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
|
||||
break;
|
||||
}
|
||||
|
||||
struct nand_device *p;
|
||||
@@ -89,8 +88,7 @@ COMMAND_HANDLER(handle_nand_info_command)
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (NULL == p->device)
|
||||
{
|
||||
if (NULL == p->device) {
|
||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -101,11 +99,16 @@ COMMAND_HANDLER(handle_nand_info_command)
|
||||
if (last >= p->num_blocks)
|
||||
last = p->num_blocks - 1;
|
||||
|
||||
command_print(CMD_CTX, "#%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);
|
||||
command_print(CMD_CTX,
|
||||
"#%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;
|
||||
|
||||
if (p->blocks[j].is_erased == 0)
|
||||
@@ -123,12 +126,12 @@ COMMAND_HANDLER(handle_nand_info_command)
|
||||
bad_state = " (block condition unknown)";
|
||||
|
||||
command_print(CMD_CTX,
|
||||
"\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
|
||||
j,
|
||||
p->blocks[j].offset,
|
||||
p->blocks[j].size / 1024,
|
||||
erase_state,
|
||||
bad_state);
|
||||
"\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
|
||||
j,
|
||||
p->blocks[j].offset,
|
||||
p->blocks[j].size / 1024,
|
||||
erase_state,
|
||||
bad_state);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -137,19 +140,17 @@ COMMAND_HANDLER(handle_nand_info_command)
|
||||
COMMAND_HANDLER(handle_nand_probe_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
struct nand_device *p;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||
if (ERROR_OK != 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",
|
||||
p->device->name, p->manufacturer->name);
|
||||
p->device->name, p->manufacturer->name);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -158,11 +159,8 @@ COMMAND_HANDLER(handle_nand_probe_command)
|
||||
COMMAND_HANDLER(handle_nand_erase_command)
|
||||
{
|
||||
if (CMD_ARGC != 1 && CMD_ARGC != 3)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
}
|
||||
|
||||
struct nand_device *p;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||
if (ERROR_OK != retval)
|
||||
@@ -177,12 +175,12 @@ COMMAND_HANDLER(handle_nand_erase_command)
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||
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);
|
||||
if ((length == 0) || (length % p->erase_size) != 0
|
||||
|| (length + offset) > size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|| (length + offset) > size)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
offset /= p->erase_size;
|
||||
length /= p->erase_size;
|
||||
@@ -192,12 +190,11 @@ COMMAND_HANDLER(handle_nand_erase_command)
|
||||
}
|
||||
|
||||
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 "
|
||||
"on NAND flash device #%s '%s'",
|
||||
offset, offset + length,
|
||||
CMD_ARGV[0], p->device->name);
|
||||
"on NAND flash device #%s '%s'",
|
||||
offset, offset + length - 1,
|
||||
CMD_ARGV[0], p->device->name);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -209,29 +206,25 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
||||
int last = -1;
|
||||
|
||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2))
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
}
|
||||
|
||||
struct nand_device *p;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (CMD_ARGC == 3)
|
||||
{
|
||||
if (CMD_ARGC == 3) {
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||
if (offset % p->erase_size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
offset /= p->erase_size;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
||||
if (length % p->erase_size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
length -= 1;
|
||||
length /= p->erase_size;
|
||||
@@ -241,10 +234,9 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
||||
}
|
||||
|
||||
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, "
|
||||
"use \"nand info\" command to list blocks");
|
||||
"use \"nand info\" command to list blocks");
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -260,11 +252,9 @@ COMMAND_HANDLER(handle_nand_write_command)
|
||||
return retval;
|
||||
|
||||
uint32_t total_bytes = s.size;
|
||||
while (s.size > 0)
|
||||
{
|
||||
while (s.size > 0) {
|
||||
int bytes_read = nand_fileio_read(nand, &s);
|
||||
if (bytes_read <= 0)
|
||||
{
|
||||
if (bytes_read <= 0) {
|
||||
command_print(CMD_CTX, "error while reading file");
|
||||
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,
|
||||
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 "
|
||||
"to NAND flash %s at offset 0x%8.8" PRIx32,
|
||||
CMD_ARGV[1], CMD_ARGV[0], s.address);
|
||||
@@ -282,12 +271,11 @@ COMMAND_HANDLER(handle_nand_write_command)
|
||||
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 "
|
||||
"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, total_bytes));
|
||||
"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, total_bytes));
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -310,12 +298,10 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
while (file.size > 0)
|
||||
{
|
||||
while (file.size > 0) {
|
||||
retval = nand_read_page(nand, dev.address / dev.page_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");
|
||||
nand_fileio_cleanup(&dev);
|
||||
nand_fileio_cleanup(&file);
|
||||
@@ -323,8 +309,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
||||
}
|
||||
|
||||
int bytes_read = nand_fileio_read(nand, &file);
|
||||
if (bytes_read <= 0)
|
||||
{
|
||||
if (bytes_read <= 0) {
|
||||
command_print(CMD_CTX, "error while reading file");
|
||||
nand_fileio_cleanup(&dev);
|
||||
nand_fileio_cleanup(&file);
|
||||
@@ -332,10 +317,9 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
||||
}
|
||||
|
||||
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 "
|
||||
"at 0x%8.8" PRIx32, dev.address);
|
||||
"at 0x%8.8" PRIx32, dev.address);
|
||||
nand_fileio_cleanup(&dev);
|
||||
nand_fileio_cleanup(&file);
|
||||
return ERROR_FAIL;
|
||||
@@ -345,12 +329,11 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
||||
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 "
|
||||
"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),
|
||||
duration_kbps(&file.bench, dev.size));
|
||||
"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),
|
||||
duration_kbps(&file.bench, dev.size));
|
||||
}
|
||||
|
||||
return nand_fileio_cleanup(&dev);
|
||||
@@ -366,13 +349,11 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
while (s.size > 0)
|
||||
{
|
||||
while (s.size > 0) {
|
||||
size_t size_written;
|
||||
retval = nand_read_page(nand, s.address / nand->page_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");
|
||||
nand_fileio_cleanup(&s);
|
||||
return retval;
|
||||
@@ -392,11 +373,10 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
||||
if (retval != ERROR_OK)
|
||||
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)",
|
||||
(long)filesize, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, filesize));
|
||||
(long)filesize, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, filesize));
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -404,17 +384,14 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
||||
COMMAND_HANDLER(handle_nand_raw_access_command)
|
||||
{
|
||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
struct nand_device *p;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (NULL == p->device)
|
||||
{
|
||||
if (NULL == p->device) {
|
||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -510,9 +487,8 @@ COMMAND_HANDLER(handle_nand_init_command)
|
||||
if (CMD_ARGC != 0)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
static bool nand_initialized = false;
|
||||
if (nand_initialized)
|
||||
{
|
||||
static bool nand_initialized;
|
||||
if (nand_initialized) {
|
||||
LOG_INFO("'nand init' has already been called");
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -536,33 +512,28 @@ COMMAND_HANDLER(handle_nand_list_drivers)
|
||||
}
|
||||
|
||||
static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
||||
struct nand_flash_controller *controller)
|
||||
struct nand_flash_controller *controller)
|
||||
{
|
||||
struct nand_device *c;
|
||||
struct target *target;
|
||||
int retval;
|
||||
|
||||
if (CMD_ARGC < 2)
|
||||
{
|
||||
LOG_ERROR("missing target");
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
target = get_target(CMD_ARGV[1]);
|
||||
if (!target) {
|
||||
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
if (NULL != controller->commands)
|
||||
{
|
||||
if (NULL != controller->commands) {
|
||||
retval = register_commands(CMD_CTX, NULL,
|
||||
controller->commands);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
c = malloc(sizeof(struct nand_device));
|
||||
if (c == NULL)
|
||||
{
|
||||
if (c == NULL) {
|
||||
LOG_ERROR("End of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -580,13 +551,17 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
||||
c->next = NULL;
|
||||
|
||||
retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
||||
if (ERROR_OK != retval)
|
||||
{
|
||||
LOG_ERROR("'%s' driver rejected nand flash", controller->name);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("'%s' driver rejected nand flash. Usage: %s",
|
||||
controller->name,
|
||||
controller->usage);
|
||||
free(c);
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (controller->usage == NULL)
|
||||
LOG_DEBUG("'%s' driver usage field missing", controller->name);
|
||||
|
||||
nand_device_add(c);
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -595,20 +570,16 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
||||
COMMAND_HANDLER(handle_nand_device_command)
|
||||
{
|
||||
if (CMD_ARGC < 2)
|
||||
{
|
||||
LOG_ERROR("incomplete nand device configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
// save name and increment (for compatibility) with drivers
|
||||
/* save name and increment (for compatibility) with drivers */
|
||||
const char *bank_name = *CMD_ARGV++;
|
||||
CMD_ARGC--;
|
||||
|
||||
const char *driver_name = CMD_ARGV[0];
|
||||
struct nand_flash_controller *controller;
|
||||
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);
|
||||
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,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "lists available NAND drivers",
|
||||
.usage = ""
|
||||
},
|
||||
{
|
||||
.name = "init",
|
||||
.mode = COMMAND_CONFIG,
|
||||
.handler = &handle_nand_init_command,
|
||||
.help = "initialize NAND devices",
|
||||
.usage = ""
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration nand_command_handlers[] = {
|
||||
{
|
||||
.name = "nand",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "NAND flash command group",
|
||||
.usage = "",
|
||||
.chain = nand_config_command_handlers,
|
||||
},
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ libocdflashnor_la_SOURCES = \
|
||||
|
||||
NOR_DRIVERS = \
|
||||
aduc702x.c \
|
||||
at91sam4.c \
|
||||
at91sam3.c \
|
||||
at91sam7.c \
|
||||
avrf.c \
|
||||
cfi.c \
|
||||
ecos.c \
|
||||
em357.c \
|
||||
faux.c \
|
||||
lpc2000.c \
|
||||
@@ -24,14 +24,17 @@ NOR_DRIVERS = \
|
||||
pic32mx.c \
|
||||
stmsmi.c \
|
||||
stellaris.c \
|
||||
stm32x.c \
|
||||
stm32f2xxx.c \
|
||||
stm32f1x.c \
|
||||
stm32f2x.c \
|
||||
stm32lx.c \
|
||||
str7x.c \
|
||||
str9x.c \
|
||||
str9xpec.c \
|
||||
tms470.c \
|
||||
virtual.c \
|
||||
fm3.c \
|
||||
dsp5680xx_flash.c \
|
||||
virtual.c
|
||||
kinetis.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
core.h \
|
||||
|
||||
@@ -29,20 +29,19 @@
|
||||
#include <target/algorithm.h>
|
||||
#include <target/arm.h>
|
||||
|
||||
|
||||
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);
|
||||
|
||||
#define ADUC702x_FLASH 0xfffff800
|
||||
#define ADUC702x_FLASH_FEESTA (0*4)
|
||||
#define ADUC702x_FLASH_FEEMOD (1*4)
|
||||
#define ADUC702x_FLASH_FEECON (2*4)
|
||||
#define ADUC702x_FLASH_FEEDAT (3*4)
|
||||
#define ADUC702x_FLASH_FEEADR (4*4)
|
||||
#define ADUC702x_FLASH_FEESIGN (5*4)
|
||||
#define ADUC702x_FLASH_FEEPRO (6*4)
|
||||
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
||||
#define ADUC702x_FLASH 0xfffff800
|
||||
#define ADUC702x_FLASH_FEESTA (0*4)
|
||||
#define ADUC702x_FLASH_FEEMOD (1*4)
|
||||
#define ADUC702x_FLASH_FEECON (2*4)
|
||||
#define ADUC702x_FLASH_FEEDAT (3*4)
|
||||
#define ADUC702x_FLASH_FEEADR (4*4)
|
||||
#define ADUC702x_FLASH_FEESIGN (5*4)
|
||||
#define ADUC702x_FLASH_FEEPRO (6*4)
|
||||
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
||||
|
||||
struct aduc702x_flash_bank {
|
||||
struct working_area *write_algorithm;
|
||||
@@ -56,33 +55,32 @@ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
||||
|
||||
nbank = malloc(sizeof(struct aduc702x_flash_bank));
|
||||
|
||||
bank->base = 0x80000;
|
||||
bank->size = 0xF800; // top 4k not accessible
|
||||
bank->base = 0x80000;
|
||||
bank->size = 0xF800; /* top 4k not accessible */
|
||||
bank->driver_priv = nbank;
|
||||
|
||||
aduc702x_build_sector_list(bank);
|
||||
aduc702x_build_sector_list(bank);
|
||||
|
||||
return ERROR_OK;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t offset = 0;
|
||||
int i = 0;
|
||||
uint32_t offset = 0;
|
||||
|
||||
// sector size is 512
|
||||
bank->num_sectors = bank->size / 512;
|
||||
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 = 512;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
/* sector size is 512 */
|
||||
bank->num_sectors = bank->size / 512;
|
||||
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 = 512;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -95,13 +93,13 @@ static int aduc702x_protect_check(struct flash_bank *bank)
|
||||
|
||||
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
//int res;
|
||||
/* int res; */
|
||||
int x;
|
||||
int count;
|
||||
//uint32_t v;
|
||||
/* uint32_t v; */
|
||||
struct target *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
|
||||
/* mass erase */
|
||||
if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
|
||||
@@ -110,38 +108,35 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
|
||||
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");
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("mass erase successful.");
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
unsigned long adr;
|
||||
unsigned long adr;
|
||||
|
||||
count = last - first + 1;
|
||||
for (x = 0; x < count; ++x)
|
||||
{
|
||||
adr = bank->base + ((first + x) * 512);
|
||||
count = last - first + 1;
|
||||
for (x = 0; x < count; ++x) {
|
||||
adr = bank->base + ((first + x) * 512);
|
||||
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
|
||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr);
|
||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05);
|
||||
|
||||
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||
}
|
||||
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) {
|
||||
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("erased sector at address 0x%08lX", adr);
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("erased sector at address 0x%08lX", adr);
|
||||
}
|
||||
}
|
||||
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int aduc702x_write_block(struct flash_bank *bank,
|
||||
uint8_t *buffer,
|
||||
uint32_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
@@ -165,74 +163,69 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
struct reg_param reg_params[6];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
struct arm_algorithm arm_algo;
|
||||
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");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* parameters:
|
||||
/* parameters:
|
||||
|
||||
r0 - address of source data (absolute)
|
||||
r1 - number of halfwords to be copied
|
||||
r2 - start address in flash (offset from beginning of flash memory)
|
||||
r3 - exit code
|
||||
r4 - base address of flash controller (0xFFFFF800)
|
||||
r0 - address of source data (absolute)
|
||||
r1 - number of halfwords to be copied
|
||||
r2 - start address in flash (offset from beginning of flash memory)
|
||||
r3 - exit code
|
||||
r4 - base address of flash controller (0xFFFFF800)
|
||||
|
||||
registers:
|
||||
registers:
|
||||
|
||||
r5 - scratch
|
||||
r6 - set to 2, used to write flash command
|
||||
r5 - scratch
|
||||
r6 - set to 2, used to write flash command
|
||||
|
||||
*/
|
||||
static const uint32_t aduc702x_flash_write_code[] = {
|
||||
//<_start>:
|
||||
0xe3a05008, // mov r5, #8 ; 0x8
|
||||
0xe5845004, // str r5, [r4, #4]
|
||||
0xe3a06002, // mov r6, #2 ; 0x2
|
||||
//<next>:
|
||||
0xe1c421b0, // strh r2, [r4, #16]
|
||||
0xe0d050b2, // ldrh r5, [r0], #2
|
||||
0xe1c450bc, // strh r5, [r4, #12]
|
||||
0xe5c46008, // strb r6, [r4, #8]
|
||||
//<wait_complete>:
|
||||
0xe1d430b0, // ldrh r3, [r4]
|
||||
0xe3130004, // tst r3, #4 ; 0x4
|
||||
0x1afffffc, // bne 1001c <wait_complete>
|
||||
0xe2822002, // add r2, r2, #2 ; 0x2
|
||||
0xe2511001, // subs r1, r1, #1 ; 0x1
|
||||
0x0a000001, // beq 1003c <done>
|
||||
0xe3130001, // tst r3, #1 ; 0x1
|
||||
0x1afffff3, // bne 1000c <next>
|
||||
//<done>:
|
||||
0xeafffffe // b 1003c <done>
|
||||
*/
|
||||
static const uint32_t aduc702x_flash_write_code[] = {
|
||||
/* <_start>: */
|
||||
0xe3a05008, /* mov r5, #8 ; 0x8 */
|
||||
0xe5845004, /* str r5, [r4, #4] */
|
||||
0xe3a06002, /* mov r6, #2 ; 0x2 */
|
||||
/* <next>: */
|
||||
0xe1c421b0, /* strh r2, [r4, #16] */
|
||||
0xe0d050b2, /* ldrh r5, [r0], #2 */
|
||||
0xe1c450bc, /* strh r5, [r4, #12] */
|
||||
0xe5c46008, /* strb r6, [r4, #8] */
|
||||
/* <wait_complete>: */
|
||||
0xe1d430b0, /* ldrh r3, [r4] */
|
||||
0xe3130004, /* tst r3, #4 ; 0x4 */
|
||||
0x1afffffc, /* bne 1001c <wait_complete> */
|
||||
0xe2822002, /* add r2, r2, #2 ; 0x2 */
|
||||
0xe2511001, /* subs r1, r1, #1 ; 0x1 */
|
||||
0x0a000001, /* beq 1003c <done> */
|
||||
0xe3130001, /* tst r3, #1 ; 0x1 */
|
||||
0x1afffff3, /* bne 1000c <next> */
|
||||
/* <done>: */
|
||||
0xeafffffe /* b 1003c <done> */
|
||||
};
|
||||
|
||||
/* 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");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
|
||||
retval=target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
||||
sizeof(aduc702x_flash_write_code), (uint8_t*)aduc702x_flash_write_code);
|
||||
if (retval!=ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
||||
sizeof(aduc702x_flash_write_code), (uint8_t *)aduc702x_flash_write_code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* 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;
|
||||
if (buffer_size <= 256)
|
||||
{
|
||||
/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
|
||||
if (buffer_size <= 256) {
|
||||
/* if we already allocated the writing code, but failed to get a buffer,
|
||||
*free the algorithm */
|
||||
if (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;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
arm_algo.common_magic = ARM_COMMON_MAGIC;
|
||||
arm_algo.core_mode = ARM_MODE_SVC;
|
||||
arm_algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 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[4], "r4", 32, PARAM_OUT);
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
while (count > 0) {
|
||||
uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
|
||||
|
||||
retval=target_write_buffer(target, source->address, thisrun_count, buffer);
|
||||
if (retval!=ERROR_OK)
|
||||
{
|
||||
retval = target_write_buffer(target, source->address, thisrun_count, 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, thisrun_count/2);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);
|
||||
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 5,
|
||||
reg_params, aduc702x_info->write_algorithm->address,
|
||||
aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
|
||||
10000, &armv4_5_info)) != ERROR_OK)
|
||||
{
|
||||
retval = target_run_algorithm(target, 0, NULL, 5,
|
||||
reg_params, aduc702x_info->write_algorithm->address,
|
||||
aduc702x_info->write_algorithm->address +
|
||||
sizeof(aduc702x_flash_write_code) - 4,
|
||||
10000, &arm_algo);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("error executing aduc702x flash write algorithm");
|
||||
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 */
|
||||
LOG_ERROR("aduc702x detected error writing flash");
|
||||
retval = ERROR_FAIL;
|
||||
@@ -302,43 +292,44 @@ 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
|
||||
* 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;
|
||||
uint8_t b;
|
||||
uint8_t b;
|
||||
struct target *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
|
||||
for (x = 0; x < count; x += 2) {
|
||||
// FEEADR = address
|
||||
/* FEEADR = address */
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x);
|
||||
|
||||
// set up data
|
||||
if ((x + 1) == count)
|
||||
{
|
||||
// last byte
|
||||
target_read_u8(target, offset + x + 1, &b);
|
||||
}
|
||||
else
|
||||
b = buffer[x + 1];
|
||||
/* set up data */
|
||||
if ((x + 1) == count) {
|
||||
/* last byte */
|
||||
target_read_u8(target, offset + x + 1, &b);
|
||||
} else
|
||||
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);
|
||||
|
||||
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x));
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) {
|
||||
LOG_ERROR("single write failed for address 0x%08lX",
|
||||
(unsigned long)(offset + x));
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x));
|
||||
LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x));
|
||||
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
aduc702x_set_write_enable(target, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -347,24 +338,23 @@ static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* try using a block write */
|
||||
if ((retval = aduc702x_write_block(bank, buffer, offset, count)) != ERROR_OK)
|
||||
{
|
||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
||||
{
|
||||
/* if block write failed (no sufficient working area),
|
||||
* use normal (slow) JTAG method */
|
||||
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
||||
/* try using a block write */
|
||||
retval = aduc702x_write_block(bank, buffer, offset, count);
|
||||
if (retval != ERROR_OK) {
|
||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
|
||||
/* if block write failed (no sufficient working area),
|
||||
* use normal (slow) JTAG method */
|
||||
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
||||
|
||||
if ((retval = aduc702x_write_single(bank, buffer, offset, count)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("slow write failed");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = aduc702x_write_single(bank, buffer, offset, count);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("slow write failed");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int aduc702x_probe(struct flash_bank *bank)
|
||||
@@ -382,10 +372,10 @@ static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
* enable = 1 enables writes & erases, 0 disables them */
|
||||
static int aduc702x_set_write_enable(struct target *target, int enable)
|
||||
{
|
||||
// don't bother to preserve int enable bit here
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
|
||||
/* don't bother to preserve int enable bit here */
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
|
||||
|
||||
return ERROR_OK;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* wait up to timeout_ms for controller to not be busy,
|
||||
@@ -393,22 +383,27 @@ static int aduc702x_set_write_enable(struct target *target, int enable)
|
||||
*
|
||||
* this function sleeps 1ms between checks (after the first one),
|
||||
* so in some cases may slow things down without a usleep after the first read */
|
||||
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)
|
||||
{
|
||||
uint8_t v = 4;
|
||||
uint8_t v = 4;
|
||||
|
||||
long long endtime = timeval_ms() + timeout_ms;
|
||||
while (1) {
|
||||
target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v);
|
||||
if ((v & 4) == 0) break;
|
||||
alive_sleep(1);
|
||||
if (timeval_ms() >= endtime) break;
|
||||
}
|
||||
long long endtime = timeval_ms() + timeout_ms;
|
||||
while (1) {
|
||||
target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v);
|
||||
if ((v & 4) == 0)
|
||||
break;
|
||||
alive_sleep(1);
|
||||
if (timeval_ms() >= endtime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (v & 2) return ERROR_FAIL;
|
||||
// if a command is ignored, both the success and fail bits may be 0
|
||||
else if ((v & 3) == 0) return ERROR_FAIL;
|
||||
else return ERROR_OK;
|
||||
if (v & 2)
|
||||
return ERROR_FAIL;
|
||||
/* if a command is ignored, both the success and fail bits may be 0 */
|
||||
else if ((v & 3) == 0)
|
||||
return ERROR_FAIL;
|
||||
else
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -24,33 +25,31 @@
|
||||
#include "imp.h"
|
||||
#include <target/avrt.h>
|
||||
|
||||
|
||||
/* AVR_JTAG_Instructions */
|
||||
#define AVR_JTAG_INS_LEN 4
|
||||
// Public Instructions:
|
||||
#define AVR_JTAG_INS_EXTEST 0x00
|
||||
#define AVR_JTAG_INS_IDCODE 0x01
|
||||
#define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02
|
||||
#define AVR_JTAG_INS_BYPASS 0x0F
|
||||
// AVR Specified Public Instructions:
|
||||
#define AVR_JTAG_INS_AVR_RESET 0x0C
|
||||
#define AVR_JTAG_INS_PROG_ENABLE 0x04
|
||||
#define AVR_JTAG_INS_PROG_COMMANDS 0x05
|
||||
#define AVR_JTAG_INS_PROG_PAGELOAD 0x06
|
||||
#define AVR_JTAG_INS_PROG_PAGEREAD 0x07
|
||||
#define AVR_JTAG_INS_LEN 4
|
||||
/* Public Instructions: */
|
||||
#define AVR_JTAG_INS_EXTEST 0x00
|
||||
#define AVR_JTAG_INS_IDCODE 0x01
|
||||
#define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02
|
||||
#define AVR_JTAG_INS_BYPASS 0x0F
|
||||
/* AVR Specified Public Instructions: */
|
||||
#define AVR_JTAG_INS_AVR_RESET 0x0C
|
||||
#define AVR_JTAG_INS_PROG_ENABLE 0x04
|
||||
#define AVR_JTAG_INS_PROG_COMMANDS 0x05
|
||||
#define AVR_JTAG_INS_PROG_PAGELOAD 0x06
|
||||
#define AVR_JTAG_INS_PROG_PAGEREAD 0x07
|
||||
|
||||
// Data Registers:
|
||||
#define AVR_JTAG_REG_Bypass_Len 1
|
||||
#define AVR_JTAG_REG_DeviceID_Len 32
|
||||
/* Data Registers: */
|
||||
#define AVR_JTAG_REG_Bypass_Len 1
|
||||
#define AVR_JTAG_REG_DeviceID_Len 32
|
||||
|
||||
#define AVR_JTAG_REG_Reset_Len 1
|
||||
#define AVR_JTAG_REG_JTAGID_Len 32
|
||||
#define AVR_JTAG_REG_ProgrammingEnable_Len 16
|
||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||
#define AVR_JTAG_REG_Reset_Len 1
|
||||
#define AVR_JTAG_REG_JTAGID_Len 32
|
||||
#define AVR_JTAG_REG_ProgrammingEnable_Len 16
|
||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||
|
||||
struct avrf_type
|
||||
{
|
||||
struct avrf_type {
|
||||
char name[15];
|
||||
uint16_t chip_id;
|
||||
int flash_page_size;
|
||||
@@ -59,26 +58,24 @@ struct avrf_type
|
||||
int eeprom_page_num;
|
||||
};
|
||||
|
||||
struct avrf_flash_bank
|
||||
{
|
||||
struct avrf_flash_bank {
|
||||
int ppage_size;
|
||||
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,
|
||||
* eeprom_page_size, eeprom_page_num
|
||||
*/
|
||||
{"atmega128", 0x9702, 256, 512, 8, 512},
|
||||
{"at90can128", 0x9781, 256, 512, 8, 512},
|
||||
{"atmega128", 0x9702, 256, 512, 8, 512},
|
||||
{"at90can128", 0x9781, 256, 512, 8, 512},
|
||||
};
|
||||
|
||||
/* avr program functions */
|
||||
static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, reset ,AVR_JTAG_REG_Reset_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, reset, AVR_JTAG_REG_Reset_Len);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -127,42 +124,48 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
|
||||
|
||||
do {
|
||||
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())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||
} while (!(poll_value & 0x0200));
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
// load addr high byte
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
/* load addr high byte */
|
||||
avr_jtag_senddat(avr->jtag_info.tap,
|
||||
NULL,
|
||||
0x0700 | ((addr >> 9) & 0xFF),
|
||||
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
// load addr low byte
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
/* load addr low byte */
|
||||
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);
|
||||
|
||||
for (i = 0; i < page_size; i++)
|
||||
{
|
||||
for (i = 0; i < page_size; i++) {
|
||||
if (i < buf_size)
|
||||
{
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||
} while (!(poll_value & 0x0200));
|
||||
|
||||
@@ -190,10 +194,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
|
||||
struct avrf_flash_bank *avrf_info;
|
||||
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank avr configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
avrf_info = malloc(sizeof(struct avrf_flash_bank));
|
||||
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;
|
||||
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");
|
||||
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)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
LOG_INFO("%s", __func__);
|
||||
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;
|
||||
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");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
page_size = bank->sectors[0].size;
|
||||
if ((offset % page_size) != 0)
|
||||
{
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size);
|
||||
if ((offset % page_size) != 0) {
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
|
||||
offset,
|
||||
page_size);
|
||||
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);
|
||||
|
||||
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
cur_size = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
while (count > 0) {
|
||||
if (count > page_size)
|
||||
{
|
||||
cur_buffer_size = page_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_buffer_size = count;
|
||||
}
|
||||
avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size);
|
||||
avr_jtagprg_writeflashpage(avr,
|
||||
buffer + cur_size,
|
||||
cur_buffer_size,
|
||||
offset + cur_size,
|
||||
page_size);
|
||||
count -= 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_PART(X) (((X) & 0xffff000) >> 12)
|
||||
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
|
||||
|
||||
static int avrf_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
@@ -294,8 +292,7 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_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);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||
{
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected",
|
||||
EXTRACT_MFG(device_id),
|
||||
0x1F);
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||
avr_info = &avft_chips_info[i];
|
||||
LOG_INFO("target device is %s", avr_info->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (avr_info != NULL)
|
||||
{
|
||||
if (bank->sectors)
|
||||
{
|
||||
if (avr_info != NULL) {
|
||||
if (bank->sectors) {
|
||||
free(bank->sectors);
|
||||
bank->sectors = NULL;
|
||||
}
|
||||
|
||||
// chip found
|
||||
/* chip found */
|
||||
bank->base = 0x00000000;
|
||||
bank->size = (avr_info->flash_page_size * 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);
|
||||
|
||||
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].size = avr_info->flash_page_size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
@@ -348,10 +338,8 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
|
||||
avrf_info->probed = 1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// chip not supported
|
||||
} else {
|
||||
/* chip not supported */
|
||||
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
|
||||
|
||||
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)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
LOG_INFO("%s", __func__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -381,28 +369,23 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
avr_jtag_read_jtagid(avr, &device_id);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||
{
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected",
|
||||
EXTRACT_MFG(device_id),
|
||||
0x1F);
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||
avr_info = &avft_chips_info[i];
|
||||
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)
|
||||
{
|
||||
// chip found
|
||||
snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id));
|
||||
if (avr_info != NULL) {
|
||||
/* chip found */
|
||||
snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name,
|
||||
EXTRACT_VER(device_id));
|
||||
return ERROR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// chip not supported
|
||||
} else {
|
||||
/* chip not supported */
|
||||
snprintf(buf, buf_size, "Cannot identify target as a avr\n");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
@@ -429,18 +410,15 @@ static int avrf_mass_erase(struct flash_bank *bank)
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||
|| (ERROR_OK != avr_jtagprg_chiperase(avr))
|
||||
|| (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
|
||||
{
|
||||
|| (ERROR_OK != avr_jtagprg_chiperase(avr))
|
||||
|| (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -450,38 +428,30 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
|
||||
int i;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(CMD_CTX, "avr mass_erase <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
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 (avrf_mass_erase(bank) == ERROR_OK)
|
||||
{
|
||||
if (avrf_mass_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, "avr mass erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
command_print(CMD_CTX, "avr mass erase failed");
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s", __FUNCTION__);
|
||||
LOG_DEBUG("%s", __func__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration avrf_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "mass_erase",
|
||||
.usage = "<bank>",
|
||||
.handler = avrf_handle_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "erase entire device",
|
||||
@@ -493,6 +463,7 @@ static const struct command_registration avrf_command_handlers[] = {
|
||||
.name = "avrf",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "AVR flash command group",
|
||||
.usage = "",
|
||||
.chain = avrf_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
@@ -508,7 +479,7 @@ struct flash_driver avr_flash = {
|
||||
.read = default_flash_read,
|
||||
.probe = avrf_probe,
|
||||
.auto_probe = avrf_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = avrf_protect_check,
|
||||
.info = avrf_info,
|
||||
};
|
||||
|
||||
1757
src/flash/nor/cfi.c
1757
src/flash/nor/cfi.c
File diff suppressed because it is too large
Load Diff
@@ -17,14 +17,14 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CFI_H
|
||||
#define CFI_H
|
||||
|
||||
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
|
||||
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
|
||||
|
||||
struct cfi_flash_bank
|
||||
{
|
||||
struct cfi_flash_bank {
|
||||
struct working_area *write_algorithm;
|
||||
|
||||
int x16_as_x8;
|
||||
@@ -80,8 +80,7 @@ struct cfi_flash_bank
|
||||
* as defined for the Advanced+ Boot Block Flash Memory (C3)
|
||||
* 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 major_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
|
||||
* 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 major_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
|
||||
* 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 major_version;
|
||||
uint8_t minor_version;
|
||||
@@ -140,14 +137,12 @@ enum {
|
||||
CFI_UNLOCK_5555_2AAA,
|
||||
};
|
||||
|
||||
struct cfi_unlock_addresses
|
||||
{
|
||||
struct cfi_unlock_addresses {
|
||||
uint32_t unlock1;
|
||||
uint32_t unlock2;
|
||||
};
|
||||
|
||||
struct cfi_fixup
|
||||
{
|
||||
struct cfi_fixup {
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
void (*fixup)(struct flash_bank *bank, void *param);
|
||||
@@ -161,6 +156,7 @@ struct cfi_fixup
|
||||
#define CFI_MFR_AMIC 0x0037
|
||||
#define CFI_MFR_SST 0x00BF
|
||||
#define CFI_MFR_MX 0x00C2
|
||||
#define CFI_MFR_EON 0x007F
|
||||
|
||||
#define CFI_MFR_ANY 0xffff
|
||||
#define CFI_ID_ANY 0xffff
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <flash/nor/imp.h>
|
||||
#include <target/image.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* 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);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed erasing sectors %d to %d", first, last);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -57,8 +54,7 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
int retval;
|
||||
|
||||
/* 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");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -79,47 +75,47 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
*/
|
||||
retval = bank->driver->protect(bank, set, first, last);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed setting protection for areas %d to %d", first, last);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_driver_write(struct flash_bank *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = bank->driver->write(bank, buffer, offset, count);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||
bank->base, offset);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR(
|
||||
"error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||
bank->base,
|
||||
offset);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_driver_read(struct flash_bank *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("call flash_driver_read()");
|
||||
|
||||
retval = bank->driver->read(bank, buffer, offset, count);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||
bank->base, offset);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR(
|
||||
"error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||
bank->base,
|
||||
offset);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int default_flash_read(struct flash_bank *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
return target_read_buffer(bank->target, offset + bank->base, count, buffer);
|
||||
}
|
||||
@@ -128,19 +124,16 @@ void flash_bank_add(struct flash_bank *bank)
|
||||
{
|
||||
/* put flash bank in linked list */
|
||||
unsigned bank_num = 0;
|
||||
if (flash_banks)
|
||||
{
|
||||
if (flash_banks) {
|
||||
/* find last flash bank */
|
||||
struct flash_bank *p = flash_banks;
|
||||
while (NULL != p->next)
|
||||
{
|
||||
while (NULL != p->next) {
|
||||
bank_num += 1;
|
||||
p = p->next;
|
||||
}
|
||||
p->next = bank;
|
||||
bank_num += 1;
|
||||
}
|
||||
else
|
||||
} else
|
||||
flash_banks = bank;
|
||||
|
||||
bank->bank_number = bank_num;
|
||||
@@ -156,12 +149,9 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num)
|
||||
struct flash_bank *p;
|
||||
int i = 0;
|
||||
|
||||
for (p = flash_banks; p; p = p->next)
|
||||
{
|
||||
for (p = flash_banks; p; p = p->next) {
|
||||
if (i++ == num)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
LOG_ERROR("flash bank %d does not exist", num);
|
||||
return NULL;
|
||||
@@ -172,9 +162,7 @@ int flash_get_bank_count(void)
|
||||
struct flash_bank *p;
|
||||
int i = 0;
|
||||
for (p = flash_banks; p; p = p->next)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -184,8 +172,7 @@ struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
|
||||
unsigned found = 0;
|
||||
|
||||
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)
|
||||
return bank;
|
||||
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;
|
||||
|
||||
bank = get_flash_bank_by_name_noprobe(name);
|
||||
if (bank != NULL)
|
||||
{
|
||||
if (bank != NULL) {
|
||||
retval = bank->driver->auto_probe(bank);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("auto_probe failed");
|
||||
return retval;
|
||||
}
|
||||
@@ -224,14 +209,11 @@ int get_flash_bank_by_num(int num, struct flash_bank **bank)
|
||||
int retval;
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
retval = p->driver->auto_probe(p);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("auto_probe failed");
|
||||
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
|
||||
* 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;
|
||||
|
||||
/* cycle through bank list */
|
||||
for (c = flash_banks; c; c = c->next)
|
||||
{
|
||||
for (c = flash_banks; c; c = c->next) {
|
||||
int retval;
|
||||
retval = c->driver->auto_probe(c);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("auto_probe failed");
|
||||
return retval;
|
||||
}
|
||||
/* 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;
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
*result_bank = NULL;
|
||||
if (check)
|
||||
{
|
||||
if (check) {
|
||||
LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
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;
|
||||
const int buffer_size = 1024;
|
||||
@@ -280,38 +261,33 @@ int default_flash_mem_blank_check(struct flash_bank *bank)
|
||||
uint32_t nBytes;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
chunk = buffer_size;
|
||||
if (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)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (nBytes = 0; nBytes < chunk; nBytes++)
|
||||
{
|
||||
if (buffer[nBytes] != 0xFF)
|
||||
{
|
||||
for (nBytes = 0; nBytes < chunk; nBytes++) {
|
||||
if (buffer[nBytes] != 0xFF) {
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
}
|
||||
@@ -319,7 +295,7 @@ int default_flash_mem_blank_check(struct flash_bank *bank)
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
free(buffer);
|
||||
|
||||
return retval;
|
||||
@@ -333,19 +309,17 @@ int default_flash_blank_check(struct flash_bank *bank)
|
||||
int fast_check = 0;
|
||||
uint32_t blank;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_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 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;
|
||||
break;
|
||||
}
|
||||
@@ -356,8 +330,7 @@ int default_flash_blank_check(struct flash_bank *bank)
|
||||
fast_check = 1;
|
||||
}
|
||||
|
||||
if (!fast_check)
|
||||
{
|
||||
if (!fast_check) {
|
||||
LOG_USER("Running slow fallback erase check - add working memory");
|
||||
return default_flash_mem_blank_check(bank);
|
||||
}
|
||||
@@ -380,8 +353,8 @@ int default_flash_blank_check(struct flash_bank *bank)
|
||||
* warning about those additions.
|
||||
*/
|
||||
static int flash_iterate_address_range_inner(struct target *target,
|
||||
char *pad_reason, uint32_t addr, uint32_t length,
|
||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||
char *pad_reason, uint32_t addr, uint32_t length,
|
||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||
{
|
||||
struct flash_bank *c;
|
||||
uint32_t last_addr = addr + length; /* first address AFTER end */
|
||||
@@ -393,17 +366,14 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (c->size == 0 || c->num_sectors == 0)
|
||||
{
|
||||
if (c->size == 0 || c->num_sectors == 0) {
|
||||
LOG_ERROR("Bank is invalid");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
if (length == 0) {
|
||||
/* 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.");
|
||||
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 */
|
||||
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.");
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
@@ -423,8 +392,7 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
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;
|
||||
uint32_t end = f->offset + f->size;
|
||||
|
||||
@@ -448,7 +416,7 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
else if (addr < end && pad_reason) {
|
||||
/* FIXME say how many bytes (e.g. 80 KB) */
|
||||
LOG_WARNING("Adding extra %s range, "
|
||||
"%#8.8x to %#8.8x",
|
||||
"%#8.8x to %#8.8x",
|
||||
pad_reason,
|
||||
(unsigned) f->offset,
|
||||
(unsigned) addr - 1);
|
||||
@@ -469,7 +437,7 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
if (last_addr < end && pad_reason) {
|
||||
/* FIXME say how many bytes (e.g. 80 KB) */
|
||||
LOG_WARNING("Adding extra %s range, "
|
||||
"%#8.8x to %#8.8x",
|
||||
"%#8.8x to %#8.8x",
|
||||
pad_reason,
|
||||
(unsigned) last_addr,
|
||||
(unsigned) end - 1);
|
||||
@@ -485,9 +453,9 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
/* invalid start or end address? */
|
||||
if (first == -1 || last == -1) {
|
||||
LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
|
||||
"is not sector-aligned",
|
||||
(unsigned) (c->base + addr),
|
||||
(unsigned) (c->base + last_addr - 1));
|
||||
"is not sector-aligned",
|
||||
(unsigned) (c->base + addr),
|
||||
(unsigned) (c->base + last_addr - 1));
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
@@ -502,23 +470,21 @@ static int flash_iterate_address_range_inner(struct target *target,
|
||||
* multiple chips.
|
||||
*/
|
||||
static int flash_iterate_address_range(struct target *target,
|
||||
char *pad_reason, uint32_t addr, uint32_t length,
|
||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||
char *pad_reason, uint32_t addr, uint32_t length,
|
||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||
{
|
||||
struct flash_bank *c;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
/* Danger! zero-length iterations means entire bank! */
|
||||
do
|
||||
{
|
||||
do {
|
||||
retval = get_flash_bank_by_addr(target, addr, true, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t cur_length = length;
|
||||
/* 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.");
|
||||
cur_length = c->base + c->size - addr;
|
||||
}
|
||||
@@ -536,10 +502,10 @@ static int flash_iterate_address_range(struct target *target,
|
||||
}
|
||||
|
||||
int flash_erase_address_range(struct target *target,
|
||||
bool pad, uint32_t addr, uint32_t length)
|
||||
bool pad, uint32_t addr, uint32_t length)
|
||||
{
|
||||
return flash_iterate_address_range(target, pad ? "erase" : NULL,
|
||||
addr, length, &flash_driver_erase);
|
||||
addr, length, &flash_driver_erase);
|
||||
}
|
||||
|
||||
static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
|
||||
@@ -554,30 +520,25 @@ int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t le
|
||||
* and doesn't restore it.
|
||||
*/
|
||||
return flash_iterate_address_range(target, "unprotect",
|
||||
addr, length, &flash_driver_unprotect);
|
||||
addr, length, &flash_driver_unprotect);
|
||||
}
|
||||
|
||||
static int compare_section (const void * a, const void * b)
|
||||
static int compare_section(const void *a, const void *b)
|
||||
{
|
||||
struct imagesection *b1, *b2;
|
||||
b1=*((struct imagesection **)a);
|
||||
b2=*((struct imagesection **)b);
|
||||
b1 = *((struct imagesection **)a);
|
||||
b2 = *((struct imagesection **)b);
|
||||
|
||||
if (b1->base_address == b2->base_address)
|
||||
{
|
||||
return 0;
|
||||
} else if (b1->base_address > b2->base_address)
|
||||
{
|
||||
else if (b1->base_address > b2->base_address)
|
||||
return 1;
|
||||
} else
|
||||
{
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int flash_write_unlock(struct target *target, struct image *image,
|
||||
uint32_t *written, int erase, bool unlock)
|
||||
uint32_t *written, int erase, bool unlock)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
@@ -592,8 +553,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
if (written)
|
||||
*written = 0;
|
||||
|
||||
if (erase)
|
||||
{
|
||||
if (erase) {
|
||||
/* assume all sectors need erasing - stops any problems
|
||||
* when flash_write is called multiple times */
|
||||
|
||||
@@ -609,16 +569,13 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
image->num_sections);
|
||||
int i;
|
||||
for (i = 0; i < image->num_sections; i++)
|
||||
{
|
||||
sections[i] = &image->sections[i];
|
||||
}
|
||||
|
||||
qsort(sections, image->num_sections, sizeof(struct imagesection *),
|
||||
compare_section);
|
||||
compare_section);
|
||||
|
||||
/* loop until we reach end of the image */
|
||||
while (section < image->num_sections)
|
||||
{
|
||||
while (section < image->num_sections) {
|
||||
uint32_t buffer_size;
|
||||
uint8_t *buffer;
|
||||
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;
|
||||
int pad_bytes = 0;
|
||||
|
||||
if (sections[section]->size == 0)
|
||||
{
|
||||
if (sections[section]->size == 0) {
|
||||
LOG_WARNING("empty section %d", section);
|
||||
section++;
|
||||
section_offset = 0;
|
||||
@@ -637,12 +593,10 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
/* find the corresponding flash bank */
|
||||
retval = get_flash_bank_by_addr(target, run_address, false, &c);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
if (c == NULL)
|
||||
{
|
||||
section++; /* and skip it */
|
||||
if (c == NULL) {
|
||||
LOG_WARNING("no flash bank found for address %x", run_address);
|
||||
section++; /* and skip it */
|
||||
section_offset = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -650,15 +604,13 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
/* collect consecutive sections which fall into the same bank */
|
||||
section_last = section;
|
||||
padding[section] = 0;
|
||||
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
||||
&& (section_last + 1 < image->num_sections))
|
||||
{
|
||||
while ((run_address + run_size - 1 < c->base + c->size - 1) &&
|
||||
(section_last + 1 < image->num_sections)) {
|
||||
/* sections are sorted */
|
||||
assert(sections[section_last + 1]->base_address >= c->base);
|
||||
if (sections[section_last + 1]->base_address >= (c->base + c->size))
|
||||
{
|
||||
/* Done with this bank */
|
||||
break;
|
||||
if (sections[section_last + 1]->base_address >= (c->base + c->size)) {
|
||||
/* Done with this bank */
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME This needlessly touches sectors BETWEEN the
|
||||
@@ -684,11 +636,12 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
run_size += pad_bytes;
|
||||
|
||||
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
|
||||
* the current write operation to the current chip.
|
||||
*/
|
||||
@@ -709,7 +662,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
|
||||
for (sector = 0; sector < c->num_sectors; sector++) {
|
||||
end = c->sectors[sector].offset
|
||||
+ c->sectors[sector].size;
|
||||
+ c->sectors[sector].size;
|
||||
if (offset_end <= end)
|
||||
break;
|
||||
}
|
||||
@@ -721,8 +674,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
|
||||
/* allocate buffer */
|
||||
buffer = malloc(run_size);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
if (buffer == NULL) {
|
||||
LOG_ERROR("Out of memory for flash bank buffer");
|
||||
retval = ERROR_FAIL;
|
||||
goto done;
|
||||
@@ -730,13 +682,12 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
buffer_size = 0;
|
||||
|
||||
/* read sections to the buffer */
|
||||
while (buffer_size < run_size)
|
||||
{
|
||||
while (buffer_size < run_size) {
|
||||
size_t size_read;
|
||||
|
||||
size_read = run_size - buffer_size;
|
||||
if (size_read > sections[section]->size - section_offset)
|
||||
size_read = sections[section]->size - section_offset;
|
||||
size_read = sections[section]->size - section_offset;
|
||||
|
||||
/* KLUDGE!
|
||||
*
|
||||
@@ -746,25 +697,25 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
|
||||
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",
|
||||
(int)section,
|
||||
(int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read);
|
||||
if ((retval = image_read_section(image, t_section_num, section_offset,
|
||||
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
|
||||
{
|
||||
LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, "
|
||||
"section_offset = %d, buffer_size = %d, size_read = %d",
|
||||
(int)section, (int)t_section_num, (int)section_offset,
|
||||
(int)buffer_size, (int)size_read);
|
||||
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);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* see if we need to pad the section */
|
||||
while (padding[section]--)
|
||||
(buffer + buffer_size)[size_read++] = 0xff;
|
||||
(buffer + buffer_size)[size_read++] = 0xff;
|
||||
|
||||
buffer_size += size_read;
|
||||
section_offset += size_read;
|
||||
|
||||
if (section_offset >= sections[section]->size)
|
||||
{
|
||||
if (section_offset >= sections[section]->size) {
|
||||
section++;
|
||||
section_offset = 0;
|
||||
}
|
||||
@@ -773,38 +724,31 @@ int flash_write_unlock(struct target *target, struct image *image,
|
||||
retval = ERROR_OK;
|
||||
|
||||
if (unlock)
|
||||
{
|
||||
retval = flash_unlock_address_range(target, run_address, run_size);
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if (erase)
|
||||
{
|
||||
if (retval == ERROR_OK) {
|
||||
if (erase) {
|
||||
/* calculate and erase sectors */
|
||||
retval = flash_erase_address_range(target,
|
||||
true, run_address, run_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if (retval == ERROR_OK) {
|
||||
/* write flash sectors */
|
||||
retval = flash_driver_write(c, buffer, run_address - c->base, run_size);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
if (retval != ERROR_OK) {
|
||||
/* abort operation */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (written != NULL)
|
||||
*written += run_size; /* add run size to total written counter */
|
||||
*written += run_size; /* add run size to total written counter */
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
free(sections);
|
||||
free(padding);
|
||||
@@ -813,7 +757,7 @@ done:
|
||||
}
|
||||
|
||||
int flash_write(struct target *target, struct image *image,
|
||||
uint32_t *written, int erase)
|
||||
uint32_t *written, int erase)
|
||||
{
|
||||
return flash_write_unlock(target, image, written, erase, false);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef 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
|
||||
* sectors, each of which can be erased and protected independently.
|
||||
*/
|
||||
struct flash_sector
|
||||
{
|
||||
/// Bus offset from start of the flash chip (in bytes).
|
||||
struct flash_sector {
|
||||
/** Bus offset from start of the flash chip (in bytes). */
|
||||
uint32_t offset;
|
||||
/// Number of bytes in this flash sector.
|
||||
/** Number of bytes in this flash sector. */
|
||||
uint32_t size;
|
||||
/**
|
||||
* 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
|
||||
* per-bank basis, if required.
|
||||
*/
|
||||
struct flash_bank
|
||||
{
|
||||
struct flash_bank {
|
||||
const char *name;
|
||||
|
||||
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()".
|
||||
*/
|
||||
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_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);
|
||||
|
||||
/**
|
||||
@@ -134,7 +133,7 @@ int flash_write(struct target *target,
|
||||
* This routine must be called when the system may modify the status.
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
@@ -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
|
||||
* @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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef 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>
|
||||
* routine in flash.c.
|
||||
*/
|
||||
struct flash_driver
|
||||
{
|
||||
struct flash_driver {
|
||||
/**
|
||||
* Gives a human-readable name of this flash driver,
|
||||
* This field is used to select and initialize the driver.
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Gives a human-readable description of arguments.
|
||||
*/
|
||||
const char *usage;
|
||||
|
||||
/**
|
||||
* An array of driver-specific commands to register. When called
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* This callback is often called from the inside of other
|
||||
@@ -208,7 +213,8 @@ struct flash_driver
|
||||
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.
|
||||
@@ -217,4 +223,4 @@ struct flash_driver
|
||||
*/
|
||||
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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -26,16 +27,17 @@ extern struct flash_driver lpc288x_flash;
|
||||
extern struct flash_driver lpc2900_flash;
|
||||
extern struct flash_driver cfi_flash;
|
||||
extern struct flash_driver at91sam3_flash;
|
||||
extern struct flash_driver at91sam4_flash;
|
||||
extern struct flash_driver at91sam7_flash;
|
||||
extern struct flash_driver str7x_flash;
|
||||
extern struct flash_driver str9x_flash;
|
||||
extern struct flash_driver aduc702x_flash;
|
||||
extern struct flash_driver stellaris_flash;
|
||||
extern struct flash_driver str9xpec_flash;
|
||||
extern struct flash_driver stm32x_flash;
|
||||
extern struct flash_driver stm32xf2xxx_flash;
|
||||
extern struct flash_driver stm32f1x_flash;
|
||||
extern struct flash_driver stm32f2x_flash;
|
||||
extern struct flash_driver stm32lx_flash;
|
||||
extern struct flash_driver tms470_flash;
|
||||
extern struct flash_driver ecosflash_flash;
|
||||
extern struct flash_driver ocl_flash;
|
||||
extern struct flash_driver pic32mx_flash;
|
||||
extern struct flash_driver avr_flash;
|
||||
@@ -44,6 +46,8 @@ extern struct flash_driver virtual_flash;
|
||||
extern struct flash_driver stmsmi_flash;
|
||||
extern struct flash_driver em357_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.
|
||||
@@ -56,15 +60,16 @@ static struct flash_driver *flash_drivers[] = {
|
||||
&cfi_flash,
|
||||
&at91sam7_flash,
|
||||
&at91sam3_flash,
|
||||
&at91sam4_flash,
|
||||
&str7x_flash,
|
||||
&str9x_flash,
|
||||
&aduc702x_flash,
|
||||
&stellaris_flash,
|
||||
&str9xpec_flash,
|
||||
&stm32x_flash,
|
||||
&stm32xf2xxx_flash,
|
||||
&stm32f1x_flash,
|
||||
&stm32f2x_flash,
|
||||
&stm32lx_flash,
|
||||
&tms470_flash,
|
||||
&ecosflash_flash,
|
||||
&ocl_flash,
|
||||
&pic32mx_flash,
|
||||
&avr_flash,
|
||||
@@ -72,14 +77,15 @@ static struct flash_driver *flash_drivers[] = {
|
||||
&virtual_flash,
|
||||
&stmsmi_flash,
|
||||
&em357_flash,
|
||||
&fm3_flash,
|
||||
&dsp5680xx_flash,
|
||||
&kinetis_flash,
|
||||
NULL,
|
||||
};
|
||||
|
||||
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)
|
||||
return flash_drivers[i];
|
||||
}
|
||||
|
||||
@@ -27,22 +27,18 @@
|
||||
* @file dsp5680xx_flash.c
|
||||
* @author Rodrigo L. Rosa <rodrigorosa.LG@gmail.com>
|
||||
* @date Thu Jun 9 18:21:58 2011
|
||||
*
|
||||
*
|
||||
* @brief This file implements the basic functions to run flashing commands
|
||||
* from the TCL interface.
|
||||
* It allows the user to flash the Freescale 5680xx DSP.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef DSP5680XX_FLASH_H
|
||||
#define DSP5680XX_FLASH_H
|
||||
|
||||
#include "imp.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <helper/time_support.h>
|
||||
@@ -53,193 +49,242 @@ struct dsp5680xx_flash_bank {
|
||||
struct working_area *write_algorithm;
|
||||
};
|
||||
|
||||
static int dsp5680xx_build_sector_list(struct flash_bank *bank){
|
||||
uint32_t offset = HFM_FLASH_BASE_ADDR;
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
int i;
|
||||
for (i = 0; i < bank->num_sectors; ++i){
|
||||
bank->sectors[i].offset = i*HFM_SECTOR_SIZE;
|
||||
bank->sectors[i].size = HFM_SECTOR_SIZE;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = -1;
|
||||
}
|
||||
LOG_USER("%s not tested yet.",__FUNCTION__);
|
||||
return ERROR_OK;
|
||||
static int dsp5680xx_build_sector_list(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t offset = HFM_FLASH_BASE_ADDR;
|
||||
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bank->num_sectors; ++i) {
|
||||
bank->sectors[i].offset = i * HFM_SECTOR_SIZE;
|
||||
bank->sectors[i].size = HFM_SECTOR_SIZE;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = -1;
|
||||
}
|
||||
LOG_USER("%s not tested yet.", __func__);
|
||||
return ERROR_OK;
|
||||
|
||||
}
|
||||
|
||||
// flash bank dsp5680xx 0 0 0 0 <target#>
|
||||
FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command){
|
||||
struct dsp5680xx_flash_bank *nbank;
|
||||
/* flash bank dsp5680xx 0 0 0 0 <target#> */
|
||||
FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command)
|
||||
{
|
||||
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->size = HFM_SIZE_BYTES; // top 4k not accessible
|
||||
bank->driver_priv = nbank;
|
||||
bank->num_sectors = HFM_SECTOR_COUNT;
|
||||
dsp5680xx_build_sector_list(bank);
|
||||
bank->base = HFM_FLASH_BASE_ADDR;
|
||||
bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */
|
||||
bank->driver_priv = nbank;
|
||||
bank->num_sectors = HFM_SECTOR_COUNT;
|
||||
dsp5680xx_build_sector_list(bank);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* A memory mapped register (PROT) holds information regarding sector protection.
|
||||
* Protection refers to undesired core access.
|
||||
* The value in this register is loaded from flash upon reset.
|
||||
*
|
||||
* @param bank
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_protect_check(struct flash_bank *bank){
|
||||
int retval = ERROR_OK;
|
||||
uint16_t protected = 0;
|
||||
retval = dsp5680xx_f_protect_check(bank->target,&protected);
|
||||
if(retval != ERROR_OK){
|
||||
for(int i = 0;i<HFM_SECTOR_COUNT;i++)
|
||||
bank->sectors[i].is_protected = -1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
for(int i = 0;i<HFM_SECTOR_COUNT/2;i++){
|
||||
if(protected & 1){
|
||||
bank->sectors[2*i].is_protected = 1;
|
||||
bank->sectors[2*i+1].is_protected = 1;
|
||||
}else{
|
||||
bank->sectors[2*i].is_protected = 0;
|
||||
bank->sectors[2*i+1].is_protected = 0;
|
||||
}
|
||||
protected = (protected >> 1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protection funcionality is not implemented.
|
||||
* 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.
|
||||
*
|
||||
* @param bank
|
||||
* @param set Apply or remove security on the chip.
|
||||
* @param first This parameter is ignored.
|
||||
* @param last This parameter is ignored.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, 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;
|
||||
if(set)
|
||||
retval = dsp5680xx_f_lock(bank->target);
|
||||
else
|
||||
retval = dsp5680xx_f_unlock(bank->target);
|
||||
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.
|
||||
*
|
||||
* @param bank
|
||||
* @param buffer Data to write to flash.
|
||||
* @param offset
|
||||
* @param count In bytes (2 bytes per address).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count){
|
||||
int retval;
|
||||
if((offset + count/2)>bank->size){
|
||||
LOG_ERROR("%s: Flash bank cannot fit data.",__FUNCTION__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
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__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset/2, count);
|
||||
uint32_t addr_word;
|
||||
for(addr_word = bank->base + offset/2;addr_word<count/2;addr_word+=(HFM_SECTOR_SIZE/2)){
|
||||
if(retval == ERROR_OK)
|
||||
bank->sectors[addr_word/(HFM_SECTOR_SIZE/2)].is_erased = 0;
|
||||
else
|
||||
bank->sectors[addr_word/(HFM_SECTOR_SIZE/2)].is_erased = -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int dsp5680xx_probe(struct flash_bank *bank){
|
||||
LOG_DEBUG("%s not implemented",__FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf, int buf_size){
|
||||
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.");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* The flash module (FM) on the dsp5680xx supports both individual sector 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 first
|
||||
* @param last
|
||||
*
|
||||
* @return
|
||||
/**
|
||||
* A memory mapped register (PROT) holds information regarding sector protection.
|
||||
* Protection refers to undesired core access.
|
||||
* The value in this register is loaded from flash upon reset.
|
||||
*
|
||||
* @param bank
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_erase(struct flash_bank * bank, int first, int last){
|
||||
int retval;
|
||||
retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
|
||||
if(retval == ERROR_OK)
|
||||
for(int i = first;i<=last;i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
// If an error occurred unknown status is set even though some sector could have been correctly erased.
|
||||
for(int i = first;i<=last;i++)
|
||||
bank->sectors[i].is_erased = -1;
|
||||
return retval;
|
||||
static int dsp5680xx_flash_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
uint16_t protected = 0;
|
||||
|
||||
retval = dsp5680xx_f_protect_check(bank->target, &protected);
|
||||
if (retval != ERROR_OK) {
|
||||
for (int i = 0; i < HFM_SECTOR_COUNT; i++)
|
||||
bank->sectors[i].is_protected = -1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
for (int i = 0; i < HFM_SECTOR_COUNT / 2; i++) {
|
||||
if (protected & 1) {
|
||||
bank->sectors[2 * i].is_protected = 1;
|
||||
bank->sectors[2 * i + 1].is_protected = 1;
|
||||
} else {
|
||||
bank->sectors[2 * i].is_protected = 0;
|
||||
bank->sectors[2 * i + 1].is_protected = 0;
|
||||
}
|
||||
protected = (protected >> 1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Protection funcionality is not implemented.
|
||||
* 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.
|
||||
*
|
||||
* @param bank
|
||||
* @param set Apply or remove security on the chip.
|
||||
* @param first This parameter is ignored.
|
||||
* @param last This parameter is ignored.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
|
||||
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;
|
||||
|
||||
if (set)
|
||||
retval = dsp5680xx_f_lock(bank->target);
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 buffer Data to write to flash.
|
||||
* @param offset
|
||||
* @param count In bytes (2 bytes per address).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t * buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if ((offset + count / 2) > bank->size) {
|
||||
LOG_ERROR("%s: Flash bank cannot fit data.", __func__);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (offset % 2) {
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0);
|
||||
uint32_t addr_word;
|
||||
|
||||
for (addr_word = bank->base + offset / 2; addr_word < count / 2;
|
||||
addr_word += (HFM_SECTOR_SIZE / 2)) {
|
||||
if (retval == ERROR_OK)
|
||||
bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0;
|
||||
else
|
||||
bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int dsp5680xx_probe(struct flash_bank *bank)
|
||||
{
|
||||
LOG_DEBUG("%s not implemented", __func__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf,
|
||||
int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size,
|
||||
"\ndsp5680xx flash driver info:\n - See comments in code.");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* The flash module (FM) on the dsp5680xx supports both individual sector
|
||||
* 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 first
|
||||
* @param last
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
|
||||
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)
|
||||
for (int i = first; i <= last; i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
/**
|
||||
* If an error occurred unknown status
|
||||
*is set even though some sector could have been correctly erased.
|
||||
*/
|
||||
for (int i = first; i <= last; i++)
|
||||
bank->sectors[i].is_erased = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* The flash module (FM) on the dsp5680xx support a blank check function.
|
||||
* This function executes the FM's blank check functionality on each and every sector.
|
||||
*
|
||||
* @param bank
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @param bank
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_erase_check(struct flash_bank * bank){
|
||||
int retval = ERROR_OK;
|
||||
uint8_t erased = 0;
|
||||
uint32_t i;
|
||||
for(i=0;i<HFM_SECTOR_COUNT;i++){
|
||||
if(bank->sectors[i].is_erased == -1){
|
||||
retval = dsp5680xx_f_erase_check(bank->target,&erased,i);
|
||||
if (retval != ERROR_OK){
|
||||
bank->sectors[i].is_erased = -1;
|
||||
}else{
|
||||
if(erased)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
bank->sectors[i].is_erased = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
static int dsp5680xx_flash_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
uint8_t erased = 0;
|
||||
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < HFM_SECTOR_COUNT; i++) {
|
||||
if (bank->sectors[i].is_erased == -1) {
|
||||
retval = dsp5680xx_f_erase_check(bank->target, &erased, i);
|
||||
if (retval != ERROR_OK) {
|
||||
bank->sectors[i].is_erased = -1;
|
||||
} else {
|
||||
if (erased)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
bank->sectors[i].is_erased = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct flash_driver dsp5680xx_flash = {
|
||||
.name = "dsp5680xx_flash",
|
||||
.flash_bank_command = dsp5680xx_flash_bank_command,
|
||||
.erase = dsp5680xx_flash_erase,
|
||||
.protect = dsp5680xx_flash_protect,
|
||||
.write = dsp5680xx_flash_write,
|
||||
//.read = default_flash_read,
|
||||
.probe = dsp5680xx_probe,
|
||||
.auto_probe = dsp5680xx_probe,
|
||||
.erase_check = dsp5680xx_flash_erase_check,
|
||||
.protect_check = dsp5680xx_flash_protect_check,
|
||||
.info = dsp5680xx_flash_info
|
||||
.name = "dsp5680xx_flash",
|
||||
.flash_bank_command = dsp5680xx_flash_bank_command,
|
||||
.erase = dsp5680xx_flash_erase,
|
||||
.protect = dsp5680xx_flash_protect,
|
||||
.write = dsp5680xx_flash_write,
|
||||
/* .read = default_flash_read, */
|
||||
.probe = dsp5680xx_probe,
|
||||
.auto_probe = dsp5680xx_probe,
|
||||
.erase_check = dsp5680xx_flash_erase_check,
|
||||
.protect_check = dsp5680xx_flash_protect_check,
|
||||
.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
|
||||
};
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* Copyright (C) 2011 by Erik Botö
|
||||
* erik.boto@pelagicore.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 *
|
||||
@@ -23,6 +23,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -34,60 +35,58 @@
|
||||
|
||||
/* em357 register locations */
|
||||
|
||||
#define EM357_FLASH_ACR 0x40008000
|
||||
#define EM357_FLASH_KEYR 0x40008004
|
||||
#define EM357_FLASH_OPTKEYR 0x40008008
|
||||
#define EM357_FLASH_SR 0x4000800C
|
||||
#define EM357_FLASH_CR 0x40008010
|
||||
#define EM357_FLASH_AR 0x40008014
|
||||
#define EM357_FLASH_OBR 0x4000801C
|
||||
#define EM357_FLASH_WRPR 0x40008020
|
||||
#define EM357_FLASH_ACR 0x40008000
|
||||
#define EM357_FLASH_KEYR 0x40008004
|
||||
#define EM357_FLASH_OPTKEYR 0x40008008
|
||||
#define EM357_FLASH_SR 0x4000800C
|
||||
#define EM357_FLASH_CR 0x40008010
|
||||
#define EM357_FLASH_AR 0x40008014
|
||||
#define EM357_FLASH_OBR 0x4000801C
|
||||
#define EM357_FLASH_WRPR 0x40008020
|
||||
|
||||
#define EM357_FPEC_CLK 0x4000402c
|
||||
#define EM357_FPEC_CLK 0x4000402c
|
||||
/* option byte location */
|
||||
|
||||
#define EM357_OB_RDP 0x08040800
|
||||
#define EM357_OB_WRP0 0x08040808
|
||||
#define EM357_OB_WRP1 0x0804080A
|
||||
#define EM357_OB_WRP2 0x0804080C
|
||||
#define EM357_OB_RDP 0x08040800
|
||||
#define EM357_OB_WRP0 0x08040808
|
||||
#define EM357_OB_WRP1 0x0804080A
|
||||
#define EM357_OB_WRP2 0x0804080C
|
||||
|
||||
/* FLASH_CR register bits */
|
||||
|
||||
#define FLASH_PG (1 << 0)
|
||||
#define FLASH_PER (1 << 1)
|
||||
#define FLASH_MER (1 << 2)
|
||||
#define FLASH_OPTPG (1 << 4)
|
||||
#define FLASH_OPTER (1 << 5)
|
||||
#define FLASH_STRT (1 << 6)
|
||||
#define FLASH_LOCK (1 << 7)
|
||||
#define FLASH_OPTWRE (1 << 9)
|
||||
#define FLASH_PG (1 << 0)
|
||||
#define FLASH_PER (1 << 1)
|
||||
#define FLASH_MER (1 << 2)
|
||||
#define FLASH_OPTPG (1 << 4)
|
||||
#define FLASH_OPTER (1 << 5)
|
||||
#define FLASH_STRT (1 << 6)
|
||||
#define FLASH_LOCK (1 << 7)
|
||||
#define FLASH_OPTWRE (1 << 9)
|
||||
|
||||
/* FLASH_SR register bits */
|
||||
|
||||
#define FLASH_BSY (1 << 0)
|
||||
#define FLASH_PGERR (1 << 2)
|
||||
#define FLASH_WRPRTERR (1 << 4)
|
||||
#define FLASH_EOP (1 << 5)
|
||||
#define FLASH_BSY (1 << 0)
|
||||
#define FLASH_PGERR (1 << 2)
|
||||
#define FLASH_WRPRTERR (1 << 4)
|
||||
#define FLASH_EOP (1 << 5)
|
||||
|
||||
/* EM357_FLASH_OBR bit definitions (reading) */
|
||||
|
||||
#define OPT_ERROR 0
|
||||
#define OPT_READOUT 1
|
||||
#define OPT_ERROR 0
|
||||
#define OPT_READOUT 1
|
||||
|
||||
/* register unlock keys */
|
||||
|
||||
#define KEY1 0x45670123
|
||||
#define KEY2 0xCDEF89AB
|
||||
#define KEY1 0x45670123
|
||||
#define KEY2 0xCDEF89AB
|
||||
|
||||
struct em357_options
|
||||
{
|
||||
struct em357_options {
|
||||
uint16_t RDP;
|
||||
uint16_t user_options;
|
||||
uint16_t protection[3];
|
||||
};
|
||||
|
||||
struct em357_flash_bank
|
||||
{
|
||||
struct em357_flash_bank {
|
||||
struct em357_options option_bytes;
|
||||
struct working_area *write_algorithm;
|
||||
int ppage_size;
|
||||
@@ -103,10 +102,7 @@ FLASH_BANK_COMMAND_HANDLER(em357_flash_bank_command)
|
||||
struct em357_flash_bank *em357_info;
|
||||
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank em357 configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
em357_info = malloc(sizeof(struct em357_flash_bank));
|
||||
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;
|
||||
|
||||
/* wait for busy to clear */
|
||||
for (;;)
|
||||
{
|
||||
for (;; ) {
|
||||
retval = em357_get_flash_status(bank, &status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
||||
if ((status & FLASH_BSY) == 0)
|
||||
break;
|
||||
if (timeout-- <= 0)
|
||||
{
|
||||
if (timeout-- <= 0) {
|
||||
LOG_ERROR("timed out waiting for flash");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
if (status & FLASH_WRPRTERR)
|
||||
{
|
||||
if (status & FLASH_WRPRTERR) {
|
||||
LOG_ERROR("em357 device protected");
|
||||
retval = ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (status & FLASH_PGERR)
|
||||
{
|
||||
if (status & FLASH_PGERR) {
|
||||
LOG_ERROR("em357 device programming failed");
|
||||
retval = ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* retval
|
||||
*/
|
||||
@@ -331,8 +322,7 @@ static int em357_protect_check(struct flash_bank *bank)
|
||||
int num_bits;
|
||||
int set;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_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 */
|
||||
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;
|
||||
if (protection & (1 << i))
|
||||
set = 0;
|
||||
@@ -363,16 +352,13 @@ static int em357_erase(struct flash_bank *bank, int first, int last)
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((first == 0) && (last == (bank->num_sectors - 1)))
|
||||
{
|
||||
return em357_mass_erase(bank);
|
||||
}
|
||||
|
||||
/* unlock flash registers */
|
||||
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)
|
||||
return retval;
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
for (i = first; i <= last; i++) {
|
||||
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -420,22 +405,19 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
|
||||
em357_info = bank->driver_priv;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_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",
|
||||
em357_info->ppage_size);
|
||||
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",
|
||||
em357_info->ppage_size);
|
||||
em357_info->ppage_size);
|
||||
last++;
|
||||
last = last - (last % em357_info->ppage_size);
|
||||
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[2] = (uint16_t)(protection >> 16);
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
for (i = first; i <= last; i++) {
|
||||
reg = (i / em357_info->ppage_size) / 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);
|
||||
}
|
||||
|
||||
if ((status = em357_erase_options(bank)) != ERROR_OK)
|
||||
status = em357_erase_options(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return status;
|
||||
|
||||
em357_info->option_bytes.protection[0] = prot_reg[0];
|
||||
@@ -473,7 +455,7 @@ static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
}
|
||||
|
||||
static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct em357_flash_bank *em357_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
@@ -484,61 +466,63 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
/* see contib/loaders/flash/stm32x.s for src, the same is used here except for
|
||||
/* see contib/loaders/flash/stm32x.s for src, the same is used here except for
|
||||
* a modified *_FLASH_BASE */
|
||||
|
||||
static const uint8_t em357_flash_write_code[] = {
|
||||
/* #define EM357_FLASH_CR_OFFSET 0x10 */
|
||||
/* #define EM357_FLASH_SR_OFFSET 0x0C */
|
||||
/* write: */
|
||||
/* #define EM357_FLASH_CR_OFFSET 0x10
|
||||
* #define EM357_FLASH_SR_OFFSET 0x0C
|
||||
* write: */
|
||||
0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */
|
||||
0x1c, 0x44, /* add r4, r3 */
|
||||
/* write_half_word: */
|
||||
/* write_half_word: */
|
||||
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 */
|
||||
0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
|
||||
/* busy: */
|
||||
0xe3, 0x68, /* ldr r3, [r4, #EM357_FLASH_SR_OFFSET] */
|
||||
/* busy: */
|
||||
0xe3, 0x68, /* ldr r3, [r4,
|
||||
*#EM357_FLASH_SR_OFFSET] */
|
||||
0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
|
||||
0xfb, 0xd0, /* beq busy */
|
||||
0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
|
||||
0x01, 0xd1, /* bne exit */
|
||||
0x01, 0x3a, /* subs r2, r2, #0x01 */
|
||||
0xf0, 0xd1, /* bne write_half_word */
|
||||
/* exit: */
|
||||
/* exit: */
|
||||
0x00, 0xbe, /* bkpt #0x00 */
|
||||
0x00, 0x80, 0x00, 0x40, /* EM357_FLASH_BASE: .word 0x40008000 */
|
||||
};
|
||||
|
||||
/* 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");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
if ((retval = target_write_buffer(target, em357_info->write_algorithm->address,
|
||||
sizeof(em357_flash_write_code),
|
||||
(uint8_t*)em357_flash_write_code)) != ERROR_OK)
|
||||
retval = target_write_buffer(target, em357_info->write_algorithm->address,
|
||||
sizeof(em357_flash_write_code), (uint8_t *)em357_flash_write_code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* 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;
|
||||
if (buffer_size <= 256)
|
||||
{
|
||||
if (buffer_size <= 256) {
|
||||
/* if we already allocated the writing code, but failed to get a
|
||||
* buffer, free the algorithm */
|
||||
if (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;
|
||||
}
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
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[3], "r3", 32, PARAM_IN_OUT);
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
while (count > 0) {
|
||||
uint32_t thisrun_count = (count > (buffer_size / 2)) ?
|
||||
(buffer_size / 2) : count;
|
||||
(buffer_size / 2) : count;
|
||||
|
||||
if ((retval = target_write_buffer(target, source->address,
|
||||
thisrun_count * 2, buffer)) != ERROR_OK)
|
||||
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);
|
||||
@@ -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[3].value, 0, 32, 0);
|
||||
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||
em357_info->write_algorithm->address,
|
||||
0,
|
||||
10000, &armv7m_info)) != ERROR_OK)
|
||||
{
|
||||
retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||
em357_info->write_algorithm->address, 0, 10000, &armv7m_info);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("error executing em357 flash write algorithm");
|
||||
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");
|
||||
/* Clear but report errors */
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
/* Clear but report errors */
|
||||
target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR);
|
||||
@@ -606,7 +585,7 @@ static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||
}
|
||||
|
||||
static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
uint32_t words_remaining = (count / 2);
|
||||
@@ -615,14 +594,12 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t bytes_written = 0;
|
||||
int retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_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);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
@@ -636,20 +613,17 @@ static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
||||
return retval;
|
||||
|
||||
/* multiple half words (2-byte) to be programmed? */
|
||||
if (words_remaining > 0)
|
||||
{
|
||||
if (words_remaining > 0) {
|
||||
/* try using a block write */
|
||||
if ((retval = em357_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
|
||||
{
|
||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
||||
{
|
||||
retval = em357_write_block(bank, buffer, offset, words_remaining);
|
||||
if (retval != ERROR_OK) {
|
||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
|
||||
/* if block write failed (no sufficient working area),
|
||||
* 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;
|
||||
address += words_remaining * 2;
|
||||
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))
|
||||
return retval;
|
||||
|
||||
while (words_remaining > 0)
|
||||
{
|
||||
while (words_remaining > 0) {
|
||||
uint16_t value;
|
||||
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;
|
||||
}
|
||||
|
||||
if (bytes_remaining)
|
||||
{
|
||||
if (bytes_remaining) {
|
||||
uint16_t value = 0xffff;
|
||||
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);
|
||||
|
||||
if (bank->sectors)
|
||||
{
|
||||
if (bank->sectors) {
|
||||
free(bank->sectors);
|
||||
bank->sectors = NULL;
|
||||
}
|
||||
@@ -733,8 +704,7 @@ static int em357_probe(struct flash_bank *bank)
|
||||
bank->num_sectors = 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].size = page_size;
|
||||
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)
|
||||
{
|
||||
int printed;
|
||||
printed = snprintf(buf, buf_size, "em357\n");
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
snprintf(buf, buf_size, "em357\n");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -770,10 +737,7 @@ COMMAND_HANDLER(em357_handle_lock_command)
|
||||
struct em357_flash_bank *em357_info = NULL;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(CMD_CTX, "em357 lock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct flash_bank *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;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_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");
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -799,8 +761,7 @@ COMMAND_HANDLER(em357_handle_lock_command)
|
||||
/* set readout protection */
|
||||
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");
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -815,10 +776,7 @@ COMMAND_HANDLER(em357_handle_unlock_command)
|
||||
struct target *target = NULL;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(CMD_CTX, "em357 unlock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
@@ -827,27 +785,24 @@ COMMAND_HANDLER(em357_handle_unlock_command)
|
||||
|
||||
target = bank->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_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");
|
||||
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");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "em357 unlocked.\n"
|
||||
"INFO: a reset or power cycle is required "
|
||||
"for the new settings to take effect.");
|
||||
"INFO: a reset or power cycle is required "
|
||||
"for the new settings to take effect.");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -856,8 +811,7 @@ static int em357_mass_erase(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
@@ -894,10 +848,7 @@ COMMAND_HANDLER(em357_handle_mass_erase_command)
|
||||
int i;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(CMD_CTX, "em357 mass_erase <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct flash_bank *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;
|
||||
|
||||
retval = em357_mass_erase(bank);
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if (retval == 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, "em357 mass erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
command_print(CMD_CTX, "em357 mass erase failed");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -926,23 +871,23 @@ COMMAND_HANDLER(em357_handle_mass_erase_command)
|
||||
static const struct command_registration em357_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "lock",
|
||||
.usage = "<bank>",
|
||||
.handler = em357_handle_lock_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Lock entire flash device.",
|
||||
},
|
||||
{
|
||||
.name = "unlock",
|
||||
.usage = "<bank>",
|
||||
.handler = em357_handle_unlock_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Unlock entire protected flash device.",
|
||||
},
|
||||
{
|
||||
.name = "mass_erase",
|
||||
.usage = "<bank>",
|
||||
.handler = em357_handle_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Erase entire flash device.",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
@@ -953,6 +898,7 @@ static const struct command_registration em357_command_handlers[] = {
|
||||
.name = "em357",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "em357 flash command group",
|
||||
.usage = "",
|
||||
.chain = em357_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
@@ -968,7 +914,7 @@ struct flash_driver em357_flash = {
|
||||
.read = default_flash_read,
|
||||
.probe = em357_probe,
|
||||
.auto_probe = em357_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = em357_protect_check,
|
||||
.info = get_em357_info,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@@ -25,9 +26,7 @@
|
||||
#include <target/image.h>
|
||||
#include "hello.h"
|
||||
|
||||
|
||||
struct faux_flash_bank
|
||||
{
|
||||
struct faux_flash_bank {
|
||||
struct target *target;
|
||||
uint8_t *memory;
|
||||
uint32_t start_address;
|
||||
@@ -43,20 +42,15 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
||||
struct faux_flash_bank *info;
|
||||
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank faux configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
info = malloc(sizeof(struct faux_flash_bank));
|
||||
if (info == NULL)
|
||||
{
|
||||
if (info == NULL) {
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
info->memory = malloc(bank->size);
|
||||
if (info == NULL)
|
||||
{
|
||||
if (info == NULL) {
|
||||
free(info);
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
@@ -68,8 +62,7 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
||||
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++)
|
||||
{
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
bank->sectors[i].offset = offset;
|
||||
bank->sectors[i].size = sectorSize;
|
||||
offset += bank->sectors[i].size;
|
||||
@@ -78,8 +71,7 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
||||
}
|
||||
|
||||
info->target = get_target(CMD_ARGV[5]);
|
||||
if (info->target == NULL)
|
||||
{
|
||||
if (info->target == NULL) {
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
||||
free(info->memory);
|
||||
free(info);
|
||||
@@ -97,7 +89,7 @@ static int faux_erase(struct flash_bank *bank, int first, int last)
|
||||
|
||||
static int faux_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
LOG_USER("set protection sector %d to %d to %s", first, last, set?"on":"off");
|
||||
LOG_USER("set protection sector %d to %d to %s", first, last, set ? "on" : "off");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FLASH_NOR_IMP_H
|
||||
#define FLASH_NOR_IMP_H
|
||||
|
||||
// this is an internal header
|
||||
/* this is an internal header */
|
||||
#include "core.h"
|
||||
#include "driver.h"
|
||||
// almost all drivers will need this file
|
||||
/* almost all drivers will need this file */
|
||||
#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,
|
||||
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/armv7m.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* flash programming support for NXP LPC17xx and LPC2xxx devices.
|
||||
@@ -62,15 +61,13 @@
|
||||
* - 176x (tested with LPC1768)
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
lpc2000_v1,
|
||||
lpc2000_v2,
|
||||
lpc1700
|
||||
} lpc2000_variant;
|
||||
|
||||
struct lpc2000_flash_bank
|
||||
{
|
||||
struct lpc2000_flash_bank {
|
||||
lpc2000_variant variant;
|
||||
struct working_area *iap_working_area;
|
||||
uint32_t cclk;
|
||||
@@ -82,8 +79,7 @@ struct lpc2000_flash_bank
|
||||
int checksum_vector;
|
||||
};
|
||||
|
||||
enum lpc2000_status_codes
|
||||
{
|
||||
enum lpc2000_status_codes {
|
||||
LPC2000_CMD_SUCCESS = 0,
|
||||
LPC2000_INVALID_COMMAND = 1,
|
||||
LPC2000_SRC_ADDR_ERROR = 2,
|
||||
@@ -104,7 +100,6 @@ enum lpc2000_status_codes
|
||||
LPC2000_INVALID_BAUD_RATE = 17,
|
||||
LPC2000_INVALID_STOP_BIT = 18,
|
||||
LPC2000_CRP_ENABLED = 19
|
||||
|
||||
};
|
||||
|
||||
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 */
|
||||
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 */
|
||||
if (bank->size == 128 * 1024)
|
||||
{
|
||||
if (bank->size == 128 * 1024) {
|
||||
bank->num_sectors = 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].size = 8 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
}
|
||||
else if (bank->size == 256 * 1024)
|
||||
{
|
||||
} else if (bank->size == 256 * 1024) {
|
||||
bank->num_sectors = 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].size = 8 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -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].size = 64 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -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].size = 8 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||
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 */
|
||||
switch (bank->size)
|
||||
{
|
||||
switch (bank->size) {
|
||||
case 4 * 1024:
|
||||
lpc2000_info->cmd51_max_buffer = 1024;
|
||||
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);
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
if (i < 8)
|
||||
{
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
if (i < 8) {
|
||||
bank->sectors[i].offset = offset;
|
||||
bank->sectors[i].size = 4 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
else if (i < 22)
|
||||
{
|
||||
} else if (i < 22) {
|
||||
bank->sectors[i].offset = offset;
|
||||
bank->sectors[i].size = 32 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
else if (i < 28)
|
||||
{
|
||||
} else if (i < 28) {
|
||||
bank->sectors[i].offset = offset;
|
||||
bank->sectors[i].size = 4 * 1024;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lpc2000_info->variant == lpc1700)
|
||||
{
|
||||
switch(bank->size)
|
||||
{
|
||||
} else if (lpc2000_info->variant == lpc1700) {
|
||||
switch (bank->size) {
|
||||
case 32 * 1024:
|
||||
bank->num_sectors = 8;
|
||||
break;
|
||||
@@ -251,7 +224,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
||||
break;
|
||||
case 128 * 1024:
|
||||
bank->num_sectors = 18;
|
||||
break;
|
||||
break;
|
||||
case 256 * 1024:
|
||||
bank->num_sectors = 22;
|
||||
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);
|
||||
|
||||
for(i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
bank->sectors[i].offset = offset;
|
||||
/* 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;
|
||||
/* 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;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||
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)
|
||||
* 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;
|
||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct mem_param mem_params[2];
|
||||
struct reg_param reg_params[5];
|
||||
struct arm_algorithm armv4_5_info; /* for LPC2000 */
|
||||
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
|
||||
uint32_t status_code;
|
||||
uint32_t iap_entry_point = 0; /* to make compiler happier */
|
||||
struct arm_algorithm arm_algo; /* for LPC2000 */
|
||||
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
|
||||
uint32_t status_code;
|
||||
uint32_t iap_entry_point = 0; /* to make compiler happier */
|
||||
|
||||
/* 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];
|
||||
|
||||
/* 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");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* write IAP code to working area */
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
switch (lpc2000_info->variant) {
|
||||
case lpc1700:
|
||||
target_buffer_set_u32(target, jump_gate,
|
||||
ARMV4_5_T_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4,
|
||||
ARMV5_T_BKPT(0));
|
||||
target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0));
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
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));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
|
||||
retval = target_write_memory(target,
|
||||
lpc2000_info->iap_working_area->address, 4, 2, jump_gate);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
switch (lpc2000_info->variant) {
|
||||
case lpc1700:
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
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;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
arm_algo.common_magic = ARM_COMMON_MAGIC;
|
||||
arm_algo.core_mode = ARM_MODE_SVC;
|
||||
arm_algo.core_state = ARM_STATE_ARM;
|
||||
iap_entry_point = 0x7ffffff1;
|
||||
break;
|
||||
default:
|
||||
@@ -361,7 +333,8 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
||||
}
|
||||
|
||||
/* 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 + 0x04, param_table[0]);
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
|
||||
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
switch (lpc2000_info->variant) {
|
||||
case lpc1700:
|
||||
/* IAP stack */
|
||||
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 */
|
||||
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;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
/* IAP stack */
|
||||
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 */
|
||||
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;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown lpc2000->variant encountered");
|
||||
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[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[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,
|
||||
code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
|
||||
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,
|
||||
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[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)
|
||||
{
|
||||
uint32_t param_table[5];
|
||||
uint32_t param_table[5] = {0};
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
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))
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
for (i = first; i <= last; i++) {
|
||||
/* check single sector */
|
||||
param_table[0] = param_table[1] = i;
|
||||
status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
|
||||
|
||||
switch (status_code)
|
||||
{
|
||||
switch (status_code) {
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
@@ -483,40 +467,30 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
||||
struct lpc2000_flash_bank *lpc2000_info;
|
||||
|
||||
if (CMD_ARGC < 8)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank lpc2000 configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
|
||||
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->cmd51_dst_boundary = 512;
|
||||
lpc2000_info->cmd51_can_256b = 0;
|
||||
lpc2000_info->cmd51_can_8192b = 1;
|
||||
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->cmd51_dst_boundary = 256;
|
||||
lpc2000_info->cmd51_can_256b = 1;
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
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->cmd51_dst_boundary = 256;
|
||||
lpc2000_info->cmd51_can_256b = 1;
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
lpc2000_info->checksum_vector = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
|
||||
free(lpc2000_info);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
@@ -527,8 +501,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
||||
lpc2000_info->calc_checksum = 0;
|
||||
lpc2000_build_sector_list(bank);
|
||||
|
||||
if (CMD_ARGC >= 9)
|
||||
{
|
||||
if (CMD_ARGC >= 9) {
|
||||
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
|
||||
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)
|
||||
{
|
||||
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];
|
||||
int status_code;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_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 */
|
||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
switch (status_code) {
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
@@ -571,8 +542,7 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
||||
|
||||
/* Erase sectors */
|
||||
status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
switch (status_code) {
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
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;
|
||||
int first_sector = 0;
|
||||
int last_sector = 0;
|
||||
uint32_t param_table[5];
|
||||
uint32_t param_table[5] = {0};
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
int i;
|
||||
struct working_area *download_area;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_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;
|
||||
|
||||
if (offset % dst_min_alignment)
|
||||
{
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment);
|
||||
if (offset % dst_min_alignment) {
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32,
|
||||
offset,
|
||||
dst_min_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)
|
||||
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;
|
||||
}
|
||||
|
||||
LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
|
||||
|
||||
/* 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;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||
for (i = 0; i < 8; i++) {
|
||||
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4,
|
||||
buf_get_u32(buffer + (i * 4), 0, 32));
|
||||
if (i != lpc2000_info->checksum_vector)
|
||||
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
||||
}
|
||||
checksum = 0 - checksum;
|
||||
LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
|
||||
|
||||
uint32_t original_value = buf_get_u32(buffer + (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 ").",
|
||||
original_value, checksum);
|
||||
LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
|
||||
uint32_t original_value = buf_get_u32(buffer +
|
||||
(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 ").", 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);
|
||||
}
|
||||
|
||||
/* 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");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t thisrun_bytes;
|
||||
if (bytes_remaining >= 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[1] = last_sector;
|
||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
switch (status_code) {
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
@@ -704,24 +673,28 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
|
||||
if (bytes_remaining >= thisrun_bytes)
|
||||
{
|
||||
if ((retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written)) != ERROR_OK)
|
||||
{
|
||||
if (bytes_remaining >= thisrun_bytes) {
|
||||
retval = target_write_buffer(bank->target, download_area->address,
|
||||
thisrun_bytes, buffer + bytes_written);
|
||||
if (retval != ERROR_OK) {
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint8_t *last_buffer = malloc(thisrun_bytes);
|
||||
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
||||
memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
|
||||
target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
|
||||
memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes -
|
||||
bytes_remaining);
|
||||
target_write_buffer(bank->target,
|
||||
download_area->address,
|
||||
thisrun_bytes,
|
||||
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 */
|
||||
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[3] = lpc2000_info->cclk;
|
||||
status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
switch (status_code) {
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
@@ -771,8 +743,7 @@ static int lpc2000_probe(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");
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(lpc2000_handle_part_id_command)
|
||||
{
|
||||
uint32_t param_table[5];
|
||||
uint32_t param_table[5] = {0};
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
|
||||
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 (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
|
||||
{
|
||||
if (status_code == ERROR_FLASH_OPERATION_FAILED)
|
||||
{
|
||||
command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||
status_code = lpc2000_iap_call(bank, 54, param_table, result_table);
|
||||
if (status_code != 0x0) {
|
||||
if (status_code == ERROR_FLASH_OPERATION_FAILED) {
|
||||
command_print(CMD_CTX,
|
||||
"no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||
return ERROR_OK;
|
||||
}
|
||||
command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
|
||||
}
|
||||
} else
|
||||
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, result_table[0]);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -840,6 +809,7 @@ static const struct command_registration lpc2000_exec_command_handlers[] = {
|
||||
.handler = lpc2000_handle_part_id_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "print part id of lpc2000 flash bank <num>",
|
||||
.usage = "<bank>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
@@ -848,6 +818,7 @@ static const struct command_registration lpc2000_command_handlers[] = {
|
||||
.name = "lpc2000",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "lpc2000 flash command group",
|
||||
.usage = "",
|
||||
.chain = lpc2000_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user