Compare commits
1211 Commits
v0.3.0-rc0
...
v0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56e74908d1 | ||
|
|
4aa0a4d811 | ||
|
|
bb4cb7935e | ||
|
|
57d5673dea | ||
|
|
d2a2c14d20 | ||
|
|
3f30563c88 | ||
|
|
aa8db989b9 | ||
|
|
fa1cfc2d4d | ||
|
|
5869992314 | ||
|
|
52d4ba3467 | ||
|
|
a2ce3a51df | ||
|
|
4c4ec09110 | ||
|
|
a0a1be5cd6 | ||
|
|
f7a6e62776 | ||
|
|
747a607aef | ||
|
|
d4d4b11a77 | ||
|
|
ff404da155 | ||
|
|
32188c5004 | ||
|
|
527e073bba | ||
|
|
65cc81ddb6 | ||
|
|
84ac6bb0d9 | ||
|
|
c646b76797 | ||
|
|
f899c2aa97 | ||
|
|
885a2f5b96 | ||
|
|
6f262b69f4 | ||
|
|
41d0901115 | ||
|
|
ff5deeeeaa | ||
|
|
3ea9e62189 | ||
|
|
e380930478 | ||
|
|
709f08f17a | ||
|
|
8b049fdba5 | ||
|
|
95ed9c4393 | ||
|
|
18969466c9 | ||
|
|
5750e899e0 | ||
|
|
cc440ca1d4 | ||
|
|
503f6139c7 | ||
|
|
3d2d5dcc9c | ||
|
|
bef37ceba2 | ||
|
|
91e3268737 | ||
|
|
82f2492138 | ||
|
|
02731cf78b | ||
|
|
f68dff6690 | ||
|
|
e11ce3e6b0 | ||
|
|
695666d294 | ||
|
|
46b6d5bfe6 | ||
|
|
3d3128a8f5 | ||
|
|
2248c387f2 | ||
|
|
303b493c22 | ||
|
|
cd3017cffa | ||
|
|
804c0b2ad3 | ||
|
|
5dcf7898f6 | ||
|
|
75cfda4cd1 | ||
|
|
465a06dfdc | ||
|
|
3172be80a3 | ||
|
|
d44f1aaeff | ||
|
|
2b5c444a32 | ||
|
|
30365886da | ||
|
|
9e52957efc | ||
|
|
33fc60befc | ||
|
|
1dad2ee602 | ||
|
|
9ff16575d2 | ||
|
|
718ee762e7 | ||
|
|
82c3c47825 | ||
|
|
b7fa16eeac | ||
|
|
4960c9018f | ||
|
|
08b0be94b5 | ||
|
|
f06148612b | ||
|
|
98f7c2127b | ||
|
|
dfba7fa949 | ||
|
|
bc088b302b | ||
|
|
1350b6aad0 | ||
|
|
60cb5bdd30 | ||
|
|
dbecb13b24 | ||
|
|
2a0c9b08d7 | ||
|
|
22d25e6921 | ||
|
|
6f2b88448f | ||
|
|
d036f17001 | ||
|
|
87cb29dcfe | ||
|
|
ff976cdb29 | ||
|
|
0c3a4b4d81 | ||
|
|
20d1ef70e8 | ||
|
|
44aaba3d08 | ||
|
|
bf1e9a83c8 | ||
|
|
4f310aa0c9 | ||
|
|
fb4239866c | ||
|
|
924bf27596 | ||
|
|
c795b0d8f1 | ||
|
|
cdcb9b0885 | ||
|
|
5ab34b28ce | ||
|
|
56d2c86500 | ||
|
|
0b641dac71 | ||
|
|
daa1ff3535 | ||
|
|
183765707f | ||
|
|
6c4a643d63 | ||
|
|
187ccb60ee | ||
|
|
0f7cea2847 | ||
|
|
8e1b5c3138 | ||
|
|
1d140c4dcd | ||
|
|
000a1cfd01 | ||
|
|
24653c950a | ||
|
|
e1679a29f0 | ||
|
|
e2d3266ff1 | ||
|
|
b60dd35e33 | ||
|
|
73566405b6 | ||
|
|
d91941d5a0 | ||
|
|
b8e930e3bf | ||
|
|
ee519ab356 | ||
|
|
dc793455e9 | ||
|
|
3e33393078 | ||
|
|
6c75f5249c | ||
|
|
b4a4d5c731 | ||
|
|
1de107a5a2 | ||
|
|
e5349bfb49 | ||
|
|
fb71a0a0dd | ||
|
|
6d8604de37 | ||
|
|
c74ca40e09 | ||
|
|
8c730aaee2 | ||
|
|
88907cc7f9 | ||
|
|
d746dee833 | ||
|
|
c8267930c7 | ||
|
|
5e221fa3a7 | ||
|
|
ab4307e693 | ||
|
|
5cb1dcfad3 | ||
|
|
0811f6b192 | ||
|
|
ad5fd39063 | ||
|
|
ff647e6bb4 | ||
|
|
1dd5277ba3 | ||
|
|
1c5c57ec8e | ||
|
|
70738bd75d | ||
|
|
fc9a2d0e6f | ||
|
|
aafd3877e6 | ||
|
|
973cd9a299 | ||
|
|
2a76c1bcf9 | ||
|
|
ae71005929 | ||
|
|
b800eb0336 | ||
|
|
1a2c258ed4 | ||
|
|
c1cb20971e | ||
|
|
296a011db5 | ||
|
|
12c143d594 | ||
|
|
82c0fb5277 | ||
|
|
e7965cd3eb | ||
|
|
a42bea654c | ||
|
|
e0b6e5deef | ||
|
|
199abf49ea | ||
|
|
48d51e1719 | ||
|
|
17921f51ab | ||
|
|
e19fe9ad09 | ||
|
|
dd8f679aa2 | ||
|
|
7c3aee96b2 | ||
|
|
991d030fcc | ||
|
|
c68c2751f3 | ||
|
|
2d450b9033 | ||
|
|
2bc7446bb8 | ||
|
|
844b5eb49d | ||
|
|
fccb812f82 | ||
|
|
adf2a9a267 | ||
|
|
9d83df72dc | ||
|
|
ba96fc3e9d | ||
|
|
f6412d9c7b | ||
|
|
faad9e5923 | ||
|
|
03e8649bc6 | ||
|
|
95f86e8e05 | ||
|
|
6d4abe906f | ||
|
|
1b3f15d51e | ||
|
|
237a707f96 | ||
|
|
e1258c703b | ||
|
|
50fb3a5129 | ||
|
|
4aedb02fcd | ||
|
|
e0338293b8 | ||
|
|
d9508b30e0 | ||
|
|
4ed5b45097 | ||
|
|
858226aae2 | ||
|
|
6105f2bc4a | ||
|
|
e60c164cdb | ||
|
|
ec88ccc51c | ||
|
|
b3bf1d12b2 | ||
|
|
9d167d62f2 | ||
|
|
be01786186 | ||
|
|
668f20d0ab | ||
|
|
384e9193e9 | ||
|
|
7cef6d650c | ||
|
|
3ed254c18a | ||
|
|
7c5acf8660 | ||
|
|
17fb7ead4b | ||
|
|
c116d8f6bc | ||
|
|
20354a66b9 | ||
|
|
2cf6d47375 | ||
|
|
272c33c190 | ||
|
|
bd3700e89d | ||
|
|
12618e4c6d | ||
|
|
d4bef466c3 | ||
|
|
aa81462618 | ||
|
|
6b1eeb92fe | ||
|
|
37cc6c495f | ||
|
|
ec297e4bf1 | ||
|
|
cba1813d5c | ||
|
|
3ace333663 | ||
|
|
155a6a2c0b | ||
|
|
84dbf8ab5a | ||
|
|
900d745567 | ||
|
|
3a84436afb | ||
|
|
e7f81c11c9 | ||
|
|
df58812b52 | ||
|
|
396b0f3012 | ||
|
|
08a890e4aa | ||
|
|
f9d203d1e6 | ||
|
|
4e2b15fc93 | ||
|
|
0c55017a22 | ||
|
|
07c06ec5e2 | ||
|
|
b963e17be7 | ||
|
|
b5962b23d8 | ||
|
|
34bbbe7961 | ||
|
|
abf01895ae | ||
|
|
0df5d1eb3c | ||
|
|
b72bfabf0d | ||
|
|
3ac2a44041 | ||
|
|
28f8e9dfb7 | ||
|
|
abe8b43755 | ||
|
|
64934d9204 | ||
|
|
e25819645e | ||
|
|
9abad965ab | ||
|
|
bfadd79965 | ||
|
|
3f18900b19 | ||
|
|
013b05f7f8 | ||
|
|
7641934197 | ||
|
|
12b8c7b89b | ||
|
|
85a4136d0b | ||
|
|
e40f638063 | ||
|
|
ef4fbd36d4 | ||
|
|
b8b4bb0745 | ||
|
|
3616b93eee | ||
|
|
960ad2f776 | ||
|
|
2c3e413d49 | ||
|
|
d265c219b9 | ||
|
|
1cd7b3b49b | ||
|
|
6f2b9ea9e1 | ||
|
|
f85dc92d2a | ||
|
|
47998a55e0 | ||
|
|
fcd3c52611 | ||
|
|
c8b8a34bb5 | ||
|
|
74ce435d97 | ||
|
|
4a2f4e3433 | ||
|
|
80a757d82e | ||
|
|
fc99287b09 | ||
|
|
646ce814b4 | ||
|
|
4639366947 | ||
|
|
dca173053b | ||
|
|
d6aff79f1a | ||
|
|
bb77e5d32f | ||
|
|
27b13e3377 | ||
|
|
c86a64dff7 | ||
|
|
a1009509fb | ||
|
|
36dec1b319 | ||
|
|
af79925eb1 | ||
|
|
6f929dbd93 | ||
|
|
38e376d232 | ||
|
|
0a9d7cab6d | ||
|
|
b3e64566ab | ||
|
|
75892bfc6e | ||
|
|
8438dee786 | ||
|
|
75c706cc04 | ||
|
|
838d41af29 | ||
|
|
cfd79e96a6 | ||
|
|
08589462ad | ||
|
|
6b9c14e908 | ||
|
|
97996214f5 | ||
|
|
1c42606aea | ||
|
|
ac46e072df | ||
|
|
068626fde4 | ||
|
|
a34345451d | ||
|
|
134df4b701 | ||
|
|
29a8cdc3b0 | ||
|
|
3d9cb516c2 | ||
|
|
910dd664ce | ||
|
|
26d7ed08f9 | ||
|
|
733ced125a | ||
|
|
f0da635e55 | ||
|
|
cbea1ed71f | ||
|
|
e7acbdf5db | ||
|
|
ac19fc0da7 | ||
|
|
96d2b61c04 | ||
|
|
97de520bc0 | ||
|
|
304af6e7d8 | ||
|
|
eb1bc657ae | ||
|
|
456ec016c2 | ||
|
|
81aec6be04 | ||
|
|
bbb754aa39 | ||
|
|
19ad7f828b | ||
|
|
927ae6899d | ||
|
|
0a1b7dcfc4 | ||
|
|
0529c14bfe | ||
|
|
a4a2808c2a | ||
|
|
7b0314c377 | ||
|
|
7936ab16da | ||
|
|
efb93efd6f | ||
|
|
ecd709fa55 | ||
|
|
5da53f17f0 | ||
|
|
30a6e683b8 | ||
|
|
2bc4dee7e6 | ||
|
|
56c5f6361e | ||
|
|
dd9d1a3459 | ||
|
|
12b67a2b41 | ||
|
|
ec8c3b5a67 | ||
|
|
e8599cc3d8 | ||
|
|
899c9975e7 | ||
|
|
da3bcb392e | ||
|
|
747d6f2286 | ||
|
|
a7fd30c07f | ||
|
|
af1d7590ed | ||
|
|
3edcff8b8e | ||
|
|
c2cc677056 | ||
|
|
340e2eb762 | ||
|
|
e51b9a4ac7 | ||
|
|
87589043fa | ||
|
|
56e0171420 | ||
|
|
d4d16f1036 | ||
|
|
0073e7a69e | ||
|
|
31e3ea7c19 | ||
|
|
f67f6fe5bb | ||
|
|
a0edb8a328 | ||
|
|
f4651c869f | ||
|
|
87a0119fa2 | ||
|
|
f3e6f584f1 | ||
|
|
ae6374e25d | ||
|
|
d9dc604a4d | ||
|
|
1527272fb2 | ||
|
|
5fdee60fd4 | ||
|
|
c90702eaa7 | ||
|
|
04ee41de52 | ||
|
|
32f961daba | ||
|
|
bdde9460b9 | ||
|
|
acd6d33994 | ||
|
|
146e841fc9 | ||
|
|
c65d94f7d0 | ||
|
|
3cb0b56005 | ||
|
|
79a73a786e | ||
|
|
b58c1d808f | ||
|
|
c5eb8e29bd | ||
|
|
eae56d27c3 | ||
|
|
a535d2f643 | ||
|
|
24551b7b92 | ||
|
|
ed59dfc80a | ||
|
|
f62c035c52 | ||
|
|
cf2cb0fc84 | ||
|
|
66985bb306 | ||
|
|
9a51b8b0e3 | ||
|
|
7e2dffbbff | ||
|
|
ea7a49cb9b | ||
|
|
6eee0729d7 | ||
|
|
eb6c880ddc | ||
|
|
adbf40a045 | ||
|
|
de27ebfa83 | ||
|
|
23f07d08e3 | ||
|
|
434f570e51 | ||
|
|
822c06d9e3 | ||
|
|
f7bd1e8f3a | ||
|
|
12499f97fd | ||
|
|
66e45ba611 | ||
|
|
49675db972 | ||
|
|
8256a792c5 | ||
|
|
c538a830cd | ||
|
|
6db3ed48c6 | ||
|
|
5e7369d99a | ||
|
|
2a402ae2c7 | ||
|
|
afb6d38bd5 | ||
|
|
450ceda9ae | ||
|
|
9cbab8d3a6 | ||
|
|
2b2d5ec1e3 | ||
|
|
eac262e5d2 | ||
|
|
7a4f4457e5 | ||
|
|
5a94612148 | ||
|
|
c6dd6a576d | ||
|
|
fa43bdff54 | ||
|
|
aaf948a6be | ||
|
|
36e53978b9 | ||
|
|
a8880f0b5a | ||
|
|
7da02a8330 | ||
|
|
0241b1e105 | ||
|
|
1650ab3a22 | ||
|
|
26e4fac57e | ||
|
|
54063d7294 | ||
|
|
f52a596860 | ||
|
|
a1c40f5120 | ||
|
|
377c5504b9 | ||
|
|
56adfadb5d | ||
|
|
ddea033043 | ||
|
|
15accefbe2 | ||
|
|
98eea5680b | ||
|
|
0c1bc6703c | ||
|
|
2c35b35e11 | ||
|
|
41e92d8a7a | ||
|
|
447f0896dd | ||
|
|
9e3136a5f8 | ||
|
|
28b1794505 | ||
|
|
2958665f6b | ||
|
|
2641fd9576 | ||
|
|
cb4a475f6c | ||
|
|
165fb9309d | ||
|
|
c9e448222c | ||
|
|
df0e90ec8c | ||
|
|
6512e5e36b | ||
|
|
ba00ba47d2 | ||
|
|
6c3a28ca26 | ||
|
|
c79cca04be | ||
|
|
35f1a40f6f | ||
|
|
2fc071c6e1 | ||
|
|
14ed20967f | ||
|
|
0b7720d2ff | ||
|
|
264d24495d | ||
|
|
d1bc4375e9 | ||
|
|
5d57cad001 | ||
|
|
4bbe7d174f | ||
|
|
896ac8d4ef | ||
|
|
a976ce2dd4 | ||
|
|
879a04cc6b | ||
|
|
865efd828a | ||
|
|
fe9228a32d | ||
|
|
e1ec02bb05 | ||
|
|
d5e4e23f9a | ||
|
|
f0c3e7011f | ||
|
|
62dd15d78f | ||
|
|
7e18d96d03 | ||
|
|
6ec5b9c674 | ||
|
|
1d29440a9c | ||
|
|
c2af99d471 | ||
|
|
b123fd3cd9 | ||
|
|
f4a1070dcf | ||
|
|
4c43afce85 | ||
|
|
a79b76d893 | ||
|
|
6ec526e706 | ||
|
|
eaf10f69de | ||
|
|
34654359a9 | ||
|
|
62fbb0f545 | ||
|
|
e03f3c57a5 | ||
|
|
ac1887c703 | ||
|
|
37201c019f | ||
|
|
1de0b9d351 | ||
|
|
747f8af672 | ||
|
|
682910fdc2 | ||
|
|
55eeea7fce | ||
|
|
03c103d56a | ||
|
|
d84fead487 | ||
|
|
f4b52e1ceb | ||
|
|
66ca84b581 | ||
|
|
1c7d3d200c | ||
|
|
a65e75ea34 | ||
|
|
48edd58c39 | ||
|
|
445da543d8 | ||
|
|
5576a6240a | ||
|
|
63dc352876 | ||
|
|
5949a3b3a5 | ||
|
|
563d937c3c | ||
|
|
177bbd8891 | ||
|
|
209a0197f0 | ||
|
|
fb984a477d | ||
|
|
51e9b25c9a | ||
|
|
330733eadf | ||
|
|
892604bc7e | ||
|
|
da7c202b57 | ||
|
|
8fc5a9a5e9 | ||
|
|
cbc894ed7b | ||
|
|
7b2906de24 | ||
|
|
8e8a359af2 | ||
|
|
e1ee270265 | ||
|
|
be65f497f5 | ||
|
|
5dd6457d2c | ||
|
|
3d204ec66a | ||
|
|
bc9ae74073 | ||
|
|
c0630d8a58 | ||
|
|
cee1f39f18 | ||
|
|
64653b0bbb | ||
|
|
ec6c1962c2 | ||
|
|
2264270fe4 | ||
|
|
5219b35be6 | ||
|
|
8c8e53baf6 | ||
|
|
e456da073a | ||
|
|
8c2846ed45 | ||
|
|
17b7600a59 | ||
|
|
73ec6d9b89 | ||
|
|
3debd59c5e | ||
|
|
b0858e89c7 | ||
|
|
a398c85de7 | ||
|
|
01f93137c4 | ||
|
|
cdfdcb2854 | ||
|
|
070259cadb | ||
|
|
cb8d567b75 | ||
|
|
f8a62fb9c6 | ||
|
|
7124be8247 | ||
|
|
4ff5eda576 | ||
|
|
0377e5b54d | ||
|
|
c4992c6d86 | ||
|
|
2da2864632 | ||
|
|
8795b8f9df | ||
|
|
42e00bb379 | ||
|
|
fd343bea7f | ||
|
|
933b4579f0 | ||
|
|
3b5751a4d4 | ||
|
|
89fa493a3b | ||
|
|
df22f0f9ca | ||
|
|
37dd5a685a | ||
|
|
5f0223423d | ||
|
|
30f6142fc8 | ||
|
|
acbe054a38 | ||
|
|
68889ea02f | ||
|
|
5782999f60 | ||
|
|
ddce517e3a | ||
|
|
e0cb27df6b | ||
|
|
4e56a2303b | ||
|
|
4d2750e571 | ||
|
|
77aa7ca8d6 | ||
|
|
a0d983ab06 | ||
|
|
6ce3a299f3 | ||
|
|
f31dfffdef | ||
|
|
46ed068bac | ||
|
|
bd3ef5ca3d | ||
|
|
2221a03744 | ||
|
|
8f3c728273 | ||
|
|
05a5f682c6 | ||
|
|
ffc704fdeb | ||
|
|
7c9cd47893 | ||
|
|
fd5f53f035 | ||
|
|
e07ad30577 | ||
|
|
cfc02ccca2 | ||
|
|
1240ae459f | ||
|
|
060980357d | ||
|
|
3f8aa3cb03 | ||
|
|
2653b80307 | ||
|
|
b715a81f5b | ||
|
|
ac06d41fc7 | ||
|
|
cc53ad81d3 | ||
|
|
21378f58b6 | ||
|
|
5d244b85e2 | ||
|
|
83568b6b62 | ||
|
|
49036463db | ||
|
|
4946925bea | ||
|
|
a3d81eed4d | ||
|
|
be482a5335 | ||
|
|
ed90b6659f | ||
|
|
9d4c89f37f | ||
|
|
a93b404161 | ||
|
|
d89c631014 | ||
|
|
9e5d8a94f1 | ||
|
|
910bb250c4 | ||
|
|
c297a14f70 | ||
|
|
6b066cd170 | ||
|
|
8f5ff3ddcf | ||
|
|
17a9dea53a | ||
|
|
cd7e76ebf0 | ||
|
|
f74e2e033a | ||
|
|
66ee303456 | ||
|
|
144e3678bd | ||
|
|
8a41656391 | ||
|
|
5f6962b34f | ||
|
|
4e67912fb0 | ||
|
|
c3800b5e67 | ||
|
|
a17caa387c | ||
|
|
dd063d9914 | ||
|
|
8161fd3163 | ||
|
|
97fbd793b3 | ||
|
|
28300bbf6f | ||
|
|
df95fe25a4 | ||
|
|
d79176e1bc | ||
|
|
84c03168a5 | ||
|
|
d1eca9a74c | ||
|
|
69908ddbd0 | ||
|
|
11061486b5 | ||
|
|
509fe82b07 | ||
|
|
e232dea176 | ||
|
|
e905fe6e75 | ||
|
|
b40f265f9c | ||
|
|
90d09e35e4 | ||
|
|
ad090413a8 | ||
|
|
6b9bb584a5 | ||
|
|
b4e95c3720 | ||
|
|
5e977b46c3 | ||
|
|
dfa856ca18 | ||
|
|
f9606a6cb7 | ||
|
|
737f8f2735 | ||
|
|
0ff0dbba49 | ||
|
|
ccae9ae020 | ||
|
|
1bf7462edb | ||
|
|
7609e1091a | ||
|
|
1cbe3ec6f1 | ||
|
|
a12a29c28a | ||
|
|
b90bf52be3 | ||
|
|
1765b10304 | ||
|
|
b595ab8b97 | ||
|
|
c4aa2fd6e7 | ||
|
|
bdae918dcd | ||
|
|
2a4a94b7ac | ||
|
|
8d46720cda | ||
|
|
fc2d9f8761 | ||
|
|
355a673032 | ||
|
|
9a31d66b3f | ||
|
|
339e08baa5 | ||
|
|
b1d034bf2f | ||
|
|
779bdbe797 | ||
|
|
3ab599a7e4 | ||
|
|
30be874de8 | ||
|
|
0af32bb938 | ||
|
|
48429dcfad | ||
|
|
e2f23c5437 | ||
|
|
76b89755c9 | ||
|
|
75e37b5348 | ||
|
|
b4c4b5f71e | ||
|
|
29772ec372 | ||
|
|
8de1e7bd9e | ||
|
|
1595fd7c4b | ||
|
|
16e0404777 | ||
|
|
e7fd1d3d50 | ||
|
|
62e5649600 | ||
|
|
769fbfa058 | ||
|
|
4c54c27da7 | ||
|
|
60ba4641d6 | ||
|
|
607634f967 | ||
|
|
25a7ac2c75 | ||
|
|
d107f71c50 | ||
|
|
2461855494 | ||
|
|
69076057dd | ||
|
|
833e7f5248 | ||
|
|
f7e1f2df74 | ||
|
|
47cb10217a | ||
|
|
b6210907ea | ||
|
|
e109bb6af2 | ||
|
|
c008d30fe8 | ||
|
|
991daa03eb | ||
|
|
338a674faa | ||
|
|
5507b5f430 | ||
|
|
96f0ab894a | ||
|
|
31fc1586a0 | ||
|
|
9a21ef7614 | ||
|
|
ec5e484fd6 | ||
|
|
de9a182ca6 | ||
|
|
0f544f4310 | ||
|
|
d836b079b4 | ||
|
|
3a660e2293 | ||
|
|
3efc99b34a | ||
|
|
ec64acf536 | ||
|
|
bf3abc48f0 | ||
|
|
5eb893ec41 | ||
|
|
6ff33a4ee8 | ||
|
|
caf827ee81 | ||
|
|
e6dc927e97 | ||
|
|
ad75af0b17 | ||
|
|
0583cb0a0d | ||
|
|
0d06a06f8b | ||
|
|
828d006a9d | ||
|
|
eeb4276deb | ||
|
|
b8b1353dd7 | ||
|
|
fa9b0e2167 | ||
|
|
af7f6891e9 | ||
|
|
2d6829d698 | ||
|
|
5985dee35d | ||
|
|
bcebce3ce2 | ||
|
|
dc22fd899e | ||
|
|
b404b9ab57 | ||
|
|
fa618cc74d | ||
|
|
1c619a2f12 | ||
|
|
ab5ac33fd4 | ||
|
|
5416c525d4 | ||
|
|
aacc5b583c | ||
|
|
7daec5a0ce | ||
|
|
5c4a73d0d8 | ||
|
|
700a60ec57 | ||
|
|
964c3639e2 | ||
|
|
31da0003dc | ||
|
|
808e53368c | ||
|
|
d1fbcc3589 | ||
|
|
dd9894f481 | ||
|
|
ff810723e0 | ||
|
|
5706fd7860 | ||
|
|
60a2d85af1 | ||
|
|
b58239e4c0 | ||
|
|
c46c2d77e6 | ||
|
|
425e43d9d1 | ||
|
|
69c7519562 | ||
|
|
85fe1506a2 | ||
|
|
7a67aae93c | ||
|
|
a19aaf9136 | ||
|
|
e5b0a69ba9 | ||
|
|
5458fef43c | ||
|
|
82449e2d60 | ||
|
|
9e9633c6b9 | ||
|
|
73c6e3bb18 | ||
|
|
67c29d9935 | ||
|
|
7b77b3c5d1 | ||
|
|
153848e6cc | ||
|
|
a1777fc649 | ||
|
|
d7760352e8 | ||
|
|
71cde5e359 | ||
|
|
31fb7788a6 | ||
|
|
4b18ef15a3 | ||
|
|
3e1f5e7c64 | ||
|
|
664ba309d5 | ||
|
|
59d4466b55 | ||
|
|
2dfa5e9c84 | ||
|
|
fd654c8a3e | ||
|
|
dd44ae18b4 | ||
|
|
ff25e76bad | ||
|
|
870b8c0455 | ||
|
|
8f446fcf67 | ||
|
|
cbc13187c3 | ||
|
|
e3ed06579b | ||
|
|
c049033fde | ||
|
|
195ce5eb27 | ||
|
|
f320b12289 | ||
|
|
f382ebae10 | ||
|
|
c0d14dc7f1 | ||
|
|
20218b8de6 | ||
|
|
4d8d1d32d0 | ||
|
|
7e4adfe1c5 | ||
|
|
410fab9ea8 | ||
|
|
75a37eb5b3 | ||
|
|
bd5a1799ea | ||
|
|
bd9d05e14b | ||
|
|
f0c9e89e1a | ||
|
|
94dba42313 | ||
|
|
f5093e1605 | ||
|
|
8a6d4ced4c | ||
|
|
bbebfd9e13 | ||
|
|
9b1f9810b0 | ||
|
|
5e229bbf87 | ||
|
|
cb7dbc1af4 | ||
|
|
903daa796a | ||
|
|
59f32cbe53 | ||
|
|
6e95f16d0a | ||
|
|
181d401d59 | ||
|
|
ec93209f51 | ||
|
|
d6c8945662 | ||
|
|
0091e59d2a | ||
|
|
94975c96d4 | ||
|
|
789d47c180 | ||
|
|
cfaf7bdd0a | ||
|
|
cffc98ad80 | ||
|
|
be084414ba | ||
|
|
2861877b32 | ||
|
|
23402315ce | ||
|
|
7bf1a86e47 | ||
|
|
5b9899d6ea | ||
|
|
f4788652e4 | ||
|
|
959b373f8c | ||
|
|
741cd3c3ab | ||
|
|
ca32f25638 | ||
|
|
83104648e6 | ||
|
|
b888b63fe9 | ||
|
|
0181296f61 | ||
|
|
812ab89f58 | ||
|
|
a2df544fd9 | ||
|
|
e722396890 | ||
|
|
36a538c6d7 | ||
|
|
c5e0026836 | ||
|
|
1d4a09c2ef | ||
|
|
1f3e067b86 | ||
|
|
9d57f4d5a1 | ||
|
|
6030f2ca03 | ||
|
|
47f2305229 | ||
|
|
56adbaffd0 | ||
|
|
d7d857a189 | ||
|
|
f86137066a | ||
|
|
7c393679c0 | ||
|
|
51862bb98c | ||
|
|
69df712d1d | ||
|
|
9763aef76a | ||
|
|
df9b12695f | ||
|
|
0a9daddc2e | ||
|
|
ccf59123b7 | ||
|
|
91ac164d95 | ||
|
|
bf97237401 | ||
|
|
2fb58116a5 | ||
|
|
a7c04a0e49 | ||
|
|
b6e0f2e1c3 | ||
|
|
66300d5966 | ||
|
|
9a98e83b49 | ||
|
|
dc1685ca25 | ||
|
|
10cce4a5fe | ||
|
|
0535a92456 | ||
|
|
a94748ec6d | ||
|
|
f0ce88b3af | ||
|
|
cbc0578372 | ||
|
|
e84849f5ed | ||
|
|
d7a0dfa4dc | ||
|
|
555757175e | ||
|
|
da4cb3c029 | ||
|
|
51cd370b39 | ||
|
|
23cc85b307 | ||
|
|
45527ee82c | ||
|
|
d6348d4316 | ||
|
|
21b452cf67 | ||
|
|
d8d8c5d8c3 | ||
|
|
d09e308130 | ||
|
|
e4ee891759 | ||
|
|
d50caa97d1 | ||
|
|
5a43bd2e18 | ||
|
|
82fc2f9628 | ||
|
|
b695cb7522 | ||
|
|
8193f17c3a | ||
|
|
1186f7efa7 | ||
|
|
db094c2e60 | ||
|
|
aa7c449600 | ||
|
|
5d1a9033ab | ||
|
|
2280ddeea5 | ||
|
|
269040bbad | ||
|
|
9ac7cdec82 | ||
|
|
f30136603e | ||
|
|
6731968873 | ||
|
|
a502676df7 | ||
|
|
bc07ee82fb | ||
|
|
4d4b2958a5 | ||
|
|
c2edc7908f | ||
|
|
ecc659d44d | ||
|
|
dd47bba6f8 | ||
|
|
7f48f463a1 | ||
|
|
c93ae60bce | ||
|
|
4088b1e622 | ||
|
|
ab3bdfb2cb | ||
|
|
ecab0cfe25 | ||
|
|
817bf74302 | ||
|
|
44d6a531f7 | ||
|
|
aafb916bea | ||
|
|
78c6b922e2 | ||
|
|
a7f5cdf999 | ||
|
|
04b514707f | ||
|
|
38e8d60f79 | ||
|
|
afe0298399 | ||
|
|
6435e75e14 | ||
|
|
ef746e27c5 | ||
|
|
98723c4ecd | ||
|
|
d16968e24f | ||
|
|
96b62996d2 | ||
|
|
2f6e56e383 | ||
|
|
0f1163e823 | ||
|
|
d0dee7ccaf | ||
|
|
ac927559c3 | ||
|
|
d64a873db4 | ||
|
|
dfecfd5fd4 | ||
|
|
af949b2531 | ||
|
|
d0c19e0a9d | ||
|
|
6421c2075c | ||
|
|
4952eadd8f | ||
|
|
d90063ffc5 | ||
|
|
2ec440588f | ||
|
|
cdd2d9c2d0 | ||
|
|
d727f97889 | ||
|
|
42fb6b8876 | ||
|
|
53c05c8b1d | ||
|
|
1e51cf049c | ||
|
|
e76d085603 | ||
|
|
abd7b40408 | ||
|
|
55edfdf2ab | ||
|
|
22f6a4cef5 | ||
|
|
18475360b2 | ||
|
|
1f87cf4e80 | ||
|
|
ea34dc988f | ||
|
|
73ad5cbb1a | ||
|
|
151347585a | ||
|
|
93459582fd | ||
|
|
2d5767201b | ||
|
|
46fc1d57ac | ||
|
|
c2b5d8a6fa | ||
|
|
74d09617b9 | ||
|
|
de3fb2f3bc | ||
|
|
f4e03e3b90 | ||
|
|
b87f07110a | ||
|
|
a8141cafde | ||
|
|
ccde06a08f | ||
|
|
3b7aee21b5 | ||
|
|
1bd7a78d92 | ||
|
|
ef36a7fb3b | ||
|
|
b154972bdb | ||
|
|
1a4ff43a7c | ||
|
|
a87faf5b66 | ||
|
|
24df46d067 | ||
|
|
99614219ad | ||
|
|
e2001ba211 | ||
|
|
63242c6d45 | ||
|
|
01f9dc18fc | ||
|
|
2f7fc2921d | ||
|
|
26a99ed740 | ||
|
|
a1971ecacf | ||
|
|
72b421418f | ||
|
|
e7f65c5a11 | ||
|
|
4bc80e5a65 | ||
|
|
94f5ed90f1 | ||
|
|
5e43565ab5 | ||
|
|
e8a6e3b2f4 | ||
|
|
2744a031cb | ||
|
|
5415d07139 | ||
|
|
248448ee3a | ||
|
|
f6dae0cf84 | ||
|
|
405a5df786 | ||
|
|
e976786d55 | ||
|
|
2dd9c5e1da | ||
|
|
15e8e45308 | ||
|
|
056fcdb540 | ||
|
|
c25e00b528 | ||
|
|
7de3c44320 | ||
|
|
f9e091a2d3 | ||
|
|
67f2f83937 | ||
|
|
f96d6054e6 | ||
|
|
6ba48a1b44 | ||
|
|
785115a6a0 | ||
|
|
1ad4ee2deb | ||
|
|
5f68f45186 | ||
|
|
16487e7085 | ||
|
|
b174a0d75e | ||
|
|
8e77975b92 | ||
|
|
8012b3963f | ||
|
|
bcb18b2044 | ||
|
|
f3b3752a9e | ||
|
|
3bcd9ad9d0 | ||
|
|
55926f576f | ||
|
|
0eae94879d | ||
|
|
b1de5eb9a0 | ||
|
|
6c965a3da9 | ||
|
|
996613522d | ||
|
|
52bc6cad87 | ||
|
|
ea49f2e3ff | ||
|
|
95bf461c0a | ||
|
|
db08ab8a79 | ||
|
|
cd4c059806 | ||
|
|
db2086897a | ||
|
|
38d826cec1 | ||
|
|
f7cd2aa0ef | ||
|
|
f2cbaba3cc | ||
|
|
8775a0f663 | ||
|
|
e01a0be576 | ||
|
|
45a165a432 | ||
|
|
53bfd73591 | ||
|
|
43483e5054 | ||
|
|
a03c9a8dce | ||
|
|
6a374afe71 | ||
|
|
3c9afaa645 | ||
|
|
54be77bc79 | ||
|
|
d0dfec33b6 | ||
|
|
92fc7a6fde | ||
|
|
6aa82891b6 | ||
|
|
774d71f2cf | ||
|
|
3b09560ae8 | ||
|
|
01b10d65bf | ||
|
|
c7b2cad52d | ||
|
|
40273967bf | ||
|
|
9059f9f28e | ||
|
|
ed9c4ef3c4 | ||
|
|
eba5608b52 | ||
|
|
5948e66ee8 | ||
|
|
c7b96a4dc1 | ||
|
|
958ff04b08 | ||
|
|
f7ca047213 | ||
|
|
8f4860d13f | ||
|
|
8605352387 | ||
|
|
4bc46d61ca | ||
|
|
79338ec6c2 | ||
|
|
bb6b9988cb | ||
|
|
fc01dd6a13 | ||
|
|
a043632a52 | ||
|
|
ed1aed8dd9 | ||
|
|
b712a4e8b8 | ||
|
|
12f83f0429 | ||
|
|
a15d4cc75e | ||
|
|
632fd663a8 | ||
|
|
fb59ec739a | ||
|
|
98d7ed8523 | ||
|
|
de1781b7fa | ||
|
|
453a103f48 | ||
|
|
4c28cc68ed | ||
|
|
0139e7d51a | ||
|
|
2ded74115d | ||
|
|
1f328f2885 | ||
|
|
3be0edbc5e | ||
|
|
a7a8a1c9e2 | ||
|
|
6ca63ee756 | ||
|
|
3877201581 | ||
|
|
246068fd89 | ||
|
|
1053c32d9e | ||
|
|
22b220ad7f | ||
|
|
cf2e402d71 | ||
|
|
8cc8c0544f | ||
|
|
2fecae46f6 | ||
|
|
5f6d8ecf8c | ||
|
|
c07f0600ff | ||
|
|
af3f4a0bbe | ||
|
|
e11c5a3b42 | ||
|
|
2ddeec9db5 | ||
|
|
4a29f8e21d | ||
|
|
7c0ba75eae | ||
|
|
ffc77b61dd | ||
|
|
a3f1c87eb7 | ||
|
|
4bc155398e | ||
|
|
9036fdd589 | ||
|
|
e1c26950c0 | ||
|
|
8bbb279c28 | ||
|
|
5874d5f2ea | ||
|
|
363d72a484 | ||
|
|
9f535f9af7 | ||
|
|
bee796b5b0 | ||
|
|
c20b779b89 | ||
|
|
ff3150922b | ||
|
|
d0809ac060 | ||
|
|
42ef503d37 | ||
|
|
9f212b01be | ||
|
|
f59ec2043b | ||
|
|
99b57b6dcc | ||
|
|
ebbc762182 | ||
|
|
89870c86e7 | ||
|
|
f973320cbb | ||
|
|
deede35c27 | ||
|
|
cc63d6e72b | ||
|
|
d22270e0ed | ||
|
|
a585bdf726 | ||
|
|
5b6df55a1e | ||
|
|
1df5cc18f5 | ||
|
|
670f999e7a | ||
|
|
0796dfff89 | ||
|
|
57c5c5f463 | ||
|
|
76868e0713 | ||
|
|
d02fee197f | ||
|
|
63a26b421b | ||
|
|
cfc4d5c6b7 | ||
|
|
ddb6138ed4 | ||
|
|
3f9fd4e2a6 | ||
|
|
1ae4d93c3c | ||
|
|
5eb638c71e | ||
|
|
e8e94ab245 | ||
|
|
d47764ff71 | ||
|
|
26849ad60d | ||
|
|
de735d375b | ||
|
|
5723e54fa9 | ||
|
|
e740536568 | ||
|
|
9855a11edd | ||
|
|
3ae4401901 | ||
|
|
4b20ed6b5c | ||
|
|
5e1b500b17 | ||
|
|
158698e333 | ||
|
|
46d9ba4c8b | ||
|
|
a1a3ee579c | ||
|
|
2d3cc1eac1 | ||
|
|
f93c98081f | ||
|
|
2821115ab8 | ||
|
|
39ab1c1a41 | ||
|
|
e997431602 | ||
|
|
ca594adb5a | ||
|
|
9741e126fd | ||
|
|
e09d8938f5 | ||
|
|
c942969377 | ||
|
|
6a2e83c017 | ||
|
|
0cd414c7d6 | ||
|
|
b7b4efcdf1 | ||
|
|
d796ce0e4d | ||
|
|
583a293a32 | ||
|
|
d570e4f6f6 | ||
|
|
61af6a6816 | ||
|
|
6881c1b6d6 | ||
|
|
85944d4144 | ||
|
|
627bd19768 | ||
|
|
c202ba7d34 | ||
|
|
1f357869c1 | ||
|
|
2a4d3c03cd | ||
|
|
508e5c803f | ||
|
|
65e3471d78 | ||
|
|
0df56714a0 | ||
|
|
031591ead5 | ||
|
|
151a270695 | ||
|
|
db6c2871dd | ||
|
|
841721929a | ||
|
|
23d88e5774 | ||
|
|
8d6dcb9d39 | ||
|
|
ef6387a0c9 | ||
|
|
2351641b8f | ||
|
|
6cd97f48d0 | ||
|
|
041c319d9d | ||
|
|
712d3fc0fb | ||
|
|
4cd02c63e9 | ||
|
|
770716e9e0 | ||
|
|
8b5c5c054d | ||
|
|
5c95741df7 | ||
|
|
7269ba5eb6 | ||
|
|
d70d9634bf | ||
|
|
9253ce9bae | ||
|
|
3885ab5a5a | ||
|
|
42cafc9369 | ||
|
|
994a63c3fe | ||
|
|
81fbc63718 | ||
|
|
5e9d18f027 | ||
|
|
1712d7835e | ||
|
|
4882647f3e | ||
|
|
526347f959 | ||
|
|
2689f58f2a | ||
|
|
da3196bf5e | ||
|
|
e41147bf75 | ||
|
|
b2d01a9e6a | ||
|
|
7d9df4b134 | ||
|
|
3e6f9e8d1e | ||
|
|
2b1bd97508 | ||
|
|
fb50efc6e7 | ||
|
|
a9abfa7d06 | ||
|
|
ca00483a95 | ||
|
|
ff61e6a37c | ||
|
|
c5f56437c0 | ||
|
|
6a0af06bd9 | ||
|
|
03ac53a2cf | ||
|
|
a81df55f39 | ||
|
|
fec3c4763a | ||
|
|
11fe2ec62e | ||
|
|
6cf956fa9d | ||
|
|
178c758096 | ||
|
|
865ed6ed81 | ||
|
|
1fcb351de6 | ||
|
|
6e08573efd | ||
|
|
9be533566e | ||
|
|
da739aa257 | ||
|
|
db116b1ea3 | ||
|
|
b7e4c26b9b | ||
|
|
1e57376c1a | ||
|
|
dd96b2c28e | ||
|
|
b52fa7492c | ||
|
|
20ff0a9682 | ||
|
|
ed9ac9b6fe | ||
|
|
aab023570b | ||
|
|
36b4ac90e4 | ||
|
|
fa9e5d1027 | ||
|
|
111b7a6a9d | ||
|
|
aa9351ba46 | ||
|
|
786106d725 | ||
|
|
fc116380bf | ||
|
|
ee4723c494 | ||
|
|
c63671e4f7 | ||
|
|
7b2d8d93e6 | ||
|
|
0004691e91 | ||
|
|
7f6ad49d12 | ||
|
|
680e22c4d7 | ||
|
|
7b3d54a127 | ||
|
|
266c423bbd | ||
|
|
7b49739790 | ||
|
|
75b601b1f3 | ||
|
|
5e0ee6ab08 | ||
|
|
93ab9ce888 | ||
|
|
e9566a4a6a | ||
|
|
11e545f560 | ||
|
|
4189fdad28 | ||
|
|
d660721ba8 | ||
|
|
04b8a2a6f3 | ||
|
|
a8886cdfee | ||
|
|
9b3781e5a4 | ||
|
|
af84cd33a2 | ||
|
|
4d67b0974f | ||
|
|
b699aef4c0 | ||
|
|
f8f1ac8865 | ||
|
|
714d92a954 | ||
|
|
0442bda216 | ||
|
|
11a0afc932 | ||
|
|
3541ed3aa3 | ||
|
|
3dd5c59d7d | ||
|
|
b62ee5a3c5 | ||
|
|
ab33bdd46c | ||
|
|
6e542407e7 | ||
|
|
2b78a4e82b | ||
|
|
ae5732b9e4 | ||
|
|
653ea7b25c | ||
|
|
b7b561aae8 | ||
|
|
f6f1dbfafd | ||
|
|
36a3646c22 | ||
|
|
68785af4da | ||
|
|
0f3117c19d | ||
|
|
dc98c64d71 | ||
|
|
051eaf7950 | ||
|
|
4e3c2676f1 | ||
|
|
4441c1ffdc | ||
|
|
cca7cf1e74 | ||
|
|
b64503e37f | ||
|
|
1ebdc24494 | ||
|
|
afed39c0fe | ||
|
|
98788d7a75 | ||
|
|
16b4b8cf54 | ||
|
|
8fb2baaa6b | ||
|
|
7acb2607ff | ||
|
|
ff50caa8fa | ||
|
|
d269122f91 | ||
|
|
972924b2ad | ||
|
|
af66678c9a | ||
|
|
acff2521fb | ||
|
|
a5e396b964 | ||
|
|
2d9863e121 | ||
|
|
2970696e89 | ||
|
|
fd108f5737 | ||
|
|
067501b0c7 | ||
|
|
1d5a3a6bcd | ||
|
|
ecd9c0d8bf | ||
|
|
6455ae4a59 | ||
|
|
efa7f8b4bb | ||
|
|
16f485aca2 | ||
|
|
0e37ea6499 | ||
|
|
1c51f342d7 | ||
|
|
333601da4b | ||
|
|
b8e7408b92 | ||
|
|
099e5b6920 | ||
|
|
1b60ce8d5b | ||
|
|
f37c9b8d15 | ||
|
|
b5ce7fe812 | ||
|
|
e901cee72f | ||
|
|
72210fe3a3 | ||
|
|
13e264426c | ||
|
|
2120231afd | ||
|
|
c352c96f74 | ||
|
|
0da0bfd40a | ||
|
|
8152106419 | ||
|
|
54c3cab266 | ||
|
|
e8a5092f1e | ||
|
|
a53c72cdab | ||
|
|
517049dca5 | ||
|
|
0c4d5b8b1f | ||
|
|
b628207ea6 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -4,14 +4,20 @@
|
||||
.libs
|
||||
.deps
|
||||
*.o
|
||||
*.o.??????
|
||||
*.a
|
||||
*.lo
|
||||
*.la
|
||||
*.in
|
||||
|
||||
# generated source files
|
||||
src/jtag/minidriver_imp.h
|
||||
src/jtag/jtag_minidriver.h
|
||||
|
||||
# editor files
|
||||
*.swp
|
||||
|
||||
src/startup.tcl
|
||||
startup_tcl.c
|
||||
xscale_debug.h
|
||||
|
||||
@@ -60,6 +66,10 @@ stamp-vti
|
||||
INSTALL
|
||||
NOTES
|
||||
|
||||
# coexist with quilt
|
||||
patches
|
||||
|
||||
# Eclipse stuff
|
||||
.project
|
||||
|
||||
.cproject
|
||||
.settings
|
||||
|
||||
17
BUGS
17
BUGS
@@ -1,4 +1,4 @@
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
// This file is part of the Doxygen Developer Manual
|
||||
/** @page bugs Bug Reporting
|
||||
|
||||
Please report bugs by subscribing to the OpenOCD mailing list and
|
||||
@@ -6,6 +6,12 @@ posting a message with your report:
|
||||
|
||||
openocd-development@lists.berlios.de
|
||||
|
||||
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
|
||||
such a ticket, or to update an existing ticket with more data.
|
||||
|
||||
https://sourceforge.net/apps/trac/openocd/
|
||||
|
||||
To minimize work for OpenOCD developers, you should try to include
|
||||
all of the information listed below. If you feel that some of the
|
||||
items below are unnecessary for a clear bug report, you may leave
|
||||
@@ -22,11 +28,12 @@ that may be important.
|
||||
- If the report is for a regression:
|
||||
- Include logs for both working and broken versions.
|
||||
- Find the precise version that caused the regression by binary search.
|
||||
You can use "git bisect" to expedite this binary search.
|
||||
You can use "git bisect" to expedite this binary search:
|
||||
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 file for more information
|
||||
for that process.
|
||||
solve the reported problem. See the PATCHES.txt file for information
|
||||
about that process.
|
||||
|
||||
Attach all files directly to your posting. The mailing list knows to
|
||||
transform attachments to links, but attachments must be less than 300KB
|
||||
@@ -35,7 +42,7 @@ in total.
|
||||
@section bugscrashdump Obtaining Crash Backtraces
|
||||
|
||||
If OpenOCD is crashing, there are two very effective things you can do to
|
||||
improve your chances of getting help on the development mailing list.
|
||||
improve your chances of getting help on the development mailing list.
|
||||
|
||||
Try to reproduce the problem using the dummy JTAG interface to allow other developers to replicate
|
||||
your problem robustly and use GDB to get a trace:@par
|
||||
|
||||
34
Doxyfile.in
34
Doxyfile.in
@@ -38,7 +38,7 @@ PROJECT_NUMBER =
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY =
|
||||
OUTPUT_DIRECTORY = doxygen
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
|
||||
# 4096 sub-directories (in 2 levels) under the output directory of each output
|
||||
@@ -307,13 +307,13 @@ 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 = YES
|
||||
EXTRACT_STATIC = NO
|
||||
|
||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||
# defined locally in source files will be included in the documentation.
|
||||
# If set to NO only classes defined in header files are included.
|
||||
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
|
||||
# This flag is only useful for Objective-C code. When set to YES local
|
||||
# methods, which are defined in the implementation section but not in
|
||||
@@ -384,7 +384,7 @@ HIDE_SCOPE_NAMES = NO
|
||||
# will put a list of the files that are included by a file in the documentation
|
||||
# of that file.
|
||||
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_INCLUDE_FILES = NO
|
||||
|
||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||
# is inserted in the documentation for inline members.
|
||||
@@ -403,7 +403,7 @@ SORT_MEMBER_DOCS = YES
|
||||
# by member name. If set to NO (the default) the members will appear in
|
||||
# declaration order.
|
||||
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BRIEF_DOCS = YES
|
||||
|
||||
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
|
||||
# hierarchy of group names into alphabetical order. If set to NO (the default)
|
||||
@@ -567,9 +567,9 @@ WARN_LOGFILE =
|
||||
INPUT = @srcdir@/doc/manual \
|
||||
@srcdir@/TODO \
|
||||
@srcdir@/BUGS \
|
||||
@srcdir@/PATCHES \
|
||||
@srcdir@/PATCHES.txt \
|
||||
@srcdir@/src \
|
||||
@srcdir@/config.h
|
||||
@builddir@/config.h
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
@@ -692,13 +692,13 @@ SOURCE_BROWSER = YES
|
||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||
# of functions and classes directly in the documentation.
|
||||
|
||||
INLINE_SOURCES = YES
|
||||
INLINE_SOURCES = NO
|
||||
|
||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||
# doxygen to hide any special comment blocks from generated source code
|
||||
# fragments. Normal C and C++ comments will always remain visible.
|
||||
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the REFERENCED_BY_RELATION tag is set to YES
|
||||
# then for each documented function all documented
|
||||
@@ -764,13 +764,13 @@ IGNORE_PREFIX =
|
||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||
# generate HTML output.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_HTML = @doxygen_as_html@
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `html' will be used as the default path.
|
||||
|
||||
HTML_OUTPUT = doxygen
|
||||
HTML_OUTPUT = html
|
||||
|
||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
|
||||
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
|
||||
@@ -981,7 +981,7 @@ FORMULA_FONTSIZE = 10
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_LATEX = @doxygen_as_pdf@
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
@@ -992,7 +992,7 @@ LATEX_OUTPUT = latex
|
||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||
# invoked. If left blank `latex' will be used as the default command name.
|
||||
|
||||
LATEX_CMD_NAME = latex
|
||||
LATEX_CMD_NAME = pdflatex
|
||||
|
||||
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
|
||||
# generate index for LaTeX. If left blank `makeindex' will be used as the
|
||||
@@ -1004,7 +1004,7 @@ MAKEINDEX_CMD_NAME = makeindex
|
||||
# LaTeX documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_LATEX = NO
|
||||
COMPACT_LATEX = YES
|
||||
|
||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||
@@ -1029,20 +1029,20 @@ LATEX_HEADER =
|
||||
# contain links (just like the HTML output) instead of page references
|
||||
# This makes the output suitable for online browsing using a pdf viewer.
|
||||
|
||||
PDF_HYPERLINKS = NO
|
||||
PDF_HYPERLINKS = YES
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
|
||||
USE_PDFLATEX = NO
|
||||
USE_PDFLATEX = YES
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||
# running if errors occur, instead of asking the user for help.
|
||||
# This option is also used when generating formulas in HTML.
|
||||
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_BATCHMODE = YES
|
||||
|
||||
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
|
||||
# include the index chapters (such as File Index, Compound Index, etc.)
|
||||
|
||||
17
Makefile.am
17
Makefile.am
@@ -25,12 +25,27 @@ Doxyfile: $(srcdir)/Doxyfile.in
|
||||
@( \
|
||||
echo "### @@@ -= DO NOT EDIT THIS FILE =- @@@ ###" && \
|
||||
echo "### @@@ Make changes to Doxyfile.in @@@ ###" && \
|
||||
sed -e 's,@srcdir\@,$(srcdir),' $< \
|
||||
sed -e 's,@srcdir\@,$(srcdir),' \
|
||||
-e 's,@builddir\@,$(builddir),' \
|
||||
-e 's,@doxygen_as_html\@,$(doxygen_as_html),' \
|
||||
-e 's,@doxygen_as_pdf\@,$(doxygen_as_pdf),' $< \
|
||||
) > $@
|
||||
|
||||
THE_MANUAL = doxygen/latex/refman.pdf
|
||||
|
||||
doxygen::
|
||||
$(MAKE) Doxyfile
|
||||
doxygen Doxyfile 2>&1 | perl $(srcdir)/tools/logger.pl > doxygen.log
|
||||
@if [ -f doxygen/latex/refman.tex ]; then \
|
||||
echo "Creating $(THE_MANUAL)..."; \
|
||||
$(MAKE) $(THE_MANUAL); \
|
||||
else \
|
||||
echo "Skipping Doxygen PDF..."; \
|
||||
fi
|
||||
|
||||
$(THE_MANUAL): %.pdf: %.tex
|
||||
-cd $$(dirname $*) && pdflatex $$(basename $*)
|
||||
-cd $$(dirname $*) && pdflatex $$(basename $*)
|
||||
|
||||
TCL_PATH = tcl
|
||||
# command to find paths of script files, relative to TCL_PATH
|
||||
|
||||
122
NEWS
122
NEWS
@@ -1,58 +1,98 @@
|
||||
This file should include highlights of the changes made in the
|
||||
OpenOCD openocd-0.3.0 source archive release. See the repository
|
||||
history for details about what changed, including bugfixes and
|
||||
other issues not mentioned here.
|
||||
This file includes highlights of the changes made in the
|
||||
OpenOCD 0.4.0 source archive release. See the repository
|
||||
history for details about what changed, including bugfixes
|
||||
and other issues not mentioned here.
|
||||
|
||||
JTAG Layer:
|
||||
FT2232H (high speed USB) support doesn't need separate configuration
|
||||
New reset_config options for SRST gating the JTAG clock (or not)
|
||||
TAP declaration no longer requires ircapture and mask attributes
|
||||
New "post-reset" event handler for TAP-invariant setup code
|
||||
Overridable Tcl "init_reset" and "jtag_init" procedures
|
||||
Support KT-Link JTAG adapter.
|
||||
Support USB-JTAG, Altera USB-Blaster and compatibles.
|
||||
|
||||
Boundary Scan:
|
||||
|
||||
Target Layer:
|
||||
New commands for use with Cortex-M3 processors:
|
||||
"cortex_m3 disassemble" ... Thumb2 disassembly (UAL format)
|
||||
"cortex_m3 vector_catch" ... traps certain hardware faults
|
||||
without tying up breakpoint resources
|
||||
If you're willing to help debug it
|
||||
VERY EARLY Cortex-A8 and ARMv7A support
|
||||
Updated BeagleBoard.org hardware support
|
||||
New commands for use with XScale processors: "xscale vector_table"
|
||||
ARM9
|
||||
name change: "arm9 vector_catch" not "arm9tdmi vector_catch"
|
||||
ARM11
|
||||
single stepping support for i.MX31
|
||||
bugfix for missing "arm11" prefix on "arm11 memwrite ..."
|
||||
ETM support
|
||||
Unavailable registers are not listed
|
||||
General
|
||||
- Removed commands which have been obsolete for at least
|
||||
a year (from both documentation and, sometimes, code).
|
||||
- new "reset-assert" event, for systems without SRST
|
||||
ARM
|
||||
- supports "reset-assert" event (except on Cortex-M3)
|
||||
- renamed "armv4_5" command prefix as "arm"
|
||||
- recognize TrustZone "Secure Monitor" mode
|
||||
- "arm regs" command output changed
|
||||
- register names use "sp" not "r13"
|
||||
- add top-level "mcr" and "mrc" commands, replacing
|
||||
various core-specific operations
|
||||
- basic semihosting support (ARM7/ARM9 only, for now)
|
||||
ARM11
|
||||
- Should act much more like other ARM cores:
|
||||
* Preliminary ETM and ETB hookup
|
||||
* accelerated "flash erase_check"
|
||||
* accelerated GDB memory checksum
|
||||
* support "arm regs" command
|
||||
* can access all core modes and registers
|
||||
* watchpoint support
|
||||
- Shares some core debug code with Cortex-A8
|
||||
Cortex-A8
|
||||
- Should act much more like other ARM cores:
|
||||
* support "arm regs" command
|
||||
* can access all core modes and registers
|
||||
* watchpoint support
|
||||
- Shares some core debug code with ARM11
|
||||
Cortex-M3
|
||||
- Exposed DWT registers like cycle counter
|
||||
- vector_catch settings not clobbered by resets
|
||||
- no longer interferes with firmware's fault handling
|
||||
ETM, ETB
|
||||
- "trigger_percent" command moved ETM --> ETB
|
||||
- "etm trigger_debug" command added
|
||||
MIPS
|
||||
- use fastdata writes
|
||||
Freescale DSP563xx cores (partial support)
|
||||
|
||||
Flash Layer:
|
||||
The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips
|
||||
New lpc2900 driver for NXP LPC2900 chips (ARM968 based)
|
||||
New "last" flag for NOR "flash erase_sector" and "flash protect"
|
||||
The "nand erase N" command now erases all of bank N
|
||||
'flash bank' and 'nand device' take <bank_name> as first argument.
|
||||
With this, flash/NAND commands allow referencing banks by name:
|
||||
- <bank_name>: reference the bank with its defined name
|
||||
- <driver_name>[.N]: reference the driver's Nth bank
|
||||
New 'nand verify' command to check bank against an image file.
|
||||
The "flash erase_address" command now rejects partial sectors;
|
||||
previously it would silently erase extra data. If you
|
||||
want to erase the rest of the first and/or last sectors
|
||||
instead of failing, you must pass an explicit "pad" flag.
|
||||
New at91sam9 NAND controller driver.
|
||||
New s3c64xx NAND controller driver.
|
||||
|
||||
Board, Target, and Interface Configuration Scripts:
|
||||
Amontec JTAGkey2 support
|
||||
Cleanup and additions for the TI/Luminary Stellaris scripts
|
||||
LPC1768 target (and flash) support
|
||||
Keil MCB1700 eval board
|
||||
Samsung s3c2450
|
||||
Mini2440 board
|
||||
Numeric TAP and Target identifiers now trigger warnings
|
||||
PXA255 partially enumerates
|
||||
ARM9
|
||||
- ETM and ETB hookup for iMX2* targets
|
||||
Add $HOME/.openocd to the search path.
|
||||
Handle Rev C of LM3S811 eval boards.
|
||||
- use "luminary-lm3s811.cfg" for older boards
|
||||
- use "luminary.cfg" for RevC and newer
|
||||
|
||||
Core Jim/TCL Scripting:
|
||||
New 'usage' command to provide terse command help.
|
||||
Improved command 'help' command output (sorted and indented).
|
||||
Improved command handling:
|
||||
- Most boolean settings now accept any of the following:
|
||||
on/off, enable/disable, true/false, yes/no, 1/0
|
||||
- More error checking and reporting.
|
||||
|
||||
Documentation:
|
||||
Capture more debugging and setup advice
|
||||
Notes on target source code changes that may help debugging
|
||||
New built-in command development documentation and primer.
|
||||
|
||||
Build and Release:
|
||||
Use --enable-doxygen-pdf to build PDF developer documentation.
|
||||
Consider upgrading to libftdi 0.17 if you use that library; it
|
||||
includes bugfixes which improve FT2232H support.
|
||||
|
||||
For more details about what has changed since the last release,
|
||||
see the ChangeLog associated with this source archive. For older NEWS,
|
||||
see the NEWS files associated with each release (i.e. NEWS-<version>).
|
||||
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 files in the source archive).
|
||||
the BUGS and PATCHES.txt files in the source archive).
|
||||
|
||||
@@ -9,7 +9,7 @@ must past stricter value checks, and many more error conditions have
|
||||
been handled correctly. These efforts helped to make the 0.2.0 release
|
||||
more stable and robust, though some changes may expose latent bugs in
|
||||
your existing configuration scripts.
|
||||
|
||||
|
||||
This release does not maintain backward compatibility in all respects,
|
||||
so some target or configuration scripts may need to be updated. In some
|
||||
cases, you may also see warnings; resolve those, because they indicate
|
||||
@@ -20,7 +20,7 @@ The following areas of OpenOCD functionality changed in this release:
|
||||
JTAG Layer:
|
||||
- Improves modularity: core, TCL, driver commands, and interface have
|
||||
been separated, encapsulated, and documented for developers. Mostly.
|
||||
- Improves JTAG TAP transition tables:
|
||||
- Improves JTAG TAP transition tables:
|
||||
* Makes TAP paths variable length, rather than being fixed at 7 steps.
|
||||
* Fixes problems with some targets that did not like longer paths.
|
||||
- Improves JTAG driver/minidriver modularity and encapsulation.
|
||||
|
||||
82
NEWS-0.3.0
Normal file
82
NEWS-0.3.0
Normal file
@@ -0,0 +1,82 @@
|
||||
This file should include highlights of the changes made in the
|
||||
OpenOCD openocd-0.3.0 source archive release. See the repository
|
||||
history for details about what changed, including bugfixes and
|
||||
other issues not mentioned here.
|
||||
|
||||
JTAG Layer:
|
||||
FT2232H (high speed USB) support doesn't need separate configuration
|
||||
New FT2232H JTAG adapters: Amontec, Olimex, Signalyzer
|
||||
New reset_config options for SRST gating the JTAG clock (or not)
|
||||
TAP declaration no longer requires ircapture and mask attributes
|
||||
Scan chain setup should be more robust, with better diagnostics
|
||||
New TAP events:
|
||||
"post-reset" for TAP-invariant setup code (TAPs not usable yet)
|
||||
"setup" for use once TAPs are addressable (e.g. with ICEpick)
|
||||
Overridable Tcl "init_reset" and "jtag_init" procedures
|
||||
Simple "autoprobe" mechanism to help simplify server setup
|
||||
|
||||
Boundary Scan:
|
||||
SVF bugfixes ... parsing fixes, better STATE switch conformance
|
||||
XSVF bugfixes ... be more correct, handle Xilinx tool output
|
||||
|
||||
Target Layer:
|
||||
Warn on use of obsolete numeric target IDs
|
||||
New commands for use with Cortex-M3 processors:
|
||||
"cortex_m3 disassemble" ... Thumb2 disassembly (UAL format)
|
||||
"cortex_m3 vector_catch" ... traps certain hardware faults
|
||||
without tying up breakpoint resources
|
||||
If you're willing to help debug it
|
||||
VERY EARLY Cortex-A8 and ARMv7A support
|
||||
Updated BeagleBoard.org hardware support
|
||||
you may need to explicitly "reset" after connect-to-Beagle
|
||||
New commands for use with XScale processors: "xscale vector_table"
|
||||
ARM
|
||||
bugfixes to single-stepping Thumb code
|
||||
ETM: unavailable registers are not listed
|
||||
ETB, ETM: report actual hardware status
|
||||
ARM9
|
||||
name change: "arm9 vector_catch" not "arm9tdmi vector_catch"
|
||||
ARM11
|
||||
single stepping support for i.MX31
|
||||
bugfix for missing "arm11" prefix on "arm11 memwrite ..."
|
||||
GDB support
|
||||
gdb_attach command is gone
|
||||
|
||||
Flash Layer:
|
||||
The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips
|
||||
New drivers:
|
||||
lpc2900, for NXP LPC2900 chips (ARM968 based)
|
||||
mx3_nand, for imx31
|
||||
New "last" flag for NOR "flash erase_sector" and "flash protect"
|
||||
The "nand erase N" command now erases all of bank N
|
||||
Speed up davinci_nand by about 3x
|
||||
|
||||
Board, Target, and Interface Configuration Scripts:
|
||||
Amontec JTAGkey2 support
|
||||
Cleanup and additions for the TI/Luminary Stellaris scripts
|
||||
LPC1768 target (and flash) support
|
||||
Keil MCB1700 eval board
|
||||
Samsung s3c2450
|
||||
Mini2440 board
|
||||
Numeric TAP and Target identifiers now trigger warnings
|
||||
PXA255 partially enumerates
|
||||
|
||||
Documentation:
|
||||
Capture more debugging and setup advice
|
||||
Notes on target source code changes that may help debugging
|
||||
|
||||
Build and Release:
|
||||
Repository moved from SVN at Berlios to GIT at SourceForge
|
||||
Clean builds on (32-bit) Cygwin
|
||||
Clean builds on 64-bit MinGW
|
||||
|
||||
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 files in the source archive).
|
||||
20
NEWTAPS
20
NEWTAPS
@@ -30,7 +30,7 @@ Version Number Changes:
|
||||
not a big deal. Please do report this information. We'd like to
|
||||
know about it.
|
||||
|
||||
For example
|
||||
For example
|
||||
|
||||
Error: ERROR: Tap: s3c4510.cpu - Expected id: 0x3f0f0f0f, Got: 0x1f0f0f0f
|
||||
Error: ERROR: expected: mfg: 0x787, part: 0xf0f0, ver: 0x3
|
||||
@@ -39,7 +39,7 @@ Error: ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x1
|
||||
========================================
|
||||
|
||||
Updating the Tap ID number your self
|
||||
|
||||
|
||||
Why do this? You just want the warning to go away. And don't want
|
||||
to update your version/instance of OpenOCD.
|
||||
|
||||
@@ -79,11 +79,11 @@ Examples:
|
||||
0x3f0f0f0f - is a newer ARM7TDMI
|
||||
0x3ba00477 - is an ARM cortex M3
|
||||
|
||||
Some chips have multiple JTAG taps - be sure to list
|
||||
Some chips have multiple JTAG taps - be sure to list
|
||||
each one individually - ORDER is important!
|
||||
|
||||
========================================
|
||||
B) The maker of the part
|
||||
B) The maker of the part
|
||||
|
||||
Examples:
|
||||
Xilinx, Atmel, ST Micro Systems, Freescale
|
||||
@@ -94,7 +94,7 @@ C) The family of parts it belongs to
|
||||
Examples:
|
||||
"NXP LPC Series"
|
||||
"Atmel SAM7 Series"
|
||||
|
||||
|
||||
========================================
|
||||
|
||||
D) The actual part number on the package
|
||||
@@ -121,7 +121,7 @@ For example: A consumer GPS unit or a cellphone
|
||||
ie: Olimex, LogicPD, Freescale(eval board)
|
||||
|
||||
========================================
|
||||
|
||||
|
||||
(G) Identifying information on the board.
|
||||
|
||||
Not good: "iar red ST eval board"
|
||||
@@ -135,3 +135,11 @@ For example: A consumer GPS unit or a cellphone
|
||||
ie: An FPGA or CPLD ...
|
||||
|
||||
========================================
|
||||
|
||||
(I) What target config files need updating?
|
||||
|
||||
In fact it's best if you submit a patch with those
|
||||
updates. Most of the other information listed here
|
||||
is just to help create a good patch.
|
||||
|
||||
========================================
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
// This file is part of the Doxygen Developer Manual
|
||||
/** @page patchguide Patch Guidelines
|
||||
|
||||
Please mail patches to: @par
|
||||
@@ -32,7 +32,7 @@ in response to feedback.
|
||||
Add yourself to the GPL copyright for non-trivial changes.
|
||||
|
||||
To create a patch from the command line:
|
||||
@code
|
||||
@code
|
||||
git diff >mypatch.txt
|
||||
@endcode
|
||||
|
||||
11
README
11
README
@@ -64,8 +64,8 @@ you can build the in-tree documentation.
|
||||
Installing OpenOCD
|
||||
==================
|
||||
|
||||
On Linux, you may have permissions problems to address. The best
|
||||
way to do this is to use the contrib/udev.rules file. It probably
|
||||
On Linux, you may have permissions problems to address. The best way
|
||||
to do this is to use the contrib/openocd.udev rules file. It probably
|
||||
belongs somewhere in /etc/udev/rules.d, but consult your operating
|
||||
system documentation to be sure. In particular, make sure that it
|
||||
matches the syntax used by your operating system's version of udev.
|
||||
@@ -258,6 +258,9 @@ options may be available there:
|
||||
--enable-httpd Enable builtin httpd server - useful for standalone
|
||||
OpenOCD implementations
|
||||
|
||||
--disable-doxygen-html Disable building Doxygen manual as HTML.
|
||||
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
|
||||
|
||||
Miscellaneous Configure Options
|
||||
-------------------------------
|
||||
|
||||
@@ -335,7 +338,7 @@ all operating systems used with OpenOCD. You may, however, build such
|
||||
copies for personal use.
|
||||
|
||||
The FTDICHIP drivers come as either a (win32) ZIP file, or a (Linux)
|
||||
TAR.GZ file. You must unpack them ``some where'' convient. As of this
|
||||
TAR.GZ file. You must unpack them ``some where'' convenient. As of this
|
||||
writing FTDICHIP does not supply means to install these files "in an
|
||||
appropriate place."
|
||||
|
||||
@@ -401,7 +404,7 @@ Then you can update that at your convenience using
|
||||
git pull
|
||||
|
||||
There is also a gitweb interface, which you can use either to browse
|
||||
the repository or to downlad arbitrary snapshots using HTTP:
|
||||
the repository or to download arbitrary snapshots using HTTP:
|
||||
|
||||
http://openocd.git.sourceforge.net/git/gitweb.cgi?p=openocd/openocd
|
||||
http://repo.or.cz/w/openocd.git
|
||||
|
||||
@@ -27,8 +27,8 @@ based JTAG debuggers.
|
||||
|
||||
http://sourceforge.net/projects/libusb-win32/
|
||||
|
||||
You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz
|
||||
package. Extract this file into a temp directory.
|
||||
You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz
|
||||
package. Extract this file into a temp directory.
|
||||
|
||||
Copy the file libusb-win32-device-bin-0.1.12.2\include\usb.h
|
||||
to your MinGW include directory.
|
||||
@@ -59,10 +59,10 @@ released source tarball or the git tree.
|
||||
If you are using the git tree, the following are the instructions from
|
||||
README.mingw. You will need to have the cmake utility installed.
|
||||
|
||||
- Edit Toolchain-mingw32.cmake to point to the correct MinGW
|
||||
- Edit Toolchain-mingw32.cmake to point to the correct MinGW
|
||||
installation.
|
||||
- Create a build directory like "mkdir build-win32", e.g in ../libftdi/
|
||||
- cd into that directory and run
|
||||
- cd into that directory and run
|
||||
"cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-mingw32.cmake .."
|
||||
- Copy src/ftdi.h to your MinGW include directory.
|
||||
- Copy build-win32/src/*.a to your MinGW lib directory.
|
||||
|
||||
78
TODO
78
TODO
@@ -1,4 +1,4 @@
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
// This file is part of the Doxygen Developer Manual
|
||||
/** @page tasks Pending and Open Tasks
|
||||
|
||||
This page lists pending and open tasks being considered or worked upon
|
||||
@@ -27,8 +27,8 @@ This section provides possible things to improve with OpenOCD's TCL support.
|
||||
parameters. Currently variables assigned through one such parameter
|
||||
command/script are unset before the next one is invoked.
|
||||
|
||||
- Isolate all TCL command support:
|
||||
- Pure C CLI implementations using --disable-builtin-tcl.
|
||||
- Isolate all TCL command support:
|
||||
- Pure C CLI implementations using --disable-builtin-tcl.
|
||||
- Allow developers to build new dongles using OpenOCD's JTAG core.
|
||||
- At first, provide only low-level JTAG support; target layer and
|
||||
above rely heavily on scripting event mechanisms.
|
||||
@@ -46,7 +46,7 @@ This section list issues that need to be resolved in the JTAG layer.
|
||||
The following tasks have been suggested for cleaning up the JTAG layer:
|
||||
|
||||
- use tap_set_state everywhere to allow logging TAP state transitions
|
||||
- Encapsulate cmd_queue_cur_state and related varaible handling.
|
||||
- Encapsulate cmd_queue_cur_state and related variable handling.
|
||||
- add slick 32 bit versions of jtag_add_xxx_scan() that avoids
|
||||
buf_set_u32() calls and other evidence of poor impedance match between
|
||||
API and calling code. New API should cut down # of lines in calling
|
||||
@@ -85,7 +85,7 @@ There are some known bugs to fix in JTAG adapter drivers:
|
||||
Workaround: use "tms_sequence long" @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-July/009426.html
|
||||
|
||||
The following tasks have been suggeted for improving OpenOCD's JTAG
|
||||
The following tasks have been suggested for improving OpenOCD's JTAG
|
||||
interface support:
|
||||
|
||||
- rework USB communication to be more robust. Two possible options are:
|
||||
@@ -112,7 +112,7 @@ TCP/IP packets handled by the server.
|
||||
|
||||
@section thelistswd Serial Wire Debug
|
||||
|
||||
- implement Serial Wire Debug interface
|
||||
- implement Serial Wire Debug interface
|
||||
|
||||
@section thelistbs Boundary Scan Support
|
||||
|
||||
@@ -142,6 +142,14 @@ Once the above are completed:
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
|
||||
- regression: "reset halt" between 729(works) and 788(fails): @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-July/009206.html
|
||||
- registers
|
||||
- add flush-value operation, call them all on resume/reset
|
||||
- mcr/mrc target->type support
|
||||
- missing from ARM920t, ARM966e, XScale.
|
||||
It's possible that the current syntax is unable to support read-modify-write
|
||||
operations(see arm966e).
|
||||
- mcr/mrc - retire cp15 commands when there the mrc/mrc commands have been
|
||||
tested from: arm926ejs, arm720t, cortex_a8
|
||||
- ARM7/9:
|
||||
- clean up "arm9tdmi vector_catch". Available for some arm7 cores? @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-October/011488.html
|
||||
@@ -157,18 +165,25 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
|
||||
use hardware stepping if available.
|
||||
- mdb can return garbage data if read byte operation fails for
|
||||
a memory region(16 & 32 byte access modes may be supported). Is this
|
||||
a bug in the .MX31 PDK init script? Try on i.MX31 PDK:
|
||||
a bug in the .MX31 PDK init script? Try on i.MX31 PDK:
|
||||
mdw 0xb80005f0 0x8, mdh 0xb80005f0 0x10, mdb 0xb80005f0 0x20. mdb returns
|
||||
garabage.
|
||||
- implement missing functionality (grep FNC_INFO_NOTIMPLEMENTED ...)
|
||||
- thumb support is missing: ISTR ARMv6 requires Thumb.
|
||||
ARM1156 has Thumb2; ARM1136 doesn't.
|
||||
- Thumb2 single stepping: ARM1156T2 needs simulator support
|
||||
- Cortex A8 support (ML)
|
||||
- add target implementation (ML)
|
||||
- Cortex M3 support
|
||||
- when stepping, only write dirtied registers (be faster)
|
||||
- when connecting to halted core, fetch registers (startup is quirky)
|
||||
- Generic ARM run_algorithm() interface
|
||||
- tagged struct wrapping ARM instructions and metadata
|
||||
- not revision-specific (current: ARMv4+ARMv5 -or- ARMv6 -or- ARMv7)
|
||||
- usable with at least arm_nandwrite() and generic CFI drivers
|
||||
- ETM
|
||||
- don't show FIFOFULL registers if they're not supported
|
||||
- use comparators to get more breakpoints and watchpoints
|
||||
- add "etm drivers" command
|
||||
- trace driver init() via examine() paths only, not setup()/reset
|
||||
- MC1322x support (JW/DE?)
|
||||
- integrate and test support from JW (and DE?)
|
||||
- get working with a known good interface (i.e. not today's jlink)
|
||||
@@ -192,8 +207,8 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
|
||||
|
||||
@section thelistsvf SVF/XSVF
|
||||
|
||||
- develop SVF unit tests
|
||||
- develop XSVF unit tests
|
||||
- develop SVF unit tests
|
||||
- develop XSVF unit tests
|
||||
|
||||
@section thelistflash Flash Support
|
||||
|
||||
@@ -204,6 +219,16 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
|
||||
- ocl
|
||||
- str9xpec
|
||||
|
||||
- Don't expect writing all-ones to be a safe way to write without
|
||||
changing bit values. Minimally it loses on flash modules with
|
||||
internal ECC, where it may change the ECC.
|
||||
- NOR flash_write_unlock() does that between sectors
|
||||
- there may be other cases too
|
||||
|
||||
- Make sure all commands accept either a bank name or a bank number,
|
||||
and be sure both identifiers show up in "flash banks" and "nand list".
|
||||
Right now the user-friendly names are pretty much hidden...
|
||||
|
||||
@subsection thelistflashcfi CFI
|
||||
|
||||
- finish implementing bus width/chip width handling (suggested by NC)
|
||||
@@ -285,11 +310,11 @@ These ideas were first introduced here: @par
|
||||
- automatically detect the features that are available, unless
|
||||
options were specifically provided to configure
|
||||
- provide a report of the drivers that will be build at the end of
|
||||
running configure, so the users can verify which driverswill be
|
||||
running configure, so the users can verify which drivers will be
|
||||
built during 'make' (and their options) .
|
||||
- eliminate sources of confusion in @c bootstrap script:
|
||||
-# Make @c bootstrap call 'configure --enable-maintainer-mode \<opts\>'?
|
||||
-# Add @c buildstrap script to assist with boostrap and configure steps.
|
||||
-# Add @c buildstrap script to assist with bootstrap and configure steps.
|
||||
- automatically build tool-chains required for cross-compiling
|
||||
- produce mingw32, arm-elf, others using in-tree scripts
|
||||
- build all required target code from sources
|
||||
@@ -300,13 +325,30 @@ These ideas were first introduced here: @par
|
||||
The following architectural tasks need to be accomplished and should be
|
||||
fairly easy to complete:
|
||||
|
||||
|
||||
- use dynamic allocations for working memory. Scan & fix code
|
||||
for excessive stack allocations. take linux/scripts/checkstack.pl and
|
||||
see what the worst offenders are. Dynamic stack allocations are found
|
||||
at the bottom of the list below. Example, on amd64:
|
||||
|
||||
$ objdump -d | checkstack.pl | head -10
|
||||
0x004311e3 image_open [openocd]: 13464
|
||||
0x00431301 image_open [openocd]: 13464
|
||||
0x004237a4 target_array2mem [openocd]: 4376
|
||||
0x0042382b target_array2mem [openocd]: 4376
|
||||
0x00423e74 target_mem2array [openocd]: 4360
|
||||
0x00423ef9 target_mem2array [openocd]: 4360
|
||||
0x00404aed handle_svf_command [openocd]: 2248
|
||||
0x00404b7e handle_svf_command [openocd]: 2248
|
||||
0x00413581 handle_flash_fill_command [openocd]: 2200
|
||||
0x004135fa handle_flash_fill_command [openocd]: 2200
|
||||
- clean-up code to match style guides
|
||||
- factor code to eliminate duplicated functionality
|
||||
- rewrite code that uses casts to access 16-bit and larger types
|
||||
from unaligned memory addresses
|
||||
- libopenocd support: @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006405.html
|
||||
- review and clean up interface/target/flash APIs
|
||||
- review and clean up interface/target/flash APIs
|
||||
|
||||
The following strategic tasks will require ambition, knowledge, and time
|
||||
to complete:
|
||||
@@ -324,9 +366,11 @@ to complete:
|
||||
- Develop milestone and release guidelines, processes, and scripts.
|
||||
- Develop "style" guidelines (and scripts) for maintainers:
|
||||
- reviewing patches
|
||||
- committing to Subversion
|
||||
- Review The Guide for OpenOCD Users for documentation errors or omissions
|
||||
- Update The Manual for OpenOCD Developerrs:
|
||||
- committing to git
|
||||
- Review Users' Guide for documentation errors or omissions
|
||||
- "capture" and "ocd_find" commands
|
||||
- "ocd_" prefix on various stuff
|
||||
- Update Developer's Manual (doxygen output)
|
||||
- Add documentation describing the architecture of each module
|
||||
- Provide more Technical Primers to bootstrap contributor knowledge
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#!/bin/sh -e
|
||||
# Run the autotools bootstrap sequence to create the configure script
|
||||
|
||||
# Stop execution as soon as we have an unknown command
|
||||
set -e
|
||||
|
||||
if libtoolize --version >/dev/null 2>&1; then
|
||||
libtoolize="libtoolize"
|
||||
elif glibtoolize --version >/dev/null 2>&1; then
|
||||
|
||||
137
configure.in
137
configure.in
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.60)
|
||||
AC_INIT([openocd], [0.3.0-rc0],
|
||||
AC_INIT([openocd], [0.4.0],
|
||||
[OpenOCD Mailing List <openocd-development@lists.berlios.de>])
|
||||
AC_CONFIG_SRCDIR([src/openocd.c])
|
||||
|
||||
@@ -8,8 +8,8 @@ AM_MAINTAINER_MODE
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AH_BOTTOM([
|
||||
#include "system.h"
|
||||
#include "replacements.h"
|
||||
#include <helper/system.h>
|
||||
#include <helper/replacements.h>
|
||||
])
|
||||
|
||||
AC_LANG_C
|
||||
@@ -35,27 +35,78 @@ AC_TYPE_LONG_LONG_INT
|
||||
AC_SEARCH_LIBS([ioperm], [ioperm])
|
||||
AC_SEARCH_LIBS([dlopen], [dl])
|
||||
|
||||
AC_CHECK_HEADERS(arpa/inet.h)
|
||||
AC_CHECK_HEADERS(sys/socket.h)
|
||||
AC_CHECK_HEADERS(arpa/inet.h, [], [], [dnl
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
])
|
||||
AC_CHECK_HEADERS(elf.h)
|
||||
AC_CHECK_HEADERS(dirent.h)
|
||||
AC_CHECK_HEADERS(fcntl.h)
|
||||
AC_CHECK_HEADERS(ifaddrs.h)
|
||||
AC_CHECK_HEADERS(ifaddrs.h, [], [], [dnl
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
])
|
||||
AC_CHECK_HEADERS(malloc.h)
|
||||
AC_CHECK_HEADERS(netdb.h)
|
||||
AC_CHECK_HEADERS(netinet/in.h)
|
||||
AC_CHECK_HEADERS(netinet/tcp.h)
|
||||
AC_CHECK_HEADERS([netinet/in.h], [], [], [dnl
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
])
|
||||
AC_CHECK_HEADERS(netinet/tcp.h, [], [], [dnl
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
])
|
||||
AC_CHECK_HEADERS(pthread.h)
|
||||
AC_CHECK_HEADERS(strings.h)
|
||||
AC_CHECK_HEADERS(sys/ioctl.h)
|
||||
AC_CHECK_HEADERS(sys/param.h)
|
||||
AC_CHECK_HEADERS(sys/poll.h)
|
||||
AC_CHECK_HEADERS(sys/select.h)
|
||||
AC_CHECK_HEADERS(sys/socket.h)
|
||||
AC_CHECK_HEADERS(sys/stat.h)
|
||||
AC_CHECK_HEADERS(sys/time.h)
|
||||
AC_CHECK_HEADERS(sys/types.h)
|
||||
AC_CHECK_HEADERS(unistd.h)
|
||||
|
||||
AC_CHECK_HEADERS([net/if.h], [], [], [dnl
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
@@ -226,6 +277,24 @@ AC_ARG_WITH(ftd2xx-lib,
|
||||
with_ftd2xx_lib=static
|
||||
])
|
||||
|
||||
|
||||
AC_ARG_ENABLE(doxygen-html,
|
||||
AS_HELP_STRING([--disable-doxygen-html],
|
||||
[Disable building Doxygen manual as HTML.]),
|
||||
[doxygen_as_html=$enableval], [doxygen_as_html=yes])
|
||||
AC_SUBST(doxygen_as_html)
|
||||
AC_MSG_CHECKING([whether to build Doxygen as HTML])
|
||||
AC_MSG_RESULT($doxygen_as_html)
|
||||
|
||||
AC_ARG_ENABLE(doxygen-pdf,
|
||||
AS_HELP_STRING([--enable-doxygen-pdf],
|
||||
[Enable building Doxygen manual as PDF.]),
|
||||
[doxygen_as_pdf=$enableval], [doxygen_as_pdf=no])
|
||||
AC_SUBST(doxygen_as_pdf)
|
||||
AC_MSG_CHECKING([whether to build Doxygen as PDF])
|
||||
AC_MSG_RESULT($doxygen_as_pdf)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(gccwarnings,
|
||||
AS_HELP_STRING([--disable-gccwarnings], [Disable compiler warnings]),
|
||||
[gcc_warnings=$enableval], [gcc_warnings=yes])
|
||||
@@ -323,6 +392,14 @@ AC_ARG_ENABLE(ft2232_ftd2xx,
|
||||
AS_HELP_STRING([--enable-ft2232_ftd2xx], [Enable building support for FT2232 based devices using the FTD2XX driver from ftdichip.com]),
|
||||
[build_ft2232_ftd2xx=$enableval], [build_ft2232_ftd2xx=no])
|
||||
|
||||
AC_ARG_ENABLE(usb_blaster_libftdi,
|
||||
AS_HELP_STRING([--enable-usb_blaster_libftdi], [Enable building support for the Altera USB-Blaster using the libftdi driver, opensource alternate of FTD2XX]),
|
||||
[build_usb_blaster_libftdi=$enableval], [build_usb_blaster_libftdi=no])
|
||||
|
||||
AC_ARG_ENABLE(usb_blaster_ftd2xx,
|
||||
AS_HELP_STRING([--enable-usb_blaster_ftd2xx], [Enable building support for the Altera USB-Blaster using the FTD2XX driver from ftdichip.com]),
|
||||
[build_usb_blaster_ftd2xx=$enableval], [build_usb_blaster_ftd2xx=no])
|
||||
|
||||
AC_ARG_ENABLE(amtjtagaccel,
|
||||
AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]),
|
||||
[build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
|
||||
@@ -482,7 +559,7 @@ case $host in
|
||||
AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts])
|
||||
fi
|
||||
parport_use_giveio=yes
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO"
|
||||
|
||||
AC_DEFINE(IS_MINGW, 1, [1 if building for MinGW.])
|
||||
@@ -545,18 +622,6 @@ else
|
||||
AC_DEFINE(BUILD_ZY1000, 0, [0 if you don't want ZY1000.])
|
||||
fi
|
||||
|
||||
if test $build_ioutil = yes; then
|
||||
AC_DEFINE(BUILD_IOUTIL, 1, [1 if you want ioutils.])
|
||||
else
|
||||
AC_DEFINE(BUILD_IOUTIL, 0, [0 if you don't want ioutils.])
|
||||
fi
|
||||
|
||||
if test $build_httpd = yes; then
|
||||
AC_DEFINE(BUILD_HTTPD, 1, [1 if you want httpd.])
|
||||
else
|
||||
AC_DEFINE(BUILD_HTTPD, 0, [0 if you don't want httpd.])
|
||||
fi
|
||||
|
||||
if test $build_at91rm9200 = yes; then
|
||||
build_bitbang=yes
|
||||
AC_DEFINE(BUILD_AT91RM9200, 1, [1 if you want at91rm9200.])
|
||||
@@ -594,6 +659,20 @@ else
|
||||
AC_DEFINE(BUILD_FT2232_FTD2XX, 0, [0 if you don't want ftd2xx ft2232.])
|
||||
fi
|
||||
|
||||
if test $build_usb_blaster_libftdi = yes; then
|
||||
build_bitbang=yes
|
||||
AC_DEFINE(BUILD_USB_BLASTER_LIBFTDI, 1, [1 if you want libftdi usb_blaster.])
|
||||
else
|
||||
AC_DEFINE(BUILD_USB_BLASTER_LIBFTDI, 0, [0 if you don't want libftdi usb_blaster.])
|
||||
fi
|
||||
|
||||
if test $build_usb_blaster_ftd2xx = yes; then
|
||||
build_bitbang=yes
|
||||
AC_DEFINE(BUILD_USB_BLASTER_FTD2XX, 1, [1 if you want ftd2xx usb_blaster.])
|
||||
else
|
||||
AC_DEFINE(BUILD_USB_BLASTER_FTD2XX, 0, [0 if you don't want ftd2xx usb_blaster.])
|
||||
fi
|
||||
|
||||
if test $build_amtjtagaccel = yes; then
|
||||
AC_DEFINE(BUILD_AMTJTAGACCEL, 1, [1 if you want the Amontec JTAG-Accelerator driver.])
|
||||
else
|
||||
@@ -670,7 +749,7 @@ then
|
||||
AC_MSG_ERROR([The option: with_ftd2xx_linux_tardir is for LINUX only.])
|
||||
fi
|
||||
|
||||
if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes ; then
|
||||
if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then
|
||||
AC_MSG_CHECKING([for ftd2xx.lib exists (win32)])
|
||||
|
||||
# if we are given a zipdir...
|
||||
@@ -685,12 +764,12 @@ if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes ; then
|
||||
|
||||
# And calculate the LDFLAGS for the machine
|
||||
case "$host_cpu" in
|
||||
i?86|x86_*)
|
||||
i?86|x86_32)
|
||||
LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/i386"
|
||||
LIBS="$LIBS -lftd2xx"
|
||||
f=$with_ftd2xx_win32_zipdir/i386/ftd2xx.lib
|
||||
;;
|
||||
amd64)
|
||||
amd64|x86_64)
|
||||
LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/amd64"
|
||||
LIBS="$LIBS -lftd2xx"
|
||||
f=$with_ftd2xx_win32_zipdir/amd64/ftd2xx.lib
|
||||
@@ -922,11 +1001,13 @@ enum ftdi_chip_type x = TYPE_2232H;
|
||||
fi
|
||||
|
||||
# check for usb.h when a driver will require it
|
||||
build_usb=no
|
||||
if test $build_jlink = yes -o $build_vsllink = yes -o $build_usbprog = yes -o \
|
||||
$build_rlink = yes -o $build_armjtagew = yes
|
||||
then
|
||||
AC_CHECK_HEADERS([usb.h],[],
|
||||
[AC_MSG_ERROR([usb.h is required to build some OpenOCD driver(s)])])
|
||||
build_usb=yes
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(RELEASE, test $build_release = yes)
|
||||
@@ -942,6 +1023,8 @@ AM_CONDITIONAL(AT91RM9200, test $build_at91rm9200 = yes)
|
||||
AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
|
||||
AM_CONDITIONAL(FT2232_LIBFTDI, test $build_ft2232_libftdi = yes)
|
||||
AM_CONDITIONAL(FT2232_DRIVER, test $build_ft2232_ftd2xx = yes -o $build_ft2232_libftdi = yes)
|
||||
AM_CONDITIONAL(USB_BLASTER_LIBFTDI, test $build_usb_blaster_libftdi = yes)
|
||||
AM_CONDITIONAL(USB_BLASTER_DRIVER, test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes)
|
||||
AM_CONDITIONAL(AMTJTAGACCEL, test $build_amtjtagaccel = yes)
|
||||
AM_CONDITIONAL(GW16012, test $build_gw16012 = yes)
|
||||
AM_CONDITIONAL(PRESTO_LIBFTDI, test $build_presto_libftdi = yes)
|
||||
@@ -952,6 +1035,7 @@ AM_CONDITIONAL(JLINK, test $build_jlink = yes)
|
||||
AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
|
||||
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
|
||||
AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
|
||||
AM_CONDITIONAL(USB, test $build_usb = yes)
|
||||
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
|
||||
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
|
||||
AM_CONDITIONAL(IS_WIN32, test $is_win32 = yes)
|
||||
@@ -1057,11 +1141,14 @@ AC_OUTPUT(dnl
|
||||
src/Makefile dnl
|
||||
src/helper/Makefile dnl
|
||||
src/jtag/Makefile dnl
|
||||
src/jtag/drivers/Makefile dnl
|
||||
src/xsvf/Makefile dnl
|
||||
src/svf/Makefile dnl
|
||||
src/target/Makefile dnl
|
||||
src/server/Makefile dnl
|
||||
src/flash/Makefile dnl
|
||||
src/flash/nor/Makefile dnl
|
||||
src/flash/nand/Makefile dnl
|
||||
src/pld/Makefile dnl
|
||||
doc/Makefile dnl
|
||||
)
|
||||
|
||||
@@ -1,60 +1,68 @@
|
||||
BUS!="usb", ACTION!="add", SUBSYSTEM!=="usb_device", GOTO="openocd_rules_end"
|
||||
ACTION!="add|change", GOTO="openocd_rules_end"
|
||||
SUBSYSTEM!="usb", GOTO="openocd_rules_end"
|
||||
ENV{DEVTYPE}!="usb_device", GOTO="openocd_rules_end"
|
||||
|
||||
# Olimex ARM-USB-OCD
|
||||
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0003", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Olimex ARM-USB-OCD-TINY
|
||||
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0004", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Olimex ARM-JTAG-EW
|
||||
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="001e", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Olimex ARM-USB-OCD-TINY-H
|
||||
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev"
|
||||
|
||||
# USBprog with OpenOCD firmware
|
||||
SYSFS{idVendor}=="1781", SYSFS{idProduct}=="0c63", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Amontec JTAGkey and JTAGkey-tiny
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Amontec JTAGkey-HiSpeed
|
||||
SYSFS{idVendor}=="0fbb", SYSFS{idProduct}=="1000", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Axiom AXM-0432 Link (Symphony SoundBite?)
|
||||
# Calao Systems USB-A9260-C01
|
||||
# TinCanTools Flyswatter
|
||||
# OOCD-Link
|
||||
# Marvell Sheevaplug (early development versions)
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6010", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Calao Systems USB-A9260-C02
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
||||
|
||||
# IAR J-Link USB
|
||||
SYSFS{idVendor}=="1366", SYSFS{idProduct}=="0101", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Raisonance RLink
|
||||
SYSFS{idVendor}=="138e", SYSFS{idProduct}=="9000", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Hitex STR9-comStick
|
||||
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002c", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Hitex STM32-PerformanceStick
|
||||
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002d", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Luminary Micro Stellaris/LM3S811
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
|
||||
# TI/Luminary Stellaris Evaluation Board (several)
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
|
||||
|
||||
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Xverve Signalyzer Tool (DT-USB-ST)
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
|
||||
|
||||
# egnite Turtelizer 2
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Marvell Sheevaplug
|
||||
SYSFS{idVendor}=="9e88", SYSFS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Section5 ICEbear
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c140", MODE="664", GROUP="plugdev"
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="664", GROUP="plugdev"
|
||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
||||
|
||||
LABEL="openocd_rules_end"
|
||||
|
||||
|
||||
@@ -31,7 +31,95 @@ This section needs to be expanded to describe OpenOCD's Jim API.
|
||||
|
||||
/** @page helpercommand OpenOCD Command API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Command API.
|
||||
OpenOCD's command API allows modules to register callbacks that are then
|
||||
available to the scripting services. It provides the mechanism for
|
||||
these commands to be dispatched to the modlue using a standard
|
||||
interfaces. It provides macros for defining functions that use and
|
||||
extend this interface.
|
||||
|
||||
@section helpercmdhandler Command Handlers
|
||||
|
||||
Command handlers are functions with a particular signature, which can
|
||||
be extended by modules for passing additional parameters to helpers or
|
||||
another layer of handlers.
|
||||
|
||||
@subsection helpercmdhandlerdef Defining and Calling Command Handlers
|
||||
|
||||
These functions should be defined using the @c COMMAND_HANDLER macro.
|
||||
These methods must be defined as static, as their principle entry point
|
||||
should be the run_command dispatch mechanism.
|
||||
|
||||
Command helper functions that require access to the full set of
|
||||
parameters should be defined using the @c COMMAND_HELPER. These must be
|
||||
declared static by you, as sometimes you might want to share a helper
|
||||
among several files (e.g. @c s3c24xx_nand.h).
|
||||
|
||||
Both types of routines must be called using the @c CALL_COMMAND_HANDLER macro.
|
||||
Calls using this macro to normal handlers require the name of the command
|
||||
handler (which can a name or function pointer). Calls to helpers and
|
||||
derived handlers must pass those extra parameters specified by their
|
||||
definitions; however, lexical capture is used for the core parameters.
|
||||
This dirty trick is being used as a stop-gap measure while the API is
|
||||
migrated to one that passes a pointer to a structure containing the
|
||||
same ingredients. At that point, this macro will be removed and callers
|
||||
will be able to use direct invocations.
|
||||
|
||||
Thus, the following macros can be used to define and call command
|
||||
handlers or helpers:
|
||||
|
||||
- @c COMMAND_HANDLER - declare or define a command handler.
|
||||
- @c COMMAND_HELPER - declare or define a derived command handler or helper.
|
||||
- @c CALL_COMMAND_COMMAND - call a command handler/helper.
|
||||
|
||||
@subsection helpercmdhandlermacros Command Handler Macros
|
||||
|
||||
In addition, the following macros may be used in the context of
|
||||
command handlers and helpers:
|
||||
- @c CMD_CTX - the current @c command_context
|
||||
- @c CMD_NAME - invoked command name
|
||||
- @c CMD_ARGC - the number of command arguments
|
||||
- @c CMD_ARGV - array of command argument strings
|
||||
|
||||
@section helpercmdregister Command Registration
|
||||
|
||||
In order to use a command handler, it must be registered with the
|
||||
command subsystem. All commands are registered with command_registration
|
||||
structures, specifying the name of the command, its handler, its allowed
|
||||
mode(s) of execution, and strings that provide usage and help text.
|
||||
A single handler may be registered using multiple names, but any name
|
||||
may have only one handler associated with it.
|
||||
|
||||
The @c register_commands() and @c register_commands() functions provide
|
||||
registration, while the @c unregister_command() and
|
||||
@c unregister_all_commands() functions will remove existing commands.
|
||||
These may be called at any time, allowing the command set to change in
|
||||
response to system actions.
|
||||
|
||||
@subsection helpercmdjim Jim Command Registration
|
||||
|
||||
The command_registration structure provides support for registering
|
||||
native Jim command handlers (@c jim_handler) too. For these handlers,
|
||||
the module can provide help and usage support; however, this mechanism
|
||||
allows Jim handlers to be called as sub-commands of other commands.
|
||||
These commands may be registered with a private data value (@c
|
||||
jim_handler_data) that will be available when called, as with low-level
|
||||
Jim command registration.
|
||||
|
||||
A command may have a normal @c handler or a @c jim_handler, but not both.
|
||||
|
||||
@subsection helpercmdregisterchains Command Chaining
|
||||
|
||||
When using register_commands(), the array of commands may reference
|
||||
other arrays. When the @c chain field is filled in a
|
||||
command_registration record, the commands on in the chained list will
|
||||
added in one of two places. If the record defines a new command, then
|
||||
the chained commands are added under it; otherwise, the commands are
|
||||
added in the same context as the other commands in the array.
|
||||
|
||||
@section helpercmdprimer Command Development Primer
|
||||
|
||||
This @ref primercommand provides details about the @c hello module,
|
||||
showing how the pieces desrcribed on this page fit together.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** @mainpage OpenOCD Reference Manual
|
||||
/** @mainpage OpenOCD Developer's Guide
|
||||
|
||||
Welcome to the OpenOCD Reference Manual -- the developer's resource for
|
||||
Welcome to the OpenOCD Developer's Guide -- the developer's resource for
|
||||
learning about the internal architecture of the OpenOCD project. @par
|
||||
|
||||
In addition, this document contains the tactical and strategic plans
|
||||
@@ -42,11 +42,17 @@ associated with the fundamental technologies used by OpenOCD.
|
||||
- @subpage primertcl
|
||||
- @subpage primerjtag
|
||||
|
||||
These documents should bridge any "ancillary" gaps in contributor
|
||||
The above documents should bridge any "ancillary" gaps in contributor
|
||||
knowledge, without having to learn the complete languages or technology.
|
||||
They should provide enough information for experienced developers to
|
||||
learn how to make "correct" changes when creating patches.
|
||||
|
||||
Beyond the fundamentals, the following primers provide introductory
|
||||
tutorials for OpenOCD's sub-systems. These complement the @ref oocd
|
||||
pages that provide more high-level perspective on related topics.
|
||||
|
||||
- @subpage primercommand
|
||||
|
||||
In all cases, these Primers should use idiomatic conventions that the
|
||||
community has agreed are the "right way of doing things". In this
|
||||
respect, these documents typically assume some familiarity with the
|
||||
|
||||
138
doc/manual/primer/commands.txt
Normal file
138
doc/manual/primer/commands.txt
Normal file
@@ -0,0 +1,138 @@
|
||||
/** @page primercommand Command Development Primer
|
||||
|
||||
This page provides a primer for writing commands by introducing @c hello
|
||||
module. The full source code used in this example can be found in
|
||||
hello.c, and the @ref primercmdcode section shows how to use it.
|
||||
|
||||
A summary of this information can be found in @ref helpercommand .
|
||||
|
||||
@section primercmdhandler Command Handlers
|
||||
|
||||
Defining new commands and their helpers is easy. The following code
|
||||
defines a simple command handler that delegates its argument parsing:
|
||||
@code
|
||||
COMMAND_HANDLER(handle_hello_command)
|
||||
{
|
||||
const char *sep, *name;
|
||||
int retval = CALL_COMMAND_HANDLER(handle_hello_args);
|
||||
if (ERROR_OK == retval)
|
||||
command_print(CMD_CTX, "Greetings%s%s!", sep, name);
|
||||
return retval;
|
||||
}
|
||||
@endcode
|
||||
|
||||
Here, the @c COMMAND_HANDLER macro establishes the function signature,
|
||||
see in command.h by the @c __COMMAND_HANDLER macro.
|
||||
|
||||
The COMMAND_HELPER macro function allows defining functions with an
|
||||
extended version of the base signature. These helper functions can be
|
||||
called (with the appropriate parameters), the @c CALL_COMMAND_HANDLER
|
||||
macro to pass any e as parameters to the following helper function:
|
||||
|
||||
The subsequent blocks of code are a normal C function that can do
|
||||
anything, so only complex commands deserve should use comamnd helper
|
||||
functions. In this respect, this example uses one to demonstrate how --
|
||||
not when -- they should be used.
|
||||
|
||||
@code
|
||||
static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name)
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
LOG_ERROR("%s: too many arguments", CMD_NAME);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
if (1 == CMD_ARGC)
|
||||
{
|
||||
*sep = ", ";
|
||||
*name = CMD_ARGV[0];
|
||||
}
|
||||
else
|
||||
*sep = *name = "";
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@endcode
|
||||
|
||||
Of course, you may also call other macros or functions, but that extends
|
||||
beyond the scope of this tutorial on writing commands.
|
||||
|
||||
@section primercmdreg Command Registration
|
||||
|
||||
Before this new function can be used, it must be registered somehow.
|
||||
For a new module, registering should be done in a new function for
|
||||
the purpose, which must be called from @c openocd.c:
|
||||
@code
|
||||
|
||||
static const struct command_registration hello_command_handlers[] = {
|
||||
{
|
||||
.name = "hello",
|
||||
.mode = COMMAND_ANY,
|
||||
.handler = handle_hello_command,
|
||||
.help = "print a warm greeting",
|
||||
.usage = "[name]",
|
||||
},
|
||||
{
|
||||
.chain = foo_command_handlers,
|
||||
}
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
int hello_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL, handle_command_handlers);
|
||||
}
|
||||
@endcode
|
||||
|
||||
Note that the "usage" text should use the same EBNF that's found
|
||||
in the User's Guide: literals in 'single quotes', sequences of
|
||||
optional parameters in [square brackets], and alternatives in
|
||||
(parentheses|with|vertical bars), and so forth. No angle brackets.
|
||||
|
||||
That's it! The command should now be registered and available to scripts.
|
||||
|
||||
@section primercmdchain Command Chaining
|
||||
|
||||
This example also shows how to chain command handler registration, so
|
||||
your modules can "inherit" commands provided by other (sub)modules.
|
||||
Here, the hello module includes the foo commands in the same context
|
||||
that the 'hello' command will be registered.
|
||||
|
||||
If the @c chain field had been put in the 'hello' command, then the
|
||||
@c foo module commands would be registered under it. Indeed, that
|
||||
technique is used to define the 'foo bar' and 'foo baz' commands,
|
||||
as well as for the example drivers that use these modules.
|
||||
|
||||
The code for the 'foo' command handlers can be found in @c hello.c.
|
||||
|
||||
@section primercmdcode Trying These Example Commands
|
||||
|
||||
These commands have been inherited by the dummy interface, faux flash,
|
||||
and testee target drivers. The easiest way to test these is by using the
|
||||
dummy interface.
|
||||
|
||||
Once OpenOCD has been built with this example code, the following command
|
||||
demonstrates the abilities that the @c hello module provides:
|
||||
@code
|
||||
openocd -c 'interface dummy' \
|
||||
-c 'dummy hello' \
|
||||
-c 'dummy hello World' \
|
||||
-c 'dummy hello {John Doe}' \
|
||||
-c 'dummy hello John Doe' # error: too many arguments
|
||||
@endcode
|
||||
|
||||
If saved in @c hello.cfg, then running <code>openocd -f hello.cfg</code>
|
||||
should produce the following output before displaying the help text and
|
||||
exiting:
|
||||
@code
|
||||
Greetings!
|
||||
Greetings, World!
|
||||
Greetings, John Doe!
|
||||
Error: hello: too many arguments
|
||||
Runtime error, file "openocd.cfg", line 14:
|
||||
hello: too many arguments
|
||||
dummy hello [<name>]
|
||||
prints a warm welcome
|
||||
@endcode
|
||||
|
||||
*/
|
||||
@@ -10,7 +10,7 @@ This page provides an introduction to the OpenOCD Release Processes:
|
||||
activities for each release cycle.
|
||||
- @ref releasehow - Outlines all of the steps for the
|
||||
processes used to produce and release the package source archives.
|
||||
- @ref releasescript - Introduces the automated @c release.sh script.
|
||||
- @ref releasescriptcmds - Introduces the automated @c release.sh script.
|
||||
|
||||
@section releasewhy Why Produce Releases?
|
||||
|
||||
@@ -25,14 +25,21 @@ release, this command will package the tree into several popular archive
|
||||
formats: <code>openocd-\<version\>.{tar.gz,tar.bz2,zip}</code>. If
|
||||
produced properly, these files are suitable for release to the public.
|
||||
|
||||
When released for users, these archives present several important
|
||||
advantages when contrasted to using the git repository:
|
||||
When properly versioned and released for users, these archives present
|
||||
several important advantages compared to using the source repository
|
||||
(including snapshots downloaded from that repository using gitweb):
|
||||
|
||||
-# They allow others to package and distribute the code.
|
||||
-# They build easier for developers, because they contain
|
||||
a working configure script that was produced by the Release Manager.
|
||||
-# They prevent users from trying a random work-in-process revision.
|
||||
-# They free developers from answering questions about mainline breakage.
|
||||
-# They allow others to package and distribute the code using
|
||||
consistent version labels. Users won't normally need to care
|
||||
whose package they use, just the version of OpenOCD.
|
||||
-# They contain a working configure script and makefiles, which
|
||||
were produced as part of creating the archive.
|
||||
-# Because they have been formally released by the project, users
|
||||
don't need to try a random work-in-process revision. Releasing
|
||||
involves spending some time specifically on quality improvments,
|
||||
including bugfixing source code and documentation.
|
||||
-# They provide developers with the flexibility needed to address
|
||||
larger issues, which sometimes involves temporary breakage.
|
||||
|
||||
Hopefully, this shows several good reasons to produce regular releases,
|
||||
but the release processes were developed with some additional design
|
||||
@@ -45,66 +52,112 @@ following properties:
|
||||
-# Allow scheduling and automation of building and publishing milestones.
|
||||
|
||||
The current release processes are documented in the following sections.
|
||||
They attempt to meet these design goals, but there may improvements
|
||||
remaining to be made toward automating the process.
|
||||
They attempt to meet these design goals, but improvements may still
|
||||
need to be made.
|
||||
|
||||
@section releaseversions Release Versions
|
||||
@subsection version_labels Version Labels
|
||||
|
||||
Users can display the OpenOCD version string in at least two
|
||||
ways. The command line <code>openocd -v</code> invocation
|
||||
displays it; as does the Tcl <code>version</code> command.
|
||||
|
||||
Labels for released versions look like <em>0.3.0</em>, or
|
||||
<em>0.3.0-rc1</em> for a preliminary release.
|
||||
Non-released (developer) versions look like <em>0.3.0-dev</em>,
|
||||
or <em>0.3.0-rc1-dev</em>.
|
||||
In all cases, additional tags may be appended to those base
|
||||
release version labels.
|
||||
|
||||
The <code>tools/release/version.sh</code> script is used to
|
||||
manipulate version IDs found in the source tree.
|
||||
|
||||
@subsubsection releaseversions Release Versions and Tags
|
||||
|
||||
The OpenOCD version string is composed of three numeric components
|
||||
separated by two decimal points: @c x.y.z, where @c x is the @a major
|
||||
version number, @c y is the @a minor number, and @c z is the @a micro.
|
||||
|
||||
For a <i>bug-fix</i> release, the micro version number will be non-zero
|
||||
For any <em>bug-fix</em> release, the micro version number will be non-zero
|
||||
(<code>z > 0</code>). For a <i>minor release</i>, the micro version
|
||||
number will be zero (<code>z = 0</code>). For a <i>major releases</i>,
|
||||
the minor version will @a also be zero (<code>y = 0, z = 0</code>).
|
||||
|
||||
@subsection releaseversiontags Version Tags
|
||||
After these required numeric components, release version strings
|
||||
may contain tags such as as <em>-rc1</em> or <em>-rc2</em>.
|
||||
These 'rc' tags indicate "release candidate" versions of the package.
|
||||
Like the major/minor/micro numbers, these tags will be manipulated
|
||||
by the automated release process.
|
||||
|
||||
After these required numeric components, the version string may contain
|
||||
one or more <i>version tags</i>, such as '-rc1' or '-dev'.
|
||||
The release process includes version number manipulations to the tree
|
||||
being released, ensuring that all numbers are incremented (or rolled
|
||||
over) at the right time and in the proper locations of the repository.
|
||||
One of those manipulations creates a repository tag matching that
|
||||
release's version label.
|
||||
|
||||
Mainline and all branches should have the tag '-dev' in
|
||||
their version number. This tag helps developers identify reports
|
||||
created from the git repository, and it can be detected and
|
||||
manipulated by the release script. Specifically, this tag will be
|
||||
removed and re-added during the release process; it should never be
|
||||
manipulated by developers in submitted patches.
|
||||
|
||||
The 'rc' tags indicate a "release candidate" version of the package.
|
||||
This tag will also be manipulated by the automated release process.
|
||||
|
||||
Additional tags may be used as necessary.
|
||||
|
||||
@subsection releaseversionsdist Packager Versions
|
||||
@subsubsection releaseversionsdist Packager Versions
|
||||
|
||||
Distributors of patched versions of OpenOCD are encouraged to extend the
|
||||
version string with a unique version tag when producing external
|
||||
releases, as this helps to identify your particular distribution series.
|
||||
Knowing that a release has such patches can be essential to tracking
|
||||
down and fixing bugs.
|
||||
|
||||
For example, the following command will add a 'foo1' tag to the
|
||||
configure.in script of a local copy of the source tree:
|
||||
Packager version tags should always be suffixes to the version
|
||||
code from the OpenOCD project, signifying modifications to the
|
||||
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
|
||||
a version label like <em>0.3.0-foo</em>:
|
||||
|
||||
@code
|
||||
tools/release.sh version bump tag foo
|
||||
tools/release/version.sh version tag add foo
|
||||
@endcode
|
||||
|
||||
This command will modify the configure.in 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. The same command can be
|
||||
used each time the derived package is released, incrementing the tag's
|
||||
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
|
||||
patches you are providing.
|
||||
|
||||
You can also "bump" those tags (so "foo1" becomes "foo2" etc)
|
||||
each time a derived package is released, incrementing the tag's
|
||||
version to facilitate tracking the changes you have distributed.
|
||||
|
||||
@subsection releaseversionhow Version Processes
|
||||
@code
|
||||
tools/release/version.sh version bump tag foo
|
||||
@endcode
|
||||
|
||||
The release process includes version number manipulations to the tree
|
||||
being released, ensuring that all numbers are incremented at the right
|
||||
time and in the proper locations of the repository.
|
||||
Of course, any patches in your branches must be provided to
|
||||
your customers, and be in conformance with the GPL. In most
|
||||
cases you should also work to merge your improvements to the
|
||||
mainline tree.
|
||||
|
||||
The version numbers for any branch should increase monotonically
|
||||
to the next successive integer, except when reset to zero
|
||||
during major or minor releases. The community should decide when
|
||||
major and minor milestones will be released.
|
||||
@subsubsection version_tags Development Versions and Tags
|
||||
|
||||
Everything except formal releases should have the tag <em>-dev</em>
|
||||
in their version number. This helps developers identify reports
|
||||
created from non-release versions, and it can be detected and
|
||||
manipulated by the release script. Specifically, this tag will be
|
||||
removed and re-added during the release process; it should never be
|
||||
manipulated by developers in submitted patches.
|
||||
|
||||
Versions built from developer trees may have additional tags.
|
||||
Trees built from git snapshots have <em>snapshot</em> tags.
|
||||
When built from a "live" git tree, tags specify
|
||||
specific git revisions:
|
||||
|
||||
0.3.0-rc1-dev-00015-gf37c9b8-dirty
|
||||
|
||||
indicates a development tree based on git revison f37c9b8
|
||||
(a truncated version of a SHA1 hash) with some non-git
|
||||
patches applied (the <em>dirty</em> tag). This information
|
||||
can be useful when tracking down bugs.
|
||||
(Note that at this writing, the tags do not directly
|
||||
correspond to <code>git describe</code> output. The
|
||||
hash ID can be used with <code>git show</code>, but
|
||||
the relevant repository tag isn't <em>0.3.0-rc1-dev</em>;
|
||||
this might change in the future.)
|
||||
|
||||
@section releasewho Release Manager
|
||||
|
||||
@@ -132,14 +185,23 @@ the changes to the package version, though the release tools should
|
||||
manage the tasks of adding or removing any required development branch
|
||||
tags and incrementing the version.
|
||||
|
||||
These responsibilities matter most towards the end of the release
|
||||
cycle, when the RM creates the first RC and all contributors enter
|
||||
a quality-improvement mode. The RM works with other contributors
|
||||
to make sure everyone knows what kinds of fixes should merge, the
|
||||
status of major issues, and the release timetable.
|
||||
|
||||
In particular, the RM has the final decision on whether a given
|
||||
bug should block the release.
|
||||
|
||||
@section releasewhen Release Schedule
|
||||
|
||||
The OpenOCD release process must be carried out on a periodic basis, so
|
||||
the project can realize the benefits presented in answer to the question,
|
||||
@ref releasewhy.
|
||||
|
||||
Starting with the 0.2.0 release, the OpenOCD project should produce a
|
||||
new minor release every month or two, with a major release once a year.
|
||||
Starting with the 0.2.0 release, the OpenOCD project expects to produce
|
||||
new releases every few months.
|
||||
Bug fix releases could be provided more frequently. These release
|
||||
schedule goals may be adjusted in the future, after the project
|
||||
maintainers and distributors receive feedback and experience.
|
||||
@@ -155,16 +217,26 @@ beginning of the development cycle through the delivery of the new
|
||||
release. This section presents guidelines for scheduling key points
|
||||
where the community must be informed of changing conditions.
|
||||
|
||||
If T is the time of the next release, then the following schedule
|
||||
might describe some of the key milestones of the new release cycle:
|
||||
If Tn is the time of release n, then the following schedule
|
||||
might describe some key T0-to-T1 release cycle milestones.
|
||||
|
||||
- T minus one month: start of new development cycle
|
||||
- T minus two weeks: announce pending mainline closure to new work
|
||||
- T minus one week: close mainline to new work, begin testing phase
|
||||
- T minus two days: call for final bug fixes
|
||||
- T minus one day: produce -rc packages and distribute to testers
|
||||
- T minus one hour: produce final packages and post on-line
|
||||
- T minus zero: Announce the release to our mailing list and the world.
|
||||
- T0 ... End of T0 release cycle. T1 cycle starts, with merge
|
||||
window opening. Developers begin to merge queued work.
|
||||
- <em>... several weeks of merge window ...</em>
|
||||
- RC1 ... Close mainline to new work. Produce RC1
|
||||
release, begin testing phase; developers are in "bugfix mode",
|
||||
all other work is queued; send out planned endgame schedule.
|
||||
- RC2 ... Produce RC2 and send schedule update to
|
||||
mailing list, listing priorities for remaining fixes
|
||||
- <em>... more RC milestones, until ready ...</em>
|
||||
- T1: End of T1 release cycle. T2 cycle starts, with merge
|
||||
window opening. Developers begin to merge queued work.
|
||||
|
||||
Note that until it happens, any date for T1 is just a goal.
|
||||
Critical bugs prevent releases from happening. We are just
|
||||
beginning to use this window-plus-RCs process, so the lengths
|
||||
of the merge windows versus the RC phase is subject to change.
|
||||
Most projects have RC phases of a month or more.
|
||||
|
||||
Some additional supplemental communication will be desirable. The above
|
||||
list omits the step-by-step instructions to daily release management.
|
||||
@@ -176,29 +248,21 @@ The next section explains why the OpenOCD project allows significant
|
||||
flexibility in the part of the development that precedes the release
|
||||
process.
|
||||
|
||||
@note The OpenOCD project does not presently produce -rc packages. As
|
||||
such, the step suggested in the list above should be read as trying to
|
||||
stimulate others to test the project build and packaging on as many
|
||||
platforms as possible. This proposition will be palatable once release
|
||||
management tools have been committed to the tree.
|
||||
|
||||
@subsection releasewhenflex Schedule Flexibility
|
||||
|
||||
The Release Manager should attempt to follow the guidelines in this
|
||||
document, but the process of scheduling each release milestone should be
|
||||
community driven at the start. By the end, missing features that were
|
||||
scheduled for a release must be dropped by the Release Manager, rather
|
||||
than allowing the release cycle to be delayed while waiting for them.
|
||||
community driven at the start. Features that don't complete before
|
||||
the merge window closes can be held (perhaps in some branch) until
|
||||
the next merge window opens, rather than delaying the release cycle.
|
||||
|
||||
Despite any assurances this schedule may appear to give, the Release
|
||||
The Release
|
||||
Manager cannot schedule the work that will be done on the project,
|
||||
when it will be submitted, reviewed, and deemed suitable to be committed.
|
||||
In this way, the RM cannot act as a priest in a cathedral; OpenOCD uses
|
||||
That is, the RM cannot act as a priest in a cathedral; OpenOCD uses
|
||||
the bazaar development model. The release schedule must adapt
|
||||
continuously in response to changes in the rate of churn.
|
||||
|
||||
In particular, the suggested period of "one or two month" reflects some
|
||||
expectation of a fairly high rate of development. Fewer releases may be
|
||||
continuously in response to changes in the rate of work.
|
||||
Fewer releases may be
|
||||
required if developers contribute less patches, and more releases may be
|
||||
desirable if the project continues to grow and experience high rates of
|
||||
community contribution. During each cycle, the RM should be tracking
|
||||
@@ -206,49 +270,52 @@ the situation and gathering feedback from the community.
|
||||
|
||||
@section releasehow Release Process: Step-by-Step
|
||||
|
||||
The release process may require a few iterations to work out any bugs.
|
||||
Even with the release script, some steps require clear user intervention
|
||||
-- and not only by the Release Manager.
|
||||
The release process is not final; it may need more iterations
|
||||
to work out bugs.
|
||||
While there are release scripts, key steps require community
|
||||
support; the Release Manager isn't the only participant.
|
||||
|
||||
The following steps should be followed to produce each release:
|
||||
|
||||
-# Produce final manual patches to mainline (or release branch):
|
||||
-# Produce final patches to mainline (or a release branch). Nobody
|
||||
except the RM should be committing anything.
|
||||
-# Finalize @c NEWS file to describe the changes in the release
|
||||
- This file is Used to automatically post "blurbs" about the project.
|
||||
- This file is used to automatically post "blurbs" about the project.
|
||||
- This material should be produced during the development cycle.
|
||||
- Add a new item for each @c NEWS-worthy contribution, when committed.
|
||||
-# Bump library version if our API changed (not yet required)
|
||||
-# Produce and tag the final revision in the git repository:
|
||||
- Update and commit the final package version in @c configure.in :
|
||||
-# Remove @c -dev tag.
|
||||
-# Remove @c -rc tag, if producing the final release from an -rc series.
|
||||
- Tags must be named consistently:
|
||||
@verbatim
|
||||
@endverbatim
|
||||
- Tag the final commit with a consistent GIT tag name and message:
|
||||
-# Update and commit the final package version in @c configure.in:
|
||||
<code>tools/release/version.sh</code> may help ensure the versions
|
||||
are named consistently:
|
||||
-# Remove @c -dev tag.
|
||||
-# Update the @c -rc tag:
|
||||
- If producing the final release from an -rc series, remove it
|
||||
- If producing the first RC in a series, add rc1
|
||||
- If producing the next RC in a series, bump the rc number
|
||||
-# Commit that version change.
|
||||
-# 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>
|
||||
where relevant):
|
||||
@verbatim
|
||||
PACKAGE_VERSION="x.y.z"
|
||||
PACKAGE_TAG="v${PACKAGE_VERSION}"
|
||||
git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||
@endverbatim
|
||||
-# Prepare to resume normal development on the branch:
|
||||
- Restore @c -dev and -@c -rc0 version tags.
|
||||
- To start a new major (or minor) release cycle on the @c master branch:
|
||||
- Bump major (or minor) package version, zeroing sub-components.
|
||||
- Add -rc0 version tag:
|
||||
- This insures casual releases from GIT always increase monotonically.
|
||||
- For example, a major increment after releasing 1.2.3 starts 2.0.0-rc0-dev.
|
||||
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
|
||||
- Create a new @c NEWS file for the next release
|
||||
- To start a bug-fix release on a non-master branch:
|
||||
-# Bump bug-fix version.
|
||||
- To start another release candidate on a major or minor branch:
|
||||
-# Bump rc tag.
|
||||
-# Prepare to resume normal development on mainline (major or minor release)
|
||||
- Update the version label
|
||||
- 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
|
||||
and zero its minor number
|
||||
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
|
||||
- Create a new @c NEWS file for the next release
|
||||
- Commit those changes, and push the commit and the release tag
|
||||
to mainline.
|
||||
-# Produce the package source archives:
|
||||
-# Start with a clean working copy, used for producing releases only.
|
||||
-# <em>Start with a new clone of the source tree</em>, with the
|
||||
release's tag. This is used only for producing these packages.
|
||||
-# Checkout the appropriate tag:
|
||||
<code>git checkout $(git tag ) "${PACKAGE_VERSION}"</code>
|
||||
-# Produce a ChangeLog for the release (using @c git2cl).
|
||||
<code>git checkout "${PACKAGE_VERSION}"</code>
|
||||
-# @c bootstrap, @c configure, and @c make the package.
|
||||
-# Run <code>make distcheck</code> to produce the distribution archives.
|
||||
-# Run <code>make maintainer-clean</code> verify the repository is empty.
|
||||
@@ -257,8 +324,7 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||
- Allow users to access the documentation for each of our releases.
|
||||
- Place static copies of the following files on the project website:
|
||||
- @c NEWS: to provide a blurb for each release
|
||||
- @c ChangeLog: to show exactly what has been changed
|
||||
- User Guide, Developer Manual: to allow easy on-line viewing
|
||||
- User's Guide, Developer Manual: to allow easy on-line viewing
|
||||
-# Upload packages and post announcements of their availability:
|
||||
-# Release packages into files section of project sites:
|
||||
- SF.net:
|
||||
@@ -271,7 +337,7 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||
- .zip: Windows
|
||||
- Berlios:
|
||||
-# Create the new release for the new version.
|
||||
-# Provide @c NEWS and ChangeLog files, as requested.
|
||||
-# Provide @c NEWS file, as requested.
|
||||
-# Upload files via FTP to ftp://ftp.berlios.de/incoming/
|
||||
-# Edit descriptions for each file.
|
||||
-# Click button to send E-mail Release Notice.
|
||||
@@ -279,24 +345,23 @@ git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||
-# Announce updates on freshmeat.net and other trackers.
|
||||
-# Submit big updates to news feeds (e.g. Digg, Reddit, etc.).
|
||||
|
||||
@section releasescript The Release Script
|
||||
|
||||
Many of the processes described in the last section are no longer
|
||||
entrusted to humans. Instead, the @c release.sh script provides
|
||||
automation of the mechanical steps.
|
||||
|
||||
Presently, the @c release.sh script automates steps 2 through 4,
|
||||
allowing the Release Manager from perform these tasks in easy steps.
|
||||
|
||||
The following task still need to be automated:
|
||||
|
||||
- Step 5: produce documentation for website using released source archive.
|
||||
- Step 6(a): package archive upload process.
|
||||
- Step 6(b): package announcement e-mail process.
|
||||
- Step 6(c): post files and announce them using releaseforge.
|
||||
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
|
||||
-# 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.)
|
||||
-# Commit and push those patches.
|
||||
-# When desired, release as above ... except note that the next
|
||||
release of a bugfix branch is never a new major or minor release
|
||||
|
||||
@subsection releasescriptcmds Release Script Commands
|
||||
|
||||
The @c release.sh script automates some of the steps involved
|
||||
in making releases, simplifying the Release Manager's work.
|
||||
|
||||
The release script can be used for two tasks:
|
||||
- Creating releases and starting a new release cycle:
|
||||
@code
|
||||
@@ -334,7 +399,7 @@ affect its behavior:
|
||||
|
||||
@section releasetutorial Release Tutorials
|
||||
|
||||
This section should contain a brief tutorial for using the Release
|
||||
This section should contain a brief tutorial for using the Release
|
||||
Script to perform release tasks, but the new script needs to be
|
||||
used for 0.3.0.
|
||||
|
||||
|
||||
@@ -320,6 +320,6 @@ openocd -s /usr/local/share/openocd -f httpd/httpd.tcl -f interface/dummy.cfg -f
|
||||
|
||||
Navigate to: http://localhost:8888/
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -66,8 +66,9 @@ Finally, try to avoid lines of code that are longer than than 72-80 columns:
|
||||
- most identifiers must use lower-case letters (and digits) only.
|
||||
- macros must use upper-case letters (and digits) only.
|
||||
- OpenOCD identifiers should NEVER use @c MixedCaps.
|
||||
- structure names must end with the '_s' suffix.
|
||||
- typedef names must end with the '_t' suffix.
|
||||
- @c typedef names must end with the '_t' suffix.
|
||||
- This should be reserved for types that should be passed by value.
|
||||
- Do @b not mix the typedef keyword with @c struct.
|
||||
- use underline characters between consecutive words in identifiers
|
||||
(e.g. @c more_than_one_word).
|
||||
|
||||
@@ -77,8 +78,11 @@ Finally, try to avoid lines of code that are longer than than 72-80 columns:
|
||||
- @c // comments -- in new code, prefer these for single-line comments
|
||||
- trailing comma allowed in enum declarations
|
||||
- designated initializers (@{ .field = value @})
|
||||
- variables declarations may be mixed with code
|
||||
- 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
|
||||
or variable length arrays on the stack. non-MMU hosts(uClinux) and
|
||||
pthreads require modest and predictable stack usage.
|
||||
|
||||
@section styletypes Type Guidelines
|
||||
- use native types (@c int or @c unsigned) if the type is not important
|
||||
@@ -176,7 +180,7 @@ The following guidelines apply to all Doxygen comment blocks:
|
||||
-# @c function_name() can be used to reference functions
|
||||
(e.g. flash_set_dirty()).
|
||||
-# @c struct_name::member_name should be used to reference structure
|
||||
fields in the documentation (e.g. @c flash_driver_s::name).
|
||||
fields in the documentation (e.g. @c flash_driver::name).
|
||||
-# URLS get converted to markup automatically, without any extra effort.
|
||||
-# new pages can be linked into the heirarchy by using the @c \@subpage
|
||||
command somewhere the page(s) under which they should be linked:
|
||||
@@ -304,7 +308,7 @@ For technical reference material:
|
||||
- Else it's a "Config Command" if it must be used before the
|
||||
configuration stage completes.
|
||||
- For a "Driver", list its name.
|
||||
- Use BNF style regular expressions to define parameters:
|
||||
- Use EBNF style regular expressions to define parameters:
|
||||
brackets around zero-or-one choices, parentheses around
|
||||
exactly-one choices.
|
||||
- Use \@option, \@file, \@var and other mechanisms where appropriate.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH "OPENOCD" "1" "January 08, 2009"
|
||||
.TH "OPENOCD" "1" "November 24, 2009"
|
||||
.SH "NAME"
|
||||
openocd \- A free and open on\-chip debugging, in\-system programming and
|
||||
boundary\-scan testing tool for ARM and MIPS systems
|
||||
@@ -22,19 +22,23 @@ please check the \fIopenocd\fR info page for the complete list.
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.B "\-f, \-\-file <filename>"
|
||||
Use configuration file
|
||||
.BR <filename> .
|
||||
This is a shortcut for a \fB\-c "[script \fI<filename>\fB]"\fR
|
||||
command, using a search path to load the configuration file
|
||||
.IR <filename> .
|
||||
In order to specify multiple config files, you can use multiple
|
||||
.B \-\-file
|
||||
arguments. If this option is omitted, the config file
|
||||
arguments. If no such \fB\-c\fR
|
||||
options are included, the first config file
|
||||
.B openocd.cfg
|
||||
in the current working directory will be used.
|
||||
in the search path will be used.
|
||||
.TP
|
||||
.B "\-s, \-\-search <dirname>"
|
||||
Search for config files and scripts in the directory
|
||||
.BR <dirname> .
|
||||
If this option is omitted, OpenOCD searches for config files and scripts
|
||||
in the current directory.
|
||||
Add
|
||||
.I <dirname>
|
||||
to the search path used for config files and scripts.
|
||||
The search path begins with the current directory,
|
||||
then includes these additional directories before other
|
||||
components such as the standard OpenOCD script libraries.
|
||||
.TP
|
||||
.B "\-d, \-\-debug <debuglevel>"
|
||||
Set debug level. Possible values are:
|
||||
@@ -52,13 +56,17 @@ The default level is
|
||||
.TP
|
||||
.B "\-l, \-\-log_output <filename>"
|
||||
Redirect log output to the file
|
||||
.BR <filename> .
|
||||
.IR <filename> .
|
||||
Per default the log output is printed on
|
||||
.BR stderr .
|
||||
.TP
|
||||
.B "\-c, \-\-command <cmd>"
|
||||
Run the command
|
||||
.BR <cmd> .
|
||||
Add the command
|
||||
.I <cmd>
|
||||
to a list of commands executed on server startup.
|
||||
Note that you will need to explicitly invoke
|
||||
.I init
|
||||
if the command requires access to a target or flash.
|
||||
.TP
|
||||
.B "\-p, \-\-pipe"
|
||||
Use pipes when talking to gdb.
|
||||
@@ -69,9 +77,7 @@ Show a help text and exit.
|
||||
.B "\-v, \-\-version"
|
||||
Show version information and exit.
|
||||
.SH "BUGS"
|
||||
Please report any bugs at
|
||||
.B http://developer.berlios.de/bugs/?group_id=4148
|
||||
or on the mailing list
|
||||
Please report any bugs on the mailing list at
|
||||
.BR openocd\-development@lists.berlios.de .
|
||||
.SH "LICENCE"
|
||||
.B OpenOCD
|
||||
@@ -90,9 +96,6 @@ and
|
||||
programs are properly installed at your site, the command
|
||||
.B info openocd
|
||||
should give you access to the complete manual.
|
||||
.PP
|
||||
Also, the OpenOCD wiki contains some more information and examples:
|
||||
.B http://openfacts.berlios.de/index-en.phtml?title=Open_On-Chip_Debugger
|
||||
.SH "AUTHORS"
|
||||
Please see the file AUTHORS.
|
||||
.PP
|
||||
|
||||
1405
doc/openocd.texi
1405
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
Some of these binaries are build & linked using eCos.
|
||||
Some of these binaries are build & linked using eCos.
|
||||
|
||||
For source for the flash drivers, see:
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
SUBDIRS = helper jtag xsvf svf target server flash pld
|
||||
SUBDIRS = \
|
||||
helper \
|
||||
jtag \
|
||||
target \
|
||||
flash \
|
||||
svf \
|
||||
xsvf \
|
||||
pld \
|
||||
server
|
||||
|
||||
lib_LTLIBRARIES = libopenocd.la
|
||||
bin_PROGRAMS = openocd
|
||||
@@ -12,19 +20,20 @@ endif
|
||||
openocd_SOURCES = $(MAINFILE)
|
||||
openocd_LDADD = libopenocd.la
|
||||
|
||||
libopenocd_la_SOURCES = openocd.c
|
||||
libopenocd_la_SOURCES = \
|
||||
hello.c \
|
||||
openocd.c \
|
||||
startup_tcl.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
hello.h \
|
||||
openocd.h
|
||||
|
||||
|
||||
# set the include path found by configure
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag \
|
||||
-I$(top_srcdir)/src/target \
|
||||
-I$(top_srcdir)/src/xsvf \
|
||||
-I$(top_srcdir)/src/svf \
|
||||
-I$(top_srcdir)/src/server \
|
||||
-I$(top_srcdir)/src/flash \
|
||||
-I$(top_srcdir)/src/pld
|
||||
-I$(top_builddir)/src
|
||||
|
||||
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
||||
|
||||
@@ -51,12 +60,16 @@ endif
|
||||
if FT2232_LIBFTDI
|
||||
FTDI2232LIB = -lftdi -lusb
|
||||
else
|
||||
if USB_BLASTER_LIBFTDI
|
||||
FTDI2232LIB = -lftdi -lusb
|
||||
else
|
||||
if PRESTO_LIBFTDI
|
||||
FTDI2232LIB = -lftdi -lusb
|
||||
else
|
||||
FTDI2232LIB =
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if USBPROG
|
||||
LIBUSB = -lusb
|
||||
@@ -91,6 +104,30 @@ if HTTPD
|
||||
libopenocd_la_LIBADD += -lmicrohttpd
|
||||
endif
|
||||
|
||||
STARTUP_TCL_SRCS = \
|
||||
$(srcdir)/helper/startup.tcl \
|
||||
$(srcdir)/jtag/startup.tcl \
|
||||
$(srcdir)/target/startup.tcl \
|
||||
$(srcdir)/flash/startup.tcl \
|
||||
$(srcdir)/server/startup.tcl
|
||||
|
||||
EXTRA_DIST = $(STARTUP_TCL_SRCS)
|
||||
|
||||
BUILT_SOURCES = startup.tcl
|
||||
|
||||
startup.tcl: $(STARTUP_TCL_SRCS)
|
||||
cat $^ > $@
|
||||
|
||||
BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
|
||||
|
||||
# Convert .tcl to cfile
|
||||
startup_tcl.c: startup.tcl $(BIN2C)
|
||||
$(BIN2C) openocd_startup_tcl < $< > $@ || rm -f $@
|
||||
|
||||
# add startup_tcl.c to make clean list
|
||||
CLEANFILES = startup.tcl startup_tcl.c
|
||||
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
# The "quick" target builds executables & reinstalls the executables
|
||||
|
||||
195
src/ecosboard.c
195
src/ecosboard.c
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2008 by Øyvind Harboe *
|
||||
* Copyright (C) 2007-2009 by Øyvind Harboe *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -21,23 +21,18 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "jtag.h"
|
||||
#include "configuration.h"
|
||||
#include "xsvf.h"
|
||||
#include "svf.h"
|
||||
#include "target.h"
|
||||
#include "flash.h"
|
||||
#include "nand.h"
|
||||
#include "pld.h"
|
||||
#include <helper/types.h>
|
||||
#include <jtag/jtag.h>
|
||||
#include <helper/ioutil.h>
|
||||
#include <helper/configuration.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "server.h"
|
||||
#include "telnet_server.h"
|
||||
#include "gdb_server.h"
|
||||
#include <server/server.h>
|
||||
#include <server/telnet_server.h>
|
||||
#include <server/gdb_server.h>
|
||||
#include <openocd.h>
|
||||
|
||||
#include <helper/time_support.h>
|
||||
|
||||
#include <time_support.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -59,29 +54,20 @@
|
||||
#include <cyg/athttpd/cgi.h>
|
||||
#include <cyg/athttpd/forms.h>
|
||||
#include <cyg/discover/discover.h>
|
||||
#include <cyg/hal/hal_diag.h>
|
||||
#include <cyg/kernel/kapi.h>
|
||||
#include <cyg/io/serialio.h>
|
||||
#include <cyg/io/io.h>
|
||||
#include <cyg/io/serialio.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include "rom.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <string.h>
|
||||
#include <cyg/hal/hal_diag.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "rom.h"
|
||||
|
||||
#ifdef CYGPKG_HAL_NIOS2
|
||||
#include <cyg/hal/io.h>
|
||||
#define ZY1000_SER_DEV "/dev/uart_0"
|
||||
#else
|
||||
#define ZY1000_SER_DEV "/dev/ser0"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_IFS 64
|
||||
@@ -114,8 +100,8 @@ static bool writeLog = true;
|
||||
char hwaddr[512];
|
||||
|
||||
|
||||
extern flash_driver_t *flash_drivers[];
|
||||
extern target_type_t *target_types[];
|
||||
extern struct flash_driver *flash_drivers[];
|
||||
extern struct target_type *target_types[];
|
||||
|
||||
#ifdef CYGPKG_PROFILE_GPROF
|
||||
#include <cyg/profile/profile.h>
|
||||
@@ -160,7 +146,14 @@ static void zylinjtag_reboot(cyg_addrword_t data)
|
||||
diag_printf("Unmounting /config..\n");
|
||||
umount("/config");
|
||||
diag_printf("Rebooting..\n");
|
||||
#ifdef CYGPKG_HAL_NIOS2
|
||||
/* This will reboot & reconfigure the FPGA from the bootloader
|
||||
* and on.
|
||||
*/
|
||||
IOWR(REMOTE_UPDATE_BASE, 0x20, 0x1);
|
||||
#else
|
||||
HAL_PLATFORM_RESET();
|
||||
#endif
|
||||
}
|
||||
static cyg_thread zylinjtag_thread_object;
|
||||
static cyg_handle_t zylinjtag_thread_handle;
|
||||
@@ -229,7 +222,7 @@ void reboot_port(void)
|
||||
cyg_thread_resume(zylinjtag_reboot_port_thread_handle);
|
||||
}
|
||||
|
||||
int configuration_output_handler(struct command_context_s *context,
|
||||
int configuration_output_handler(struct command_context *context,
|
||||
const char* line)
|
||||
{
|
||||
diag_printf("%s", line);
|
||||
@@ -237,7 +230,7 @@ int configuration_output_handler(struct command_context_s *context,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int zy1000_configuration_output_handler_log(struct command_context_s *context,
|
||||
int zy1000_configuration_output_handler_log(struct command_context *context,
|
||||
const char* line)
|
||||
{
|
||||
LOG_USER_N("%s", line);
|
||||
@@ -246,11 +239,21 @@ int zy1000_configuration_output_handler_log(struct command_context_s *context,
|
||||
}
|
||||
|
||||
#ifdef CYGPKG_PROFILE_GPROF
|
||||
//extern int64_t totaltime;
|
||||
|
||||
int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int zylinjtag_Jim_Command_profile(Jim_Interp *interp, int argc,
|
||||
Jim_Obj * const *argv)
|
||||
{
|
||||
command_print(cmd_ctx, "Profiling started");
|
||||
start_profile();
|
||||
if ((argc == 2) && (strcmp(Jim_GetString(argv[1], NULL), "stats")==0))
|
||||
{
|
||||
// profile_off();
|
||||
//LOG_USER("Stats %dms sleeping in select()", (int)totaltime);
|
||||
} else
|
||||
{
|
||||
LOG_USER("Profiling started");
|
||||
start_profile();
|
||||
//totaltime = 0;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -258,7 +261,7 @@ int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx
|
||||
|
||||
externC void phi_init_all_network_interfaces(void);
|
||||
|
||||
command_context_t *cmd_ctx;
|
||||
struct command_context *cmd_ctx;
|
||||
|
||||
static bool webRunning = false;
|
||||
|
||||
@@ -474,7 +477,6 @@ static int zylinjtag_Jim_Command_reboot(Jim_Interp *interp, int argc,
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
|
||||
static void zylinjtag_startNetwork(void)
|
||||
{
|
||||
// Bring TCP/IP up immediately before we're ready to accept commands.
|
||||
@@ -501,8 +503,6 @@ static void zylinjtag_startNetwork(void)
|
||||
|
||||
cyg_httpd_init_tcl_interpreter();
|
||||
|
||||
interp = httpstate.jim_interp;
|
||||
|
||||
Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log,
|
||||
NULL, NULL);
|
||||
Jim_CreateCommand(httpstate.jim_interp, "zy1000_reboot",
|
||||
@@ -591,6 +591,7 @@ static void print_exception_handler(cyg_addrword_t data, cyg_code_t exception,
|
||||
|
||||
}
|
||||
|
||||
#ifdef CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION
|
||||
static void setHandler(cyg_code_t exception)
|
||||
{
|
||||
cyg_exception_handler_t *old_handler;
|
||||
@@ -599,6 +600,7 @@ static void setHandler(cyg_code_t exception)
|
||||
cyg_exception_set_handler(exception, print_exception_handler, 0,
|
||||
&old_handler, &old_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static cyg_thread zylinjtag_uart_thread_object;
|
||||
static cyg_handle_t zylinjtag_uart_thread_handle;
|
||||
@@ -686,7 +688,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
int oldopts = fcntl(session, F_GETFL, 0);
|
||||
fcntl(session, F_SETFL, oldopts | O_NONBLOCK); //
|
||||
|
||||
int serHandle = open("/dev/ser0", O_RDWR | O_NONBLOCK);
|
||||
int serHandle = open(ZY1000_SER_DEV, O_RDWR | O_NONBLOCK);
|
||||
if (serHandle < 0)
|
||||
{
|
||||
close(session);
|
||||
@@ -748,7 +750,6 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
pos2 = 0;
|
||||
}
|
||||
|
||||
size_t x = actual2;
|
||||
size_t y = 0;
|
||||
if (actual2 > 0)
|
||||
{
|
||||
@@ -778,7 +779,6 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
actual += t;
|
||||
}
|
||||
|
||||
int x2 = actual;
|
||||
int y2 = 0;
|
||||
if (actual > 0)
|
||||
{
|
||||
@@ -841,21 +841,25 @@ void startUart(void)
|
||||
cyg_thread_resume(zylinjtag_uart_thread_handle);
|
||||
}
|
||||
|
||||
int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc)
|
||||
static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
|
||||
Jim_Obj * const *argv)
|
||||
{
|
||||
static int current_baud = 38400;
|
||||
if (argc == 0)
|
||||
if (argc == 1)
|
||||
{
|
||||
command_print(cmd_ctx, "%d", current_baud);
|
||||
return ERROR_OK;
|
||||
Jim_SetResult(interp, Jim_NewIntObj(interp, current_baud));
|
||||
return JIM_OK;
|
||||
}
|
||||
else if (argc != 1)
|
||||
else if (argc != 2)
|
||||
{
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
current_baud = atol(args[0]);
|
||||
long new_baudrate;
|
||||
if (Jim_GetLong(interp, argv[1], &new_baudrate) != JIM_OK)
|
||||
return JIM_ERR;
|
||||
|
||||
current_baud = new_baudrate;
|
||||
|
||||
int baud;
|
||||
switch (current_baud)
|
||||
@@ -879,8 +883,8 @@ int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
baud = CYGNUM_SERIAL_BAUD_230400;
|
||||
break;
|
||||
default:
|
||||
command_print(cmd_ctx, "unsupported baudrate");
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
Jim_SetResult(interp, Jim_NewStringObj(interp, "unsupported baudrate", -1));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
cyg_serial_info_t buf;
|
||||
@@ -890,11 +894,11 @@ int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
int err;
|
||||
cyg_io_handle_t serial_handle;
|
||||
|
||||
err = cyg_io_lookup("/dev/ser0", &serial_handle);
|
||||
err = cyg_io_lookup(ZY1000_SER_DEV, &serial_handle);
|
||||
if (err != ENOERR)
|
||||
{
|
||||
LOG_ERROR("/dev/ser0 not found\n");
|
||||
return ERROR_FAIL;
|
||||
Jim_SetResult(interp, Jim_NewStringObj(interp, "Could not open serial port", -1));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
err = cyg_io_get_config(serial_handle,
|
||||
@@ -903,8 +907,8 @@ int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
&len);
|
||||
if (err != ENOERR)
|
||||
{
|
||||
command_print(cmd_ctx, "Failed to get serial port settings %d", err);
|
||||
return ERROR_OK;
|
||||
Jim_SetResult(interp, Jim_NewStringObj(interp, "Failed to get serial port settings", -1));
|
||||
return JIM_ERR;
|
||||
}
|
||||
buf.baud = baud;
|
||||
|
||||
@@ -912,11 +916,11 @@ int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
&len);
|
||||
if (err != ENOERR)
|
||||
{
|
||||
command_print(cmd_ctx, "Failed to set serial port settings %d", err);
|
||||
return ERROR_OK;
|
||||
Jim_SetResult(interp, Jim_NewStringObj(interp, "Failed to set serial port settings", -1));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
bool logAllToSerial = false;
|
||||
@@ -925,8 +929,6 @@ bool logAllToSerial = false;
|
||||
int boolParam(char *var);
|
||||
|
||||
|
||||
command_context_t *setup_command_handler(void);
|
||||
|
||||
static const char *zylin_config_dir="/config/settings";
|
||||
|
||||
static int add_default_dirs(void)
|
||||
@@ -937,8 +939,6 @@ static int add_default_dirs(void)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ioutil_init(struct command_context_s *cmd_ctx);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* ramblockdevice will be the same address every time. The deflate app uses a buffer 16mBytes out, so we
|
||||
@@ -956,7 +956,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
diag_init_putc(_zylinjtag_diag_write_char);
|
||||
// We want this in the log.
|
||||
diag_printf("Zylin ZY1000.\n");
|
||||
#ifdef CYGPKG_HAL_NIOS2
|
||||
diag_printf("Zylin ZY1000 PCB revc.\n");
|
||||
#else
|
||||
diag_printf("Zylin ZY1000 PCB revb.\n");
|
||||
#endif
|
||||
|
||||
err = mount("", "/ram", "ramfs");
|
||||
if (err < 0)
|
||||
@@ -995,6 +999,20 @@ int main(int argc, char *argv[])
|
||||
|
||||
copydir("/rom", "/ram/cgi");
|
||||
|
||||
#ifdef CYGPKG_HAL_NIOS2
|
||||
cyg_flashaddr_t err_address;
|
||||
#define UNCACHED_EXT_FLASH_BASE (0x80000000 + EXT_FLASH_BASE)
|
||||
/* The revc flash is locked upon reset, unlock it */
|
||||
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
|
||||
if ((err = flash_unlock((void *) UNCACHED_EXT_FLASH_BASE, EXT_FLASH_SPAN,
|
||||
(void **) &err_address)) != 0)
|
||||
{
|
||||
diag_printf("Error: could not unlock flash\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
err = mount("/dev/flash1", "/config", "jffs2");
|
||||
if (err < 0)
|
||||
{
|
||||
@@ -1069,34 +1087,24 @@ int main(int argc, char *argv[])
|
||||
add_default_dirs();
|
||||
|
||||
/* initialize commandline interface */
|
||||
command_context_t * cmd_ctx;
|
||||
cmd_ctx = setup_command_handler();
|
||||
struct command_context * cmd_ctx;
|
||||
struct command_context *setup_command_handler(Jim_Interp *interp);
|
||||
cmd_ctx = setup_command_handler(httpstate.jim_interp);
|
||||
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
|
||||
command_context_mode(cmd_ctx, COMMAND_CONFIG);
|
||||
|
||||
#if BUILD_IOUTIL
|
||||
if (ioutil_init(cmd_ctx) != ERROR_OK)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CYGPKG_PROFILE_GPROF
|
||||
register_command(cmd_ctx, NULL, "ecosboard_profile", eCosBoard_handle_eCosBoard_profile_command,
|
||||
COMMAND_ANY, NULL);
|
||||
Jim_CreateCommand(httpstate.jim_interp, "zy1000_profile", zylinjtag_Jim_Command_profile,
|
||||
NULL, NULL);
|
||||
#endif
|
||||
|
||||
register_command(cmd_ctx, NULL, "uart", handle_uart_command, COMMAND_ANY,
|
||||
"uart <baud> - forward uart on port 5555");
|
||||
Jim_CreateCommand(httpstate.jim_interp, "zy1000_uart", zylinjtag_Jim_Command_uart, NULL, NULL);
|
||||
|
||||
int errVal;
|
||||
errVal = log_init(cmd_ctx);
|
||||
if (errVal != ERROR_OK)
|
||||
{
|
||||
diag_printf("log_init() failed %d\n", errVal);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
log_init();
|
||||
|
||||
set_log_output(cmd_ctx, log);
|
||||
|
||||
@@ -1113,6 +1121,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
command_run_linef(cmd_ctx, "script /rom/openocd.cfg");
|
||||
|
||||
int ret;
|
||||
ret = server_init(cmd_ctx);
|
||||
if (ERROR_OK != ret)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* we MUST always run the init command as it will launch telnet sessions */
|
||||
command_run_line(cmd_ctx, "init");
|
||||
|
||||
|
||||
@@ -1,70 +1,25 @@
|
||||
SUBDIRS = \
|
||||
nor \
|
||||
nand
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag \
|
||||
-I$(top_srcdir)/src/target
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src
|
||||
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libflash.la
|
||||
libflash_la_SOURCES = \
|
||||
arm_nandio.c \
|
||||
flash.c \
|
||||
lpc2000.c \
|
||||
lpc288x.c \
|
||||
lpc2900.c \
|
||||
cfi.c \
|
||||
non_cfi.c \
|
||||
at91sam7.c \
|
||||
at91sam3.c \
|
||||
davinci_nand.c \
|
||||
str7x.c \
|
||||
str9x.c \
|
||||
aduc702x.c \
|
||||
nand.c \
|
||||
nand_ecc.c \
|
||||
nand_ecc_kw.c \
|
||||
lpc3180_nand_controller.c \
|
||||
stellaris.c \
|
||||
str9xpec.c \
|
||||
stm32x.c \
|
||||
tms470.c \
|
||||
ecos.c \
|
||||
orion_nand.c \
|
||||
s3c24xx_nand.c \
|
||||
s3c2410_nand.c \
|
||||
s3c2412_nand.c \
|
||||
s3c2440_nand.c \
|
||||
s3c2443_nand.c \
|
||||
ocl.c \
|
||||
mflash.c \
|
||||
pic32mx.c \
|
||||
avrf.c \
|
||||
faux.c \
|
||||
mx3_nand.c
|
||||
common.c \
|
||||
mflash.c
|
||||
|
||||
libflash_la_LIBADD = \
|
||||
$(top_builddir)/src/flash/nor/libocdflashnor.la \
|
||||
$(top_builddir)/src/flash/nand/libocdflashnand.la
|
||||
|
||||
noinst_HEADERS = \
|
||||
arm_nandio.h \
|
||||
flash.h \
|
||||
lpc2000.h \
|
||||
lpc288x.h \
|
||||
lpc2900.h \
|
||||
cfi.h \
|
||||
non_cfi.h \
|
||||
at91sam7.h \
|
||||
at91sam3.h \
|
||||
str7x.h \
|
||||
str9x.h \
|
||||
nand.h \
|
||||
lpc3180_nand_controller.h \
|
||||
stellaris.h \
|
||||
str9xpec.h \
|
||||
stm32x.h \
|
||||
tms470.h \
|
||||
s3c24xx_nand.h \
|
||||
s3c24xx_regs_nand.h \
|
||||
mflash.h \
|
||||
ocl.h \
|
||||
pic32mx.h \
|
||||
avrf.h \
|
||||
mx3_nand.h
|
||||
common.h \
|
||||
mflash.h
|
||||
|
||||
EXTRA_DIST = startup.tcl
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by Marvell Semiconductors, Inc.
|
||||
* Written by Nicolas Pitre <nico at marvell.com>
|
||||
*
|
||||
* Copyright (C) 2009 by David Brownell
|
||||
*
|
||||
* 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 "arm_nandio.h"
|
||||
#include "armv4_5.h"
|
||||
|
||||
|
||||
/*
|
||||
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
|
||||
* For now this only supports ARMv4 and ARMv5 cores.
|
||||
*
|
||||
* Enhancements to target_run_algorithm() could enable:
|
||||
* - ARMv6 and ARMv7 cores in ARM mode
|
||||
*
|
||||
* Different code fragments could handle:
|
||||
* - Thumb2 cores like Cortex-M (needs different byteswapping)
|
||||
* - 16-bit wide data (needs different setup too)
|
||||
*/
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
||||
{
|
||||
target_t *target = nand->target;
|
||||
armv4_5_algorithm_t algo;
|
||||
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||
reg_param_t reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit = 0;
|
||||
int retval;
|
||||
|
||||
/* Inputs:
|
||||
* r0 NAND data address (byte wide)
|
||||
* r1 buffer address
|
||||
* r2 buffer length
|
||||
*/
|
||||
static const uint32_t code[] = {
|
||||
0xe4d13001, /* s: ldrb r3, [r1], #1 */
|
||||
0xe5c03000, /* strb r3, [r0] */
|
||||
0xe2522001, /* subs r2, r2, #1 */
|
||||
0x1afffffb, /* bne s */
|
||||
|
||||
/* exit: ARMv4 needs hardware breakpoint */
|
||||
0xe1200070, /* e: bkpt #0 */
|
||||
};
|
||||
|
||||
if (!nand->copy_area) {
|
||||
uint8_t code_buf[sizeof(code)];
|
||||
unsigned i;
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target,
|
||||
sizeof(code) + nand->chunk_size,
|
||||
&nand->copy_area) != ERROR_OK) {
|
||||
LOG_DEBUG("%s: no %d byte buffer",
|
||||
__FUNCTION__,
|
||||
(int) sizeof(code) + nand->chunk_size);
|
||||
return ERROR_NAND_NO_BUFFER;
|
||||
}
|
||||
|
||||
/* buffer code in target endianness */
|
||||
for (i = 0; i < sizeof(code) / 4; i++)
|
||||
target_buffer_set_u32(target, code_buf + i * 4, code[i]);
|
||||
|
||||
/* copy code to work area */
|
||||
retval = target_write_memory(target,
|
||||
nand->copy_area->address,
|
||||
4, sizeof(code) / 4, code_buf);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* copy data to work area */
|
||||
target_buf = nand->copy_area->address + sizeof(code);
|
||||
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
|
||||
if (retval == ERROR_OK && (size & 3) != 0)
|
||||
retval = target_write_memory(target,
|
||||
target_buf + (size & ~3),
|
||||
1, size & 3, data + (size & ~3));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* set up algorithm and parameters */
|
||||
algo.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
algo.core_mode = ARMV4_5_MODE_SVC;
|
||||
algo.core_state = ARMV4_5_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, nand->data);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||
|
||||
/* armv4 must exit using a hardware breakpoint */
|
||||
if (armv4_5->is_armv4)
|
||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
||||
|
||||
/* use alg to write data from work area to NAND chip */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
nand->copy_area->address, exit, 1000, &algo);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("error executing hosted NAND write");
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* REVISIT do the same for bulk *read* too ... */
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef __ARM_NANDIO_H
|
||||
#define __ARM_NANDIO_H
|
||||
|
||||
#include "nand.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
struct arm_nand_data {
|
||||
/* target is proxy for some ARM core */
|
||||
struct target_s *target;
|
||||
|
||||
/* copy_area holds write-to-NAND loop and data to write */
|
||||
struct working_area_s *copy_area;
|
||||
|
||||
/* chunk_size == page or ECC unit */
|
||||
unsigned chunk_size;
|
||||
|
||||
/* data == where to write the data */
|
||||
uint32_t data;
|
||||
|
||||
/* currently implicit: data width == 8 bits (not 16) */
|
||||
};
|
||||
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size);
|
||||
|
||||
#endif /* __ARM_NANDIO_H */
|
||||
48
src/flash/common.c
Normal file
48
src/flash/common.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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 "common.h"
|
||||
#include <helper/log.h>
|
||||
|
||||
unsigned get_flash_name_index(const char *name)
|
||||
{
|
||||
const char *index = strrchr(name, '.');
|
||||
if (NULL == index)
|
||||
return 0;
|
||||
if (index[1] < '0' || index[1] > '9')
|
||||
return ~0U;
|
||||
unsigned requested;
|
||||
int retval = parse_uint(index + 1, &requested);
|
||||
// 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...
|
||||
if (strncmp(name, expected, blen) != 0)
|
||||
return false;
|
||||
|
||||
// ...then check that name terminates at this spot.
|
||||
return expected[blen] == '.' || expected[blen] == '\0';
|
||||
}
|
||||
48
src/flash/common.h
Normal file
48
src/flash/common.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_COMMON_H
|
||||
#define FLASH_COMMON_H
|
||||
|
||||
#include <helper/log.h>
|
||||
|
||||
/**
|
||||
* Parses the optional '.index' portion of a flash bank identifier.
|
||||
* @param name The desired driver name, passed by the user.
|
||||
* @returns The parsed index request, or 0 if not present. If the
|
||||
* name provides a suffix but it does not parse as an unsigned integer,
|
||||
* the routine returns ~0U. This will prevent further matching.
|
||||
*/
|
||||
unsigned get_flash_name_index(const char *name);
|
||||
/**
|
||||
* Attempt to match the @c expected name with the @c name of a driver.
|
||||
* @param name The name of the driver (from the bank's device structure).
|
||||
* @param expected The expected driver name, passed by the user.
|
||||
*/
|
||||
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
|
||||
|
||||
#endif // FLASH_COMMON_H
|
||||
1330
src/flash/flash.c
1330
src/flash/flash.c
File diff suppressed because it is too large
Load Diff
@@ -1,339 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2008 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_H
|
||||
#define FLASH_H
|
||||
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
|
||||
struct image_s;
|
||||
|
||||
#define FLASH_MAX_ERROR_STR (128)
|
||||
|
||||
/**
|
||||
* Describes the geometry and status of a single flash sector
|
||||
* within a flash bank. A single bank typically consists of multiple
|
||||
* sectors, each of which can be erased and protected independently.
|
||||
*/
|
||||
typedef struct flash_sector_s
|
||||
{
|
||||
/// Bus offset from start of the flash chip (in bytes).
|
||||
uint32_t offset;
|
||||
/// Number of bytes in this flash sector.
|
||||
uint32_t size;
|
||||
/**
|
||||
* Indication of erasure status: 0 = not erased, 1 = erased,
|
||||
* other = unknown. Set by @c flash_driver_s::erase_check.
|
||||
*/
|
||||
int is_erased;
|
||||
/**
|
||||
* Indication of protection status: 0 = unprotected/unlocked,
|
||||
* 1 = protected/locked, other = unknown. Set by
|
||||
* @c flash_driver_s::protect_check.
|
||||
*/
|
||||
int is_protected;
|
||||
} flash_sector_t;
|
||||
|
||||
struct flash_bank_s;
|
||||
|
||||
/**
|
||||
* @brief Provides the implementation-independent structure that defines
|
||||
* all of the callbacks required by OpenOCD flash drivers.
|
||||
*
|
||||
* Driver authors must implement the routines defined here, providing an
|
||||
* instance with the fields filled out. After that, the instance must
|
||||
* be registered in flash.c, so it can be used by the driver lookup system.
|
||||
*
|
||||
* Specifically, the user can issue the command: @par
|
||||
* @code
|
||||
* flash bank DRIVERNAME ...parameters...
|
||||
* @endcode
|
||||
*
|
||||
* OpenOCD will search for the driver with a @c flash_driver_s::name
|
||||
* that matches @c DRIVERNAME.
|
||||
*
|
||||
* The flash subsystem calls some of the other drivers routines a using
|
||||
* corresponding static <code>flash_driver_<i>callback</i>()</code>
|
||||
* routine in flash.c.
|
||||
*/
|
||||
typedef struct flash_driver_s
|
||||
{
|
||||
/**
|
||||
* Gives a human-readable name of this flash driver,
|
||||
* This field is used to select and initialize the driver.
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Registers driver-specific commands. When called (during the
|
||||
* "flash bank" command), the driver may register addition
|
||||
* commands to support new flash chip functions.
|
||||
*
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||
|
||||
/**
|
||||
* Finish the "flash bank" command for @a bank. The
|
||||
* @a bank parameter will have been filled in by the core flash
|
||||
* layer when this routine is called, and the driver can store
|
||||
* additional information in its flash_bank_t::driver_priv field.
|
||||
*
|
||||
* @param cmd_ctx - the command context
|
||||
* @param cmd - the command, in this case 'flash'
|
||||
* @param args - parameters, see below
|
||||
* @param argc - number of parameters on command line
|
||||
* @param bank - new filled in flash bank.
|
||||
*
|
||||
* The args are: @par
|
||||
* @code
|
||||
* args[0] = bank
|
||||
* args[1] = drivername {name above}
|
||||
* args[2] = baseaddress
|
||||
* args[3] = lengthbytes
|
||||
* args[4] = chip_width_in bytes
|
||||
* args[5] = bus_width_bytes
|
||||
* args[6] = driver-specific parameters
|
||||
* @endcode
|
||||
*
|
||||
* For example, args[4] = 16 bit flash, args[5] = 32bit bus.
|
||||
*
|
||||
* If extra arguments are provided (@a argc > 6), they will
|
||||
* start in @a args[6]. These can be used to implement
|
||||
* driver-specific extensions.
|
||||
*
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Bank/sector erase routine (target-specific). When
|
||||
* called, the flash driver should erase the specified sectors
|
||||
* using whatever means are at its disposal.
|
||||
*
|
||||
* @param bank The bank of flash to be erased.
|
||||
* @param first The number of the first sector to erase, typically 0.
|
||||
* @param last The number of the last sector to erase, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase)(struct flash_bank_s *bank, int first, int last);
|
||||
|
||||
/**
|
||||
* Bank/sector protection routine (target-specific).
|
||||
* When called, the driver should disable 'flash write' bits (or
|
||||
* enable 'erase protection' bits) for the given @a bank and @a
|
||||
* sectors.
|
||||
*
|
||||
* @param bank The bank to protect or unprotect.
|
||||
* @param set If non-zero, enable protection; if 0, disable it.
|
||||
* @param first The first sector to (un)protect, typicaly 0.
|
||||
* @param last The last sector to (un)project, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
|
||||
|
||||
/**
|
||||
* Program data into the flash. Note CPU address will be
|
||||
* "bank->base + offset", while the physical address is
|
||||
* dependent upon current target MMU mappings.
|
||||
*
|
||||
* @param bank The bank to program
|
||||
* @param buffer The data bytes to write.
|
||||
* @param offset The offset into the chip to program.
|
||||
* @param count The number of bytes to write.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*write)(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
|
||||
/**
|
||||
* Probe to determine what kind of flash is present.
|
||||
* This is invoked by the "probe" script command.
|
||||
*
|
||||
* @param bank The bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*probe)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Check the erasure status of a flash bank.
|
||||
* When called, the driver routine must perform the required
|
||||
* checks and then set the @c flash_sector_s::is_erased field
|
||||
* for each of the flash banks's sectors.
|
||||
*
|
||||
* @param bank The bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase_check)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Determine if the specific bank is "protected" or not.
|
||||
* When called, the driver routine must must perform the
|
||||
* required protection check(s) and then set the @c
|
||||
* flash_sector_s::is_protected field for each of the flash
|
||||
* bank's sectors.
|
||||
*
|
||||
* @param bank - the bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect_check)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Display human-readable information about the flash
|
||||
* bank into the given buffer. Drivers must be careful to avoid
|
||||
* overflowing the buffer.
|
||||
*
|
||||
* @param bank - the bank to get info about
|
||||
* @param char - where to put the text for the human to read
|
||||
* @param buf_size - the size of the human buffer.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* driver probably should not perform its probe a second time.
|
||||
*
|
||||
* This callback is often called from the inside of other
|
||||
* routines (e.g. GDB flash downloads) to autoprobe the flash as
|
||||
* it is programing the flash.
|
||||
*
|
||||
* @param bank - the bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*auto_probe)(struct flash_bank_s *bank);
|
||||
} flash_driver_t;
|
||||
|
||||
/**
|
||||
* Provides details of a flash bank, available either on-chip or through
|
||||
* a major interface.
|
||||
*
|
||||
* This structure will be passed as a parameter to the callbacks in the
|
||||
* flash_driver_s structure, some of which may modify the contents of
|
||||
* this structure of the area of flash that it defines. Driver writers
|
||||
* may use the @c driver_priv member to store additional data on a
|
||||
* per-bank basis, if required.
|
||||
*/
|
||||
typedef struct flash_bank_s
|
||||
{
|
||||
struct target_s *target; /**< Target to which this bank belongs. */
|
||||
|
||||
flash_driver_t *driver; /**< Driver for this bank. */
|
||||
void *driver_priv; /**< Private driver storage pointer */
|
||||
|
||||
int bank_number; /**< The 'bank' (or chip number) of this instance. */
|
||||
uint32_t base; /**< The base address of this bank */
|
||||
uint32_t size; /**< The size of this chip bank, in bytes */
|
||||
|
||||
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
|
||||
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
|
||||
|
||||
/**
|
||||
* The number of sectors on this chip. This value will
|
||||
* be set intially to 0, and the flash driver must set this to
|
||||
* some non-zero value during "probe()" or "auto_probe()".
|
||||
*/
|
||||
int num_sectors;
|
||||
/// Array of sectors, allocated and initilized by the flash driver
|
||||
flash_sector_t *sectors;
|
||||
|
||||
struct flash_bank_s *next; /**< The next flash bank on this chip */
|
||||
} flash_bank_t;
|
||||
|
||||
/// Registers the 'flash' subsystem commands
|
||||
extern int flash_register_commands(struct command_context_s *cmd_ctx);
|
||||
/// Initializes the 'flash' subsystem drivers
|
||||
extern int flash_init_drivers(struct command_context_s *cmd_ctx);
|
||||
|
||||
/**
|
||||
* Erases @a length bytes in the @a target flash, starting at @a addr.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int flash_erase_address_range(struct target_s *target, uint32_t addr, uint32_t length);
|
||||
/**
|
||||
* Writes @a image into the @a target flash. The @a written parameter
|
||||
* will contain the
|
||||
* @param target The target with the flash to be programmed.
|
||||
* @param image The image that will be programmed to flash.
|
||||
* @param written On return, contains the number of bytes written.
|
||||
* @param erase If non-zero, indicates the flash driver should first
|
||||
* erase the corresponding banks or sectors before programming.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int flash_write(struct target_s *target, struct image_s *image, uint32_t *written, int erase);
|
||||
/**
|
||||
* Forces targets to re-examine their erase/protection state.
|
||||
* This routine must be called when the system may modify the status.
|
||||
*/
|
||||
extern void flash_set_dirty(void);
|
||||
/// @returns The number of flash banks currently defined.
|
||||
extern int flash_get_bank_count(void);
|
||||
/**
|
||||
* Provides default erased-bank check handling. Checks to see if
|
||||
* the flash driver knows they are erased; if things look uncertain,
|
||||
* this routine will call default_flash_mem_blank_check() to confirm.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int default_flash_blank_check(struct flash_bank_s *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.
|
||||
*/
|
||||
extern int default_flash_mem_blank_check(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Returns a flash bank by the specified flash_bank_s bank_number, @a num.
|
||||
* @param num The flash bank number.
|
||||
* @returns A flash_bank_t for flash bank @a num, or NULL
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_num(int num);
|
||||
/**
|
||||
* Returns the flash bank like get_flash_bank_by_num(), without probing.
|
||||
* @param num The flash bank number.
|
||||
* @returns A flash_bank_t for flash bank @a num, or NULL.
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_num_noprobe(int num);
|
||||
/**
|
||||
* Returns the flash bank located at a specified address.
|
||||
* @param target The target, presumed to contain one or more banks.
|
||||
* @param addr An address that is within the range of the bank.
|
||||
* @returns The flash_bank_t located at @a addr, or NULL.
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_addr(struct target_s *target, uint32_t addr);
|
||||
|
||||
#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)
|
||||
|
||||
#endif /* FLASH_H */
|
||||
@@ -22,33 +22,32 @@
|
||||
#endif
|
||||
|
||||
#include "mflash.h"
|
||||
#include "time_support.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
#include <target/target.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/fileio.h>
|
||||
#include <helper/log.h>
|
||||
|
||||
|
||||
static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio);
|
||||
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
|
||||
static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio);
|
||||
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
|
||||
static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio);
|
||||
static int s3c2440_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val);
|
||||
static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio);
|
||||
static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val);
|
||||
|
||||
static command_t *mflash_cmd;
|
||||
static struct mflash_bank *mflash_bank;
|
||||
|
||||
static mflash_bank_t *mflash_bank;
|
||||
|
||||
static mflash_gpio_drv_t pxa270_gpio = {
|
||||
static struct mflash_gpio_drv pxa270_gpio = {
|
||||
.name = "pxa270",
|
||||
.set_gpio_to_output = pxa270_set_gpio_to_output,
|
||||
.set_gpio_output_val = pxa270_set_gpio_output_val
|
||||
};
|
||||
|
||||
static mflash_gpio_drv_t s3c2440_gpio = {
|
||||
static struct mflash_gpio_drv s3c2440_gpio = {
|
||||
.name = "s3c2440",
|
||||
.set_gpio_to_output = s3c2440_set_gpio_to_output,
|
||||
.set_gpio_output_val = s3c2440_set_gpio_output_val
|
||||
};
|
||||
|
||||
static mflash_gpio_drv_t *mflash_gpio[] =
|
||||
static struct mflash_gpio_drv *mflash_gpio[] =
|
||||
{
|
||||
&pxa270_gpio,
|
||||
&s3c2440_gpio,
|
||||
@@ -64,10 +63,10 @@ static mflash_gpio_drv_t *mflash_gpio[] =
|
||||
#define PXA270_GPSR0 0x40E00018
|
||||
#define PXA270_GPCR0 0x40E00024
|
||||
|
||||
static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio)
|
||||
static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio)
|
||||
{
|
||||
uint32_t addr, value, mask;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
int ret;
|
||||
|
||||
/* remove alternate function. */
|
||||
@@ -101,10 +100,10 @@ static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
|
||||
static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
|
||||
{
|
||||
uint32_t addr, value, mask;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
int ret;
|
||||
|
||||
mask = 0x1u << (gpio.num & 0x1F);
|
||||
@@ -130,10 +129,10 @@ static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
|
||||
#define S3C2440_GPJCON 0x560000d0
|
||||
#define S3C2440_GPJDAT 0x560000d4
|
||||
|
||||
static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio)
|
||||
static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio)
|
||||
{
|
||||
uint32_t data, mask, gpio_con;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
int ret;
|
||||
|
||||
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
|
||||
@@ -162,10 +161,10 @@ static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
|
||||
static int s3c2440_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
|
||||
{
|
||||
uint32_t data, mask, gpio_dat;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
int ret;
|
||||
|
||||
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
|
||||
@@ -199,7 +198,7 @@ static int mg_hdrst(uint8_t level)
|
||||
static int mg_init_gpio (void)
|
||||
{
|
||||
int ret;
|
||||
mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv;
|
||||
struct mflash_gpio_drv *gpio_drv = mflash_bank->gpio_drv;
|
||||
|
||||
ret = gpio_drv->set_gpio_to_output(mflash_bank->rst_pin);
|
||||
if (ret != ERROR_OK)
|
||||
@@ -213,13 +212,13 @@ static int mg_init_gpio (void)
|
||||
static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
||||
{
|
||||
uint8_t status, error;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
||||
duration_t duration;
|
||||
int ret;
|
||||
long long t = 0;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
struct duration bench;
|
||||
duration_start(&bench);
|
||||
|
||||
while (time) {
|
||||
|
||||
@@ -275,10 +274,11 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
||||
}
|
||||
}
|
||||
|
||||
duration_stop_measure(&duration, NULL);
|
||||
|
||||
t = duration.duration.tv_usec/1000;
|
||||
t += duration.duration.tv_sec*1000;
|
||||
ret = duration_measure(&bench);
|
||||
if (ERROR_OK == ret)
|
||||
t = duration_elapsed(&bench) * 1000.0;
|
||||
else
|
||||
LOG_ERROR("mflash: duration measurement failed: %d", ret);
|
||||
|
||||
if (t > time)
|
||||
break;
|
||||
@@ -290,7 +290,7 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
||||
|
||||
static int mg_dsk_srst(uint8_t on)
|
||||
{
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
||||
uint8_t value;
|
||||
int ret;
|
||||
@@ -310,7 +310,7 @@ static int mg_dsk_srst(uint8_t on)
|
||||
|
||||
static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd)
|
||||
{
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
||||
uint8_t value;
|
||||
int ret;
|
||||
@@ -335,22 +335,24 @@ static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd)
|
||||
|
||||
static int mg_dsk_drv_info(void)
|
||||
{
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||
int ret;
|
||||
|
||||
if ((ret = mg_dsk_io_cmd(0, 1, mg_io_cmd_identify)) != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if ((ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL)) != ERROR_OK)
|
||||
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
LOG_INFO("mflash: read drive info");
|
||||
|
||||
if (! mflash_bank->drv_info)
|
||||
mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t));
|
||||
mflash_bank->drv_info = malloc(sizeof(struct mg_drv_info));
|
||||
|
||||
target_read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1,
|
||||
ret = target_read_memory(target, mg_buff, 2,
|
||||
sizeof(mg_io_type_drv_info) >> 1,
|
||||
(uint8_t *)&mflash_bank->drv_info->drv_id);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
@@ -407,14 +409,14 @@ static int mg_mflash_probe(void)
|
||||
return mg_dsk_drv_info();
|
||||
}
|
||||
|
||||
static int mg_probe_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(mg_probe_cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mg_mflash_probe();
|
||||
|
||||
if (ret == ERROR_OK) {
|
||||
command_print(cmd_ctx, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
|
||||
command_print(CMD_CTX, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
|
||||
mflash_bank->drv_info->tot_sects, mflash_bank->base);
|
||||
}
|
||||
|
||||
@@ -425,16 +427,16 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
|
||||
{
|
||||
uint32_t i, address;
|
||||
int ret;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint8_t *buff_ptr = buff;
|
||||
duration_t duration;
|
||||
|
||||
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read)) != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
struct duration bench;
|
||||
duration_start(&bench);
|
||||
|
||||
for (i = 0; i < sect_cnt; i++) {
|
||||
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
||||
@@ -453,11 +455,10 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
|
||||
|
||||
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
||||
|
||||
duration_stop_measure(&duration, NULL);
|
||||
|
||||
if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
|
||||
ret = duration_measure(&bench);
|
||||
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
||||
LOG_INFO("mflash: read %" PRIu32 "'th sectors", sect_num + i);
|
||||
duration_start_measure(&duration);
|
||||
duration_start(&bench);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,16 +499,16 @@ static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect
|
||||
{
|
||||
uint32_t i, address;
|
||||
int ret;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint8_t *buff_ptr = buff;
|
||||
duration_t duration;
|
||||
|
||||
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd)) != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
address = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
struct duration bench;
|
||||
duration_start(&bench);
|
||||
|
||||
for (i = 0; i < sect_cnt; i++) {
|
||||
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
|
||||
@@ -526,11 +527,10 @@ static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect
|
||||
|
||||
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
|
||||
|
||||
duration_stop_measure(&duration, NULL);
|
||||
|
||||
if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
|
||||
ret = duration_measure(&bench);
|
||||
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
|
||||
LOG_INFO("mflash: wrote %" PRIu32 "'th sectors", sect_num + i);
|
||||
duration_start_measure(&duration);
|
||||
duration_start(&bench);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,22 +703,20 @@ static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mg_write_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(mg_write_cmd)
|
||||
{
|
||||
uint32_t address, buf_cnt, cnt, res, i;
|
||||
uint32_t address, cnt, res, i;
|
||||
uint8_t *buffer;
|
||||
fileio_t fileio;
|
||||
duration_t duration;
|
||||
char *duration_text;
|
||||
struct fileio fileio;
|
||||
int ret;
|
||||
|
||||
if (argc != 3) {
|
||||
if (CMD_ARGC != 3) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
address = strtoul(args[2], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
||||
|
||||
ret = fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY);
|
||||
ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
@@ -731,8 +729,10 @@ static int mg_write_cmd(struct command_context_s *cmd_ctx, char *cmd, char **arg
|
||||
cnt = fileio.size / MG_FILEIO_CHUNK;
|
||||
res = fileio.size % MG_FILEIO_CHUNK;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
struct duration bench;
|
||||
duration_start(&bench);
|
||||
|
||||
size_t buf_cnt;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if ((ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt)) !=
|
||||
ERROR_OK)
|
||||
@@ -749,44 +749,40 @@ static int mg_write_cmd(struct command_context_s *cmd_ctx, char *cmd, char **arg
|
||||
goto mg_write_cmd_err;
|
||||
}
|
||||
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
if (duration_measure(&bench) == ERROR_OK)
|
||||
{
|
||||
command_print(CMD_CTX, "wrote %ld bytes from file %s "
|
||||
"in %fs (%0.3f kB/s)", (long)fileio.size, CMD_ARGV[1],
|
||||
duration_elapsed(&bench), duration_kbps(&bench, fileio.size));
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)",
|
||||
fileio.size, args[1], duration_text,
|
||||
(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
|
||||
|
||||
free(duration_text);
|
||||
free(buffer);
|
||||
fileio_close(&fileio);
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
mg_write_cmd_err:
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
free(duration_text);
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
fileio_close(&fileio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mg_dump_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(mg_dump_cmd)
|
||||
{
|
||||
uint32_t address, size_written, size, cnt, res, i;
|
||||
uint32_t address, size, cnt, res, i;
|
||||
uint8_t *buffer;
|
||||
fileio_t fileio;
|
||||
duration_t duration;
|
||||
char *duration_text;
|
||||
struct fileio fileio;
|
||||
int ret;
|
||||
|
||||
if (argc != 4) {
|
||||
if (CMD_ARGC != 4) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
address = strtoul(args[2], NULL, 0);
|
||||
size = strtoul(args[3], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], size);
|
||||
|
||||
ret = fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY);
|
||||
ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
@@ -799,8 +795,10 @@ static int mg_dump_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args
|
||||
cnt = size / MG_FILEIO_CHUNK;
|
||||
res = size % MG_FILEIO_CHUNK;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
struct duration bench;
|
||||
duration_start(&bench);
|
||||
|
||||
size_t size_written;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if ((ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
|
||||
goto mg_dump_cmd_err;
|
||||
@@ -817,22 +815,21 @@ static int mg_dump_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args
|
||||
goto mg_dump_cmd_err;
|
||||
}
|
||||
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
if (duration_measure(&bench) == ERROR_OK)
|
||||
{
|
||||
command_print(CMD_CTX, "dump image (address 0x%8.8" PRIx32 " "
|
||||
"size %" PRIu32 ") to file %s in %fs (%0.3f kB/s)",
|
||||
address, size, CMD_ARGV[1],
|
||||
duration_elapsed(&bench), duration_kbps(&bench, size));
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "dump image (address 0x%8.8" PRIx32 " size %" PRIu32 ") to file %s in %s (%f kB/s)",
|
||||
address, size, args[1], duration_text,
|
||||
(float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
|
||||
|
||||
free(duration_text);
|
||||
free(buffer);
|
||||
fileio_close(&fileio);
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
mg_dump_cmd_err:
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
free(duration_text);
|
||||
free(buffer);
|
||||
free(buffer);
|
||||
fileio_close(&fileio);
|
||||
|
||||
return ret;
|
||||
@@ -840,7 +837,7 @@ mg_dump_cmd_err:
|
||||
|
||||
static int mg_set_feature(mg_feature_id feature, mg_feature_val config)
|
||||
{
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
|
||||
int ret;
|
||||
|
||||
@@ -959,7 +956,7 @@ static int mg_verify_interface(void)
|
||||
uint16_t buff[MG_MFLASH_SECTOR_SIZE >> 1];
|
||||
uint16_t i, j;
|
||||
uint32_t address = mflash_bank->base + MG_BUFFER_OFFSET;
|
||||
target_t *target = mflash_bank->target;
|
||||
struct target *target = mflash_bank->target;
|
||||
int ret;
|
||||
|
||||
for (j = 0; j < 10; j++) {
|
||||
@@ -1214,8 +1211,7 @@ static int mg_erase_nand(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mg_config_cmd(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc)
|
||||
COMMAND_HANDLER(mg_config_cmd)
|
||||
{
|
||||
double fin, fout;
|
||||
mg_pll_t pll;
|
||||
@@ -1227,18 +1223,20 @@ int mg_config_cmd(struct command_context_s *cmd_ctx, char *cmd,
|
||||
if ((ret = mg_mflash_rst()) != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
switch (argc) {
|
||||
switch (CMD_ARGC) {
|
||||
case 2:
|
||||
if (!strcmp(args[1], "boot"))
|
||||
if (!strcmp(CMD_ARGV[1], "boot"))
|
||||
return mg_boot_config();
|
||||
else if (!strcmp(args[1], "storage"))
|
||||
else if (!strcmp(CMD_ARGV[1], "storage"))
|
||||
return mg_storage_config();
|
||||
else
|
||||
return ERROR_COMMAND_NOTFOUND;
|
||||
break;
|
||||
case 3:
|
||||
if (!strcmp(args[1], "pll")) {
|
||||
fin = strtoul(args[2], NULL, 0);
|
||||
if (!strcmp(CMD_ARGV[1], "pll")) {
|
||||
unsigned long freq;
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], freq);
|
||||
fin = freq;
|
||||
|
||||
if (fin > MG_PLL_CLK_OUT) {
|
||||
LOG_ERROR("mflash: input freq. is too large");
|
||||
@@ -1270,64 +1268,131 @@ int mg_config_cmd(struct command_context_s *cmd_ctx, char *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
int mflash_init_drivers(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
if (mflash_bank) {
|
||||
register_command(cmd_ctx, mflash_cmd, "probe", mg_probe_cmd, COMMAND_EXEC, NULL);
|
||||
register_command(cmd_ctx, mflash_cmd, "write", mg_write_cmd, COMMAND_EXEC,
|
||||
"mflash write <num> <file> <address>");
|
||||
register_command(cmd_ctx, mflash_cmd, "dump", mg_dump_cmd, COMMAND_EXEC,
|
||||
"mflash dump <num> <file> <address> <size>");
|
||||
register_command(cmd_ctx, mflash_cmd, "config", mg_config_cmd,
|
||||
COMMAND_EXEC, "mflash config <num> <stage>");
|
||||
}
|
||||
static const struct command_registration mflash_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "probe",
|
||||
.handler = mg_probe_cmd,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Detect bank configuration information",
|
||||
},
|
||||
{
|
||||
.name = "write",
|
||||
.handler = mg_write_cmd,
|
||||
.mode = COMMAND_EXEC,
|
||||
/* FIXME bank_num is unused */
|
||||
.usage = "bank_num filename address",
|
||||
.help = "Write binary file at the specified address.",
|
||||
},
|
||||
{
|
||||
.name = "dump",
|
||||
.handler = mg_dump_cmd,
|
||||
.mode = COMMAND_EXEC,
|
||||
/* FIXME bank_num is unused */
|
||||
.usage = "bank_num filename address size",
|
||||
.help = "Write specified number of bytes from a binary file "
|
||||
"to the specified, address.",
|
||||
},
|
||||
{
|
||||
.name = "config",
|
||||
.handler = mg_config_cmd,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Configure MFLASH options.",
|
||||
.usage = "('boot'|'storage'|'pll' frequency)",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
return ERROR_OK;
|
||||
int mflash_init_drivers(struct command_context *cmd_ctx)
|
||||
{
|
||||
if (!mflash_bank)
|
||||
return ERROR_OK;
|
||||
return register_commands(cmd_ctx, NULL, mflash_exec_command_handlers);
|
||||
}
|
||||
|
||||
static int mg_bank_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(handle_mflash_init_command)
|
||||
{
|
||||
target_t *target;
|
||||
char *str;
|
||||
if (CMD_ARGC != 0)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
static bool mflash_initialized = false;
|
||||
if (mflash_initialized)
|
||||
{
|
||||
LOG_INFO("'mflash init' has already been called");
|
||||
return ERROR_OK;
|
||||
}
|
||||
mflash_initialized = true;
|
||||
|
||||
LOG_DEBUG("Initializing mflash devices...");
|
||||
return mflash_init_drivers(CMD_CTX);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(mg_bank_cmd)
|
||||
{
|
||||
struct target *target;
|
||||
int i;
|
||||
|
||||
if (argc < 4)
|
||||
if (CMD_ARGC < 4)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if ((target = get_target(args[3])) == NULL)
|
||||
if ((target = get_target(CMD_ARGV[3])) == NULL)
|
||||
{
|
||||
LOG_ERROR("target '%s' not defined", args[3]);
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[3]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
mflash_bank = calloc(sizeof(mflash_bank_t), 1);
|
||||
mflash_bank->base = strtoul(args[1], NULL, 0);
|
||||
mflash_bank->rst_pin.num = strtoul(args[2], &str, 0);
|
||||
mflash_bank = calloc(sizeof(struct mflash_bank), 1);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mflash_bank->base);
|
||||
/// @todo Verify how this parsing should work, then document it.
|
||||
char *str;
|
||||
mflash_bank->rst_pin.num = strtoul(CMD_ARGV[2], &str, 0);
|
||||
if (*str)
|
||||
mflash_bank->rst_pin.port[0] = (uint16_t)tolower(str[0]);
|
||||
mflash_bank->rst_pin.port[0] = (uint16_t)
|
||||
tolower((unsigned)str[0]);
|
||||
|
||||
mflash_bank->target = target;
|
||||
|
||||
for (i = 0; mflash_gpio[i] ; i++) {
|
||||
if (! strcmp(mflash_gpio[i]->name, args[0])) {
|
||||
if (! strcmp(mflash_gpio[i]->name, CMD_ARGV[0])) {
|
||||
mflash_bank->gpio_drv = mflash_gpio[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (! mflash_bank->gpio_drv) {
|
||||
LOG_ERROR("%s is unsupported soc", args[0]);
|
||||
LOG_ERROR("%s is unsupported soc", CMD_ARGV[0]);
|
||||
return ERROR_MG_UNSUPPORTED_SOC;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int mflash_register_commands(struct command_context_s *cmd_ctx)
|
||||
static const struct command_registration mflash_config_command_handlers[] = {
|
||||
{
|
||||
.name = "bank",
|
||||
.handler = mg_bank_cmd,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "configure a mflash device bank",
|
||||
.usage = "soc_type base_addr pin_id target",
|
||||
},
|
||||
{
|
||||
.name = "init",
|
||||
.mode = COMMAND_CONFIG,
|
||||
.handler = handle_mflash_init_command,
|
||||
.help = "initialize mflash devices",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration mflash_command_handler[] = {
|
||||
{
|
||||
.name = "mflash",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "mflash command group",
|
||||
.chain = mflash_config_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
int mflash_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
mflash_cmd = register_command(cmd_ctx, NULL, "mflash", NULL, COMMAND_ANY, NULL);
|
||||
register_command(cmd_ctx, mflash_cmd, "bank", mg_bank_cmd, COMMAND_CONFIG,
|
||||
"mflash bank <soc> <base> <RST pin> <target #>");
|
||||
return ERROR_OK;
|
||||
return register_commands(cmd_ctx, NULL, mflash_command_handler);
|
||||
}
|
||||
|
||||
@@ -20,24 +20,24 @@
|
||||
#ifndef _MFLASH_H
|
||||
#define _MFLASH_H
|
||||
|
||||
#include "target.h"
|
||||
struct command_context;
|
||||
|
||||
typedef unsigned long mg_io_uint32;
|
||||
typedef unsigned short mg_io_uint16;
|
||||
typedef unsigned char mg_io_uint8;
|
||||
|
||||
typedef struct mflash_gpio_num_s
|
||||
struct mflash_gpio_num
|
||||
{
|
||||
char port[2];
|
||||
signed short num;
|
||||
} mflash_gpio_num_t;
|
||||
};
|
||||
|
||||
typedef struct mflash_gpio_drv_s
|
||||
struct mflash_gpio_drv
|
||||
{
|
||||
char *name;
|
||||
int (*set_gpio_to_output) (mflash_gpio_num_t gpio);
|
||||
int (*set_gpio_output_val) (mflash_gpio_num_t gpio, uint8_t val);
|
||||
} mflash_gpio_drv_t;
|
||||
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 {
|
||||
|
||||
@@ -125,24 +125,24 @@ typedef struct _mg_pll_t
|
||||
unsigned char output_div; /* 2bit divider */
|
||||
} mg_pll_t;
|
||||
|
||||
typedef struct mg_drv_info_s {
|
||||
struct mg_drv_info {
|
||||
mg_io_type_drv_info drv_id;
|
||||
uint32_t tot_sects;
|
||||
} mg_drv_info_t;
|
||||
};
|
||||
|
||||
typedef struct mflash_bank_s
|
||||
struct mflash_bank
|
||||
{
|
||||
uint32_t base;
|
||||
|
||||
mflash_gpio_num_t rst_pin;
|
||||
struct mflash_gpio_num rst_pin;
|
||||
|
||||
mflash_gpio_drv_t *gpio_drv;
|
||||
target_t *target;
|
||||
mg_drv_info_t *drv_info;
|
||||
} mflash_bank_t;
|
||||
struct mflash_gpio_drv *gpio_drv;
|
||||
struct target *target;
|
||||
struct mg_drv_info *drv_info;
|
||||
};
|
||||
|
||||
extern int mflash_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int mflash_init_drivers(struct command_context_s *cmd_ctx);
|
||||
int mflash_register_commands(struct command_context *cmd_ctx);
|
||||
int mflash_init_drivers(struct command_context *cmd_ctx);
|
||||
|
||||
#define MG_MFLASH_SECTOR_SIZE (0x200) /* 512Bytes = 2^9 */
|
||||
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)
|
||||
|
||||
1672
src/flash/nand.c
1672
src/flash/nand.c
File diff suppressed because it is too large
Load Diff
42
src/flash/nand/Makefile.am
Normal file
42
src/flash/nand/Makefile.am
Normal file
@@ -0,0 +1,42 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src
|
||||
|
||||
noinst_LTLIBRARIES = libocdflashnand.la
|
||||
|
||||
libocdflashnand_la_SOURCES = \
|
||||
ecc.c \
|
||||
ecc_kw.c \
|
||||
core.c \
|
||||
fileio.c \
|
||||
tcl.c \
|
||||
arm_io.c \
|
||||
$(NAND_DRIVERS) \
|
||||
driver.c
|
||||
|
||||
NAND_DRIVERS = \
|
||||
nonce.c \
|
||||
davinci.c \
|
||||
lpc3180.c \
|
||||
mx3.c \
|
||||
orion.c \
|
||||
s3c24xx.c \
|
||||
s3c2410.c \
|
||||
s3c2412.c \
|
||||
s3c2440.c \
|
||||
s3c2443.c \
|
||||
s3c6400.c \
|
||||
at91sam9.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
arm_io.h \
|
||||
core.h \
|
||||
driver.h \
|
||||
fileio.h \
|
||||
imp.h \
|
||||
lpc3180.h \
|
||||
mx3.h \
|
||||
s3c24xx.h \
|
||||
s3c24xx_regs.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
249
src/flash/nand/arm_io.c
Normal file
249
src/flash/nand/arm_io.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by Marvell Semiconductors, Inc.
|
||||
* Written by Nicolas Pitre <nico at marvell.com>
|
||||
*
|
||||
* Copyright (C) 2009 by David Brownell
|
||||
*
|
||||
* 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 "core.h"
|
||||
#include "arm_io.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#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.
|
||||
*
|
||||
* @param target Pointer to the target to copy code to
|
||||
* @param code Pointer to the code area to be copied
|
||||
* @param code_size Size of the code being copied
|
||||
* @param additional Size of the additional area to be allocated in addition to
|
||||
* code
|
||||
* @param area Pointer to a pointer to a working area to copy code to
|
||||
* @return Success or failure of the operation
|
||||
*/
|
||||
int arm_code_to_working_area(struct target *target,
|
||||
const uint32_t *code, unsigned code_size,
|
||||
unsigned additional, struct working_area **area)
|
||||
{
|
||||
uint8_t code_buf[code_size];
|
||||
unsigned i;
|
||||
int retval;
|
||||
unsigned size = code_size + additional;
|
||||
|
||||
/* REVISIT this assumes size doesn't ever change.
|
||||
* That's usually correct; but there are boards with
|
||||
* both large and small page chips, where it won't be...
|
||||
*/
|
||||
|
||||
/* make sure we have a working area */
|
||||
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);
|
||||
return ERROR_NAND_NO_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer code in target endianness */
|
||||
for (i = 0; i < code_size / 4; i++)
|
||||
target_buffer_set_u32(target, code_buf + i * 4, code[i]);
|
||||
|
||||
/* copy code to work area */
|
||||
retval = target_write_memory(target, (*area)->address,
|
||||
4, code_size / 4, code_buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
|
||||
* For now this only supports ARMv4 and ARMv5 cores.
|
||||
*
|
||||
* Enhancements to target_run_algorithm() could enable:
|
||||
* - ARMv6 and ARMv7 cores in ARM mode
|
||||
*
|
||||
* Different code fragments could handle:
|
||||
* - Thumb2 cores like Cortex-M (needs different byteswapping)
|
||||
* - 16-bit wide data (needs different setup too)
|
||||
*
|
||||
* @param nand Pointer to the arm_nand_data struct that defines the I/O
|
||||
* @param data Pointer to the data to be copied to flash
|
||||
* @param size Size of the data being copied
|
||||
* @return Success or failure of the operation
|
||||
*/
|
||||
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 = 0;
|
||||
int retval;
|
||||
|
||||
/* Inputs:
|
||||
* r0 NAND data address (byte wide)
|
||||
* r1 buffer address
|
||||
* r2 buffer length
|
||||
*/
|
||||
static const uint32_t code[] = {
|
||||
0xe4d13001, /* s: ldrb r3, [r1], #1 */
|
||||
0xe5c03000, /* strb r3, [r0] */
|
||||
0xe2522001, /* subs r2, r2, #1 */
|
||||
0x1afffffb, /* bne s */
|
||||
|
||||
/* exit: ARMv4 needs hardware breakpoint */
|
||||
0xe1200070, /* e: bkpt #0 */
|
||||
};
|
||||
|
||||
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) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
nand->op = ARM_NAND_WRITE;
|
||||
|
||||
/* copy data to work area */
|
||||
target_buf = nand->copy_area->address + sizeof(code);
|
||||
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
|
||||
if (retval == ERROR_OK && (size & 3) != 0)
|
||||
retval = target_write_memory(target,
|
||||
target_buf + (size & ~3),
|
||||
1, size & 3, data + (size & ~3));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* set up algorithm and parameters */
|
||||
algo.common_magic = ARM_COMMON_MAGIC;
|
||||
algo.core_mode = ARM_MODE_SVC;
|
||||
algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, nand->data);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||
|
||||
/* armv4 must exit using a hardware breakpoint */
|
||||
if (armv4_5->is_armv4)
|
||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
||||
|
||||
/* use alg to write data from work area to NAND chip */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
nand->copy_area->address, exit, 1000, &algo);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("error executing hosted NAND write");
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an on-chip algorithm for an ARM device to read from a NAND device and
|
||||
* store the data into the host machine's memory.
|
||||
*
|
||||
* @param nand Pointer to the arm_nand_data struct that defines the I/O
|
||||
* @param data Pointer to the data buffer to store the read data
|
||||
* @param size Amount of data to be stored to the buffer.
|
||||
* @return Success or failure of the operation
|
||||
*/
|
||||
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 reg_param reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit = 0;
|
||||
int retval;
|
||||
|
||||
/* Inputs:
|
||||
* r0 buffer address
|
||||
* r1 NAND data address (byte wide)
|
||||
* r2 buffer length
|
||||
*/
|
||||
static const uint32_t code[] = {
|
||||
0xe5d13000, /* s: ldrb r3, [r1] */
|
||||
0xe4c03001, /* strb r3, [r0], #1 */
|
||||
0xe2522001, /* subs r2, r2, #1 */
|
||||
0x1afffffb, /* bne s */
|
||||
|
||||
/* exit: ARMv4 needs hardware breakpoint */
|
||||
0xe1200070, /* e: bkpt #0 */
|
||||
};
|
||||
|
||||
/* create the copy area if not yet available */
|
||||
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) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
nand->op = ARM_NAND_READ;
|
||||
target_buf = nand->copy_area->address + sizeof(code);
|
||||
|
||||
/* set up algorithm and parameters */
|
||||
algo.common_magic = ARM_COMMON_MAGIC;
|
||||
algo.core_mode = ARM_MODE_SVC;
|
||||
algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, target_buf);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, nand->data);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||
|
||||
/* armv4 must exit using a hardware breakpoint */
|
||||
if (armv4_5->is_armv4)
|
||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
||||
|
||||
/* use alg to write data from NAND chip to work area */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
nand->copy_area->address, exit, 1000, &algo);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("error executing hosted NAND read");
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
/* read from work area to the host's memory */
|
||||
retval = target_read_buffer(target, target_buf, size, data);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
57
src/flash/nand/arm_io.h
Normal file
57
src/flash/nand/arm_io.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by David Brownell
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __ARM_NANDIO_H
|
||||
#define __ARM_NANDIO_H
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
};
|
||||
|
||||
/**
|
||||
* The arm_nand_data struct is used for defining NAND I/O operations on an ARM
|
||||
* core.
|
||||
*/
|
||||
struct arm_nand_data {
|
||||
/** Target is proxy for some ARM core. */
|
||||
struct target *target;
|
||||
|
||||
/** The copy area holds code loop and data for I/O operations. */
|
||||
struct working_area *copy_area;
|
||||
|
||||
/** The chunk size is the page size or ECC chunk. */
|
||||
unsigned chunk_size;
|
||||
|
||||
/** Where data is read from or written to. */
|
||||
uint32_t data;
|
||||
|
||||
/** Last operation executed using this struct. */
|
||||
enum arm_nand_op op;
|
||||
|
||||
/* currently implicit: data width == 8 bits (not 16) */
|
||||
};
|
||||
|
||||
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 */
|
||||
756
src/flash/nand/at91sam9.c
Normal file
756
src/flash/nand/at91sam9.c
Normal file
@@ -0,0 +1,756 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by Dean Glazeski
|
||||
* dnglaze@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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <target/arm.h>
|
||||
#include <helper/log.h>
|
||||
#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. */
|
||||
|
||||
/**
|
||||
* Representation of a pin on an AT91SAM9 chip.
|
||||
*/
|
||||
struct at91sam9_pin {
|
||||
/** Target this pin is on. */
|
||||
struct target *target;
|
||||
|
||||
/** Address of the PIO controller. */
|
||||
uint32_t pioc;
|
||||
|
||||
/** Pin number. */
|
||||
uint32_t num;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private data for the controller that is stored in the NAND device structure.
|
||||
*/
|
||||
struct at91sam9_nand {
|
||||
/** Target the NAND is attached to. */
|
||||
struct target *target;
|
||||
|
||||
/** Address of the ECC controller for NAND. */
|
||||
uint32_t ecc;
|
||||
|
||||
/** Address data is written to. */
|
||||
uint32_t data;
|
||||
|
||||
/** Address commands are written to. */
|
||||
uint32_t cmd;
|
||||
|
||||
/** Address addresses are written to. */
|
||||
uint32_t addr;
|
||||
|
||||
/** I/O structure for hosted reads/writes. */
|
||||
struct arm_nand_data io;
|
||||
|
||||
/** Pin representing the ready/~busy line. */
|
||||
struct at91sam9_pin busy;
|
||||
|
||||
/** Pin representing the chip enable. */
|
||||
struct at91sam9_pin ce;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the target is halted and prints an error message if it isn't.
|
||||
*
|
||||
* @param target Target to be checked.
|
||||
* @param label String label for where function is called from.
|
||||
* @return True if the target is halted.
|
||||
*/
|
||||
static int at91sam9_halted(struct target *target, const char *label)
|
||||
{
|
||||
if (target->state == TARGET_HALTED)
|
||||
return true;
|
||||
|
||||
LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the AT91SAM9 NAND controller.
|
||||
*
|
||||
* @param nand NAND device the controller is attached to.
|
||||
* @return Success or failure of initialization.
|
||||
*/
|
||||
static int at91sam9_init(struct nand_device *nand)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!at91sam9_halted(target, "init")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable NAND device attached to a controller.
|
||||
*
|
||||
* @param info NAND controller information for controlling NAND device.
|
||||
* @return Success or failure of the enabling.
|
||||
*/
|
||||
static int at91sam9_enable(struct at91sam9_nand *info)
|
||||
{
|
||||
struct target *target = info->target;
|
||||
|
||||
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable NAND device attached to a controller.
|
||||
*
|
||||
* @param info NAND controller information for controlling NAND device.
|
||||
* @return Success or failure of the disabling.
|
||||
*/
|
||||
static int at91sam9_disable(struct at91sam9_nand *info)
|
||||
{
|
||||
struct target *target = info->target;
|
||||
|
||||
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the NAND device.
|
||||
*
|
||||
* @param nand NAND device to write the command to.
|
||||
* @param command Command to be written.
|
||||
* @return Success or failure of writing the command.
|
||||
*/
|
||||
static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!at91sam9_halted(target, "command")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
at91sam9_enable(info);
|
||||
|
||||
return target_write_u8(target, info->cmd, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the AT91SAM9 NAND controller.
|
||||
*
|
||||
* @param nand NAND device to be reset.
|
||||
* @return Success or failure of reset.
|
||||
*/
|
||||
static int at91sam9_reset(struct nand_device *nand)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
|
||||
if (!at91sam9_halted(info->target, "reset")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return at91sam9_disable(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an address to the NAND device attached to an AT91SAM9 NAND controller.
|
||||
*
|
||||
* @param nand NAND device to send the address to.
|
||||
* @param address Address to be sent.
|
||||
* @return Success or failure of sending the address.
|
||||
*/
|
||||
static int at91sam9_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!at91sam9_halted(info->target, "address")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return target_write_u8(target, info->addr, address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data directly from the NAND device attached to an AT91SAM9 NAND
|
||||
* controller.
|
||||
*
|
||||
* @param nand NAND device to read from.
|
||||
* @param data Pointer to where the data should be put.
|
||||
* @return Success or failure of reading the data.
|
||||
*/
|
||||
static int at91sam9_read_data(struct nand_device *nand, void *data)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!at91sam9_halted(info->target, "read data")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return target_read_u8(target, info->data, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data directly to the NAND device attached to an AT91SAM9 NAND
|
||||
* controller.
|
||||
*
|
||||
* @param nand NAND device to be written to.
|
||||
* @param data Data to be written.
|
||||
* @return Success or failure of the data write.
|
||||
*/
|
||||
static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!at91sam9_halted(target, "write data")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return target_write_u8(target, info->data, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the NAND device is ready by looking at the ready/~busy pin.
|
||||
*
|
||||
* @param nand NAND device to check.
|
||||
* @param timeout Time in milliseconds to wait for NAND to be ready.
|
||||
* @return True if the NAND is ready in the timeout period.
|
||||
*/
|
||||
static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
uint32_t status;
|
||||
|
||||
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)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
} while (timeout-- > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a block of data from the NAND device attached to an AT91SAM9. This
|
||||
* utilizes the ARM hosted NAND read function.
|
||||
*
|
||||
* @param nand NAND device to read from.
|
||||
* @param data Pointer to where the read data should be placed.
|
||||
* @param size Size of the data being read.
|
||||
* @return Success or failure of the hosted read.
|
||||
*/
|
||||
static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct arm_nand_data *io = &info->io;
|
||||
int status;
|
||||
|
||||
if (!at91sam9_halted(info->target, "read block")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
io->chunk_size = nand->page_size;
|
||||
status = arm_nandread(io, data, size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a block of data to a NAND device attached to an AT91SAM9. This uses
|
||||
* the ARM hosted write function to write the data.
|
||||
*
|
||||
* @param nand NAND device to write to.
|
||||
* @param data Data to be written to device.
|
||||
* @param size Size of the data being written.
|
||||
* @return Success or failure of the hosted write.
|
||||
*/
|
||||
static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct arm_nand_data *io = &info->io;
|
||||
int status;
|
||||
|
||||
if (!at91sam9_halted(info->target, "write block")) {
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
io->chunk_size = nand->page_size;
|
||||
status = arm_nandwrite(io, data, size);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ECC controller on the AT91SAM9.
|
||||
*
|
||||
* @param target Target to configure ECC on.
|
||||
* @param info NAND controller information for where the ECC is.
|
||||
* @return Success or failure of initialization.
|
||||
*/
|
||||
static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
|
||||
{
|
||||
if (!info->ecc) {
|
||||
LOG_ERROR("ECC controller address must be set when not reading raw NAND data");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
// reset ECC parity registers
|
||||
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an area for the OOB based on whether a user is requesting the OOB
|
||||
* data. This determines the size of the OOB and allocates the space in case
|
||||
* the user has not requested the OOB data.
|
||||
*
|
||||
* @param nand NAND device we are creating an OOB for.
|
||||
* @param oob Pointer to the user supplied OOB area.
|
||||
* @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)
|
||||
{
|
||||
if (!oob) {
|
||||
// user doesn't want OOB, allocate it
|
||||
if (nand->page_size == 512) {
|
||||
*size = 16;
|
||||
} else if (nand->page_size == 2048) {
|
||||
*size = 64;
|
||||
}
|
||||
|
||||
oob = malloc(*size);
|
||||
if (!oob) {
|
||||
LOG_ERROR("Unable to allocate space for OOB");
|
||||
}
|
||||
|
||||
memset(oob, 0xFF, *size);
|
||||
}
|
||||
|
||||
return oob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC
|
||||
* controller on chip. This makes an attempt to correct any errors that are
|
||||
* encountered while reading the page of data.
|
||||
*
|
||||
* @param nand NAND device to read from
|
||||
* @param page Page to be read.
|
||||
* @param data Pointer to where data should be read to.
|
||||
* @param data_size Size of the data to be read.
|
||||
* @param oob Pointer to where OOB data should be read to.
|
||||
* @param oob_size Size of the OOB data to be read.
|
||||
* @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)
|
||||
{
|
||||
int retval;
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
uint8_t *oob_data;
|
||||
uint32_t status;
|
||||
|
||||
retval = at91sam9_ecc_init(target, info);
|
||||
if (ERROR_OK != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
|
||||
if (ERROR_OK != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
retval = nand_read_data_page(nand, data, data_size);
|
||||
if (ERROR_OK != retval) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
||||
retval = nand_read_data_page(nand, oob_data, oob_size);
|
||||
if (ERROR_OK == retval && data) {
|
||||
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
|
||||
if (status & 1) {
|
||||
LOG_ERROR("Error detected!");
|
||||
if (status & 4) {
|
||||
LOG_ERROR("Multiple errors encountered; unrecoverable!");
|
||||
} else {
|
||||
// attempt recovery
|
||||
uint32_t parity;
|
||||
|
||||
target_read_u32(target,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (status & 2) {
|
||||
// we could write back correct ECC data
|
||||
LOG_ERROR("Error in ECC bytes detected");
|
||||
}
|
||||
}
|
||||
|
||||
if (!oob) {
|
||||
// if it wasn't asked for, free it
|
||||
free(oob_data);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a page of data including 1-bit ECC information to a NAND device
|
||||
* attached to an AT91SAM9 controller. If there is OOB data to be written,
|
||||
* this will ignore the computed ECC from the ECC controller.
|
||||
*
|
||||
* @param nand NAND device to write to.
|
||||
* @param page Page to write.
|
||||
* @param data Pointer to data being written.
|
||||
* @param data_size Size of the data being written.
|
||||
* @param oob Pointer to OOB data being written.
|
||||
* @param oob_size Size of the OOB data.
|
||||
* @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)
|
||||
{
|
||||
struct at91sam9_nand *info = nand->controller_priv;
|
||||
struct target *target = info->target;
|
||||
int retval;
|
||||
uint8_t *oob_data = oob;
|
||||
uint32_t parity, nparity;
|
||||
|
||||
retval = at91sam9_ecc_init(target, info);
|
||||
if (ERROR_OK != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
||||
if (ERROR_OK != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
retval = nand_write_data_page(nand, data, data_size);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("Unable to write data to NAND device");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
|
||||
|
||||
if (!oob) {
|
||||
// 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);
|
||||
|
||||
oob_data[0] = (uint8_t) parity;
|
||||
oob_data[1] = (uint8_t) (parity >> 8);
|
||||
oob_data[2] = (uint8_t) nparity;
|
||||
oob_data[3] = (uint8_t) (nparity >> 8);
|
||||
}
|
||||
|
||||
retval = nand_write_data_page(nand, oob_data, oob_size);
|
||||
|
||||
if (!oob) {
|
||||
free(oob_data);
|
||||
}
|
||||
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("Unable to write OOB data to NAND");
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = nand_write_finish(nand);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the initial NAND device command for AT91SAM9 controllers. This
|
||||
* initializes much of the controller information struct to be ready for future
|
||||
* reads and writes.
|
||||
*/
|
||||
NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
|
||||
{
|
||||
struct target *target = NULL;
|
||||
unsigned long chip = 0, ecc = 0;
|
||||
struct at91sam9_nand *info = NULL;
|
||||
|
||||
LOG_DEBUG("AT91SAM9 NAND Device Command\n");
|
||||
|
||||
if (CMD_ARGC < 3 || CMD_ARGC > 4) {
|
||||
LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
target = get_target(CMD_ARGV[1]);
|
||||
if (!target) {
|
||||
LOG_ERROR("invalid target: %s", CMD_ARGV[1]);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||
if (chip == 0) {
|
||||
LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (CMD_ARGC == 4) {
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc);
|
||||
if (ecc == 0) {
|
||||
LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (!info) {
|
||||
LOG_ERROR("unable to allocate space for controller private data");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
info->target = target;
|
||||
info->data = chip;
|
||||
info->cmd = chip | (1 << 22);
|
||||
info->addr = chip | (1 << 21);
|
||||
info->ecc = ecc;
|
||||
|
||||
nand->controller_priv = info;
|
||||
info->io.target = target;
|
||||
info->io.data = info->data;
|
||||
info->io.op = ARM_NAND_NONE;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the AT91SAM9 CLE command for specifying the address line to use for
|
||||
* writing commands to a NAND device.
|
||||
*/
|
||||
COMMAND_HANDLER(handle_at91sam9_cle_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, address_line;
|
||||
|
||||
if (CMD_ARGC != 2) {
|
||||
command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
if (!nand) {
|
||||
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
info = nand->controller_priv;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
|
||||
info->cmd = info->data | (1 << address_line);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the AT91SAM9 ALE command for specifying the address line to use for
|
||||
* writing addresses to the NAND device.
|
||||
*/
|
||||
COMMAND_HANDLER(handle_at91sam9_ale_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, address_line;
|
||||
|
||||
if (CMD_ARGC != 2) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
if (!nand) {
|
||||
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
info = nand->controller_priv;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
|
||||
info->addr = info->data | (1 << address_line);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the
|
||||
* RDY/~BUSY line from the NAND device.
|
||||
*/
|
||||
COMMAND_HANDLER(handle_at91sam9_rdy_busy_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, base_pioc, pin_num;
|
||||
|
||||
if (CMD_ARGC != 3) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
if (!nand) {
|
||||
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
info = nand->controller_priv;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
|
||||
info->busy.pioc = base_pioc;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
|
||||
info->busy.num = pin_num;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the AT91SAM9 CE command for specifying the pin that is used to enable
|
||||
* or disable the NAND device.
|
||||
*/
|
||||
COMMAND_HANDLER(handle_at91sam9_ce_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct at91sam9_nand *info = NULL;
|
||||
unsigned num, base_pioc, pin_num;
|
||||
|
||||
if (CMD_ARGC != 3) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
nand = get_nand_device_by_num(num);
|
||||
if (!nand) {
|
||||
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
info = nand->controller_priv;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
|
||||
info->ce.pioc = base_pioc;
|
||||
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
|
||||
info->ce.num = pin_num;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration at91sam9_sub_command_handlers[] = {
|
||||
{
|
||||
.name = "cle",
|
||||
.handler = handle_at91sam9_cle_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set command latch enable address line (default is 22)",
|
||||
.usage = "bank_id address_line",
|
||||
},
|
||||
{
|
||||
.name = "ale",
|
||||
.handler = handle_at91sam9_ale_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set address latch enable address line (default is 21)",
|
||||
.usage = "bank_id address_line",
|
||||
},
|
||||
{
|
||||
.name = "rdy_busy",
|
||||
.handler = handle_at91sam9_rdy_busy_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the GPIO input pin connected to "
|
||||
"the RDY/~BUSY signal (no default)",
|
||||
.usage = "bank_id pio_base_addr pin_num",
|
||||
},
|
||||
{
|
||||
.name = "ce",
|
||||
.handler = handle_at91sam9_ce_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the GPIO output pin connected to "
|
||||
"the chip enable signal (no default)",
|
||||
.usage = "bank_id pio_base_addr pin_num",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration at91sam9_command_handler[] = {
|
||||
{
|
||||
.name = "at91sam9",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "AT91SAM9 NAND flash controller commands",
|
||||
.chain = at91sam9_sub_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure representing the AT91SAM9 NAND controller.
|
||||
*/
|
||||
struct nand_flash_controller at91sam9_nand_controller = {
|
||||
.name = "at91sam9",
|
||||
.nand_device_command = at91sam9_nand_device_command,
|
||||
.commands = at91sam9_command_handler,
|
||||
.init = at91sam9_init,
|
||||
.command = at91sam9_command,
|
||||
.reset = at91sam9_reset,
|
||||
.address = at91sam9_address,
|
||||
.read_data = at91sam9_read_data,
|
||||
.write_data = at91sam9_write_data,
|
||||
.nand_ready = at91sam9_nand_ready,
|
||||
.read_block_data = at91sam9_read_block_data,
|
||||
.write_block_data = at91sam9_write_block_data,
|
||||
.read_page = at91sam9_read_page,
|
||||
.write_page = at91sam9_write_page,
|
||||
};
|
||||
899
src/flash/nand/core.c
Normal file
899
src/flash/nand/core.c
Normal file
@@ -0,0 +1,899 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Partially based on drivers/mtd/nand_ids.c from Linux. *
|
||||
* *
|
||||
* 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"
|
||||
|
||||
/* configured NAND devices and NAND Flash command handler */
|
||||
struct nand_device *nand_devices = NULL;
|
||||
|
||||
void nand_device_add(struct nand_device *c)
|
||||
{
|
||||
if (nand_devices) {
|
||||
struct nand_device *p = nand_devices;
|
||||
while (p && p->next) p = p->next;
|
||||
p->next = c;
|
||||
} else
|
||||
nand_devices = c;
|
||||
}
|
||||
|
||||
|
||||
/* Chip ID list
|
||||
*
|
||||
* Name, ID code, pagesize, chipsize in MegaByte, eraseblock size,
|
||||
* options
|
||||
*
|
||||
* Pagesize; 0, 256, 512
|
||||
* 0 get this information from the extended chip ID
|
||||
* 256 256 Byte page size
|
||||
* 512 512 Byte page size
|
||||
*/
|
||||
static struct nand_info nand_flash_ids[] =
|
||||
{
|
||||
/* start "museum" IDs */
|
||||
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
||||
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
|
||||
{"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
|
||||
{"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
|
||||
{"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
|
||||
{"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
|
||||
{"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
|
||||
{"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
|
||||
|
||||
{"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
|
||||
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
|
||||
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
/* end "museum" IDs */
|
||||
|
||||
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
||||
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
||||
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
||||
|
||||
{"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
|
||||
{"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
|
||||
{"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
||||
|
||||
{"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
|
||||
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
|
||||
{"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
||||
|
||||
{"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
|
||||
{"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
|
||||
{"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
|
||||
{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
||||
{"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
||||
|
||||
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
|
||||
|
||||
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
|
||||
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
|
||||
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
|
||||
|
||||
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
|
||||
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
|
||||
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
|
||||
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
|
||||
|
||||
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
|
||||
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
|
||||
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
|
||||
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
|
||||
|
||||
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
|
||||
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
|
||||
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
|
||||
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
|
||||
|
||||
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
|
||||
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
|
||||
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
|
||||
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
|
||||
|
||||
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
|
||||
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
|
||||
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
|
||||
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
|
||||
|
||||
{NULL, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* Manufacturer ID list
|
||||
*/
|
||||
static struct nand_manufacturer nand_manuf_ids[] =
|
||||
{
|
||||
{0x0, "unknown"},
|
||||
{NAND_MFR_TOSHIBA, "Toshiba"},
|
||||
{NAND_MFR_SAMSUNG, "Samsung"},
|
||||
{NAND_MFR_FUJITSU, "Fujitsu"},
|
||||
{NAND_MFR_NATIONAL, "National"},
|
||||
{NAND_MFR_RENESAS, "Renesas"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix"},
|
||||
{NAND_MFR_MICRON, "Micron"},
|
||||
{0x0, NULL},
|
||||
};
|
||||
|
||||
/*
|
||||
* Define default oob placement schemes for large and small page devices
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static struct nand_ecclayout nand_oob_8 = {
|
||||
.eccbytes = 3,
|
||||
.eccpos = {0, 1, 2},
|
||||
.oobfree = {
|
||||
{.offset = 3,
|
||||
.length = 2},
|
||||
{.offset = 6,
|
||||
.length = 2}}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct nand_device *get_nand_device_by_name(const char *name)
|
||||
{
|
||||
unsigned requested = get_flash_name_index(name);
|
||||
unsigned found = 0;
|
||||
|
||||
struct nand_device *nand;
|
||||
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))
|
||||
continue;
|
||||
if (++found < requested)
|
||||
continue;
|
||||
return nand;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (i++ == num)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||
struct nand_device **nand)
|
||||
{
|
||||
const char *str = CMD_ARGV[name_index];
|
||||
*nand = get_nand_device_by_name(str);
|
||||
if (*nand)
|
||||
return ERROR_OK;
|
||||
|
||||
unsigned num;
|
||||
COMMAND_PARSE_NUMBER(uint, str, num);
|
||||
*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_OK;
|
||||
}
|
||||
|
||||
int nand_build_bbt(struct nand_device *nand, int first, int last)
|
||||
{
|
||||
uint32_t page = 0x0;
|
||||
int i;
|
||||
uint8_t oob[6];
|
||||
|
||||
if ((first < 0) || (first >= nand->num_blocks))
|
||||
first = 0;
|
||||
|
||||
if ((last >= nand->num_blocks) || (last == -1))
|
||||
last = nand->num_blocks - 1;
|
||||
|
||||
for (i = first; i < last; i++)
|
||||
{
|
||||
nand_read_page(nand, page, NULL, 0, oob, 6);
|
||||
|
||||
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))))
|
||||
{
|
||||
LOG_WARNING("bad block: %i", i);
|
||||
nand->blocks[i].is_bad = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nand->blocks[i].is_bad = 0;
|
||||
}
|
||||
|
||||
page += (nand->erase_size / nand->page_size);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_read_status(struct nand_device *nand, uint8_t *status)
|
||||
{
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
/* Send read status command */
|
||||
nand->controller->command(nand, NAND_CMD_STATUS);
|
||||
|
||||
alive_sleep(1);
|
||||
|
||||
/* read status */
|
||||
if (nand->device->options & NAND_BUSWIDTH_16)
|
||||
{
|
||||
uint16_t data;
|
||||
nand->controller->read_data(nand, &data);
|
||||
*status = data & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
nand->controller->read_data(nand, status);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nand_poll_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
nand->controller->command(nand, NAND_CMD_STATUS);
|
||||
do {
|
||||
if (nand->device->options & NAND_BUSWIDTH_16) {
|
||||
uint16_t data;
|
||||
nand->controller->read_data(nand, &data);
|
||||
status = data & 0xff;
|
||||
} else {
|
||||
nand->controller->read_data(nand, &status);
|
||||
}
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
alive_sleep(1);
|
||||
} while (timeout--);
|
||||
|
||||
return (status & NAND_STATUS_READY) != 0;
|
||||
}
|
||||
|
||||
int nand_probe(struct nand_device *nand)
|
||||
{
|
||||
uint8_t manufacturer_id, device_id;
|
||||
uint8_t id_buff[6];
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
/* clear device data */
|
||||
nand->device = NULL;
|
||||
nand->manufacturer = NULL;
|
||||
|
||||
/* clear device parameters */
|
||||
nand->bus_width = 0;
|
||||
nand->address_cycles = 0;
|
||||
nand->page_size = 0;
|
||||
nand->erase_size = 0;
|
||||
|
||||
/* initialize controller (device parameters are zero, use controller default) */
|
||||
if ((retval = nand->controller->init(nand) != 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");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown controller initialization failure");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
nand->controller->command(nand, NAND_CMD_RESET);
|
||||
nand->controller->reset(nand);
|
||||
|
||||
nand->controller->command(nand, NAND_CMD_READID);
|
||||
nand->controller->address(nand, 0x0);
|
||||
|
||||
if (nand->bus_width == 8)
|
||||
{
|
||||
nand->controller->read_data(nand, &manufacturer_id);
|
||||
nand->controller->read_data(nand, &device_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t data_buf;
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
manufacturer_id = data_buf & 0xff;
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
device_id = data_buf & 0xff;
|
||||
}
|
||||
|
||||
for (i = 0; nand_flash_ids[i].name; i++)
|
||||
{
|
||||
if (nand_flash_ids[i].id == device_id)
|
||||
{
|
||||
nand->device = &nand_flash_ids[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("found %s (%s)", nand->device->name, nand->manufacturer->name);
|
||||
|
||||
/* initialize device parameters */
|
||||
|
||||
/* bus width */
|
||||
if (nand->device->options & NAND_BUSWIDTH_16)
|
||||
nand->bus_width = 16;
|
||||
else
|
||||
nand->bus_width = 8;
|
||||
|
||||
/* Do we need extended device probe information? */
|
||||
if (nand->device->page_size == 0 ||
|
||||
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
|
||||
{
|
||||
uint16_t data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
id_buff[3] = data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
id_buff[4] = data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
id_buff[5] = data_buf >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* page size */
|
||||
if (nand->device->page_size == 0)
|
||||
{
|
||||
nand->page_size = 1 << (10 + (id_buff[4] & 3));
|
||||
}
|
||||
else if (nand->device->page_size == 256)
|
||||
{
|
||||
LOG_ERROR("NAND flashes with 256 byte pagesize are not supported");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
nand->page_size = nand->device->page_size;
|
||||
}
|
||||
|
||||
/* number of address cycles */
|
||||
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
|
||||
{
|
||||
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
|
||||
nand->address_cycles = 5;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown controller initialization failure");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
nand->blocks[i].size = nand->erase_size;
|
||||
nand->blocks[i].offset = i * nand->erase_size;
|
||||
nand->blocks[i].is_erased = -1;
|
||||
nand->blocks[i].is_bad = -1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
||||
{
|
||||
int i;
|
||||
uint32_t page;
|
||||
uint8_t status;
|
||||
int retval;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
if ((first_block < 0) || (last_block > nand->num_blocks))
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
nand_build_bbt(nand, i, last_block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 0xff);
|
||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||
|
||||
/* 3rd cycle only on devices with more than 32 MiB */
|
||||
if (nand->address_cycles >= 4)
|
||||
nand->controller->address(nand, (page >> 16) & 0xff);
|
||||
|
||||
/* 4th cycle only on devices with more than 8 GiB */
|
||||
if (nand->address_cycles >= 5)
|
||||
nand->controller->address(nand, (page >> 24) & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 0xff);
|
||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||
|
||||
/* 3rd cycle only on devices with more than 128 MiB */
|
||||
if (nand->address_cycles >= 5)
|
||||
nand->controller->address(nand, (page >> 16) & 0xff);
|
||||
}
|
||||
|
||||
/* Send erase confirm command */
|
||||
nand->controller->command(nand, NAND_CMD_ERASE2);
|
||||
|
||||
retval = nand->controller->nand_ready ?
|
||||
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)
|
||||
{
|
||||
LOG_ERROR("couldn't read status");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (status & 0x1)
|
||||
{
|
||||
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
|
||||
(nand->blocks[i].is_bad == 1)
|
||||
? "bad " : "",
|
||||
i, status);
|
||||
/* continue; other blocks might still be erasable */
|
||||
}
|
||||
|
||||
nand->blocks[i].is_erased = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
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)
|
||||
{
|
||||
LOG_ERROR("reads need to be page aligned");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
page = malloc(nand->page_size);
|
||||
|
||||
while (data_size > 0)
|
||||
{
|
||||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
||||
uint32_t page_address;
|
||||
|
||||
|
||||
page_address = address / nand->page_size;
|
||||
|
||||
nand_read_page(nand, page_address, page, nand->page_size, NULL, 0);
|
||||
|
||||
memcpy(data, page, thisrun_size);
|
||||
|
||||
address += thisrun_size;
|
||||
data += thisrun_size;
|
||||
data_size -= thisrun_size;
|
||||
}
|
||||
|
||||
free(page);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LOG_ERROR("writes need to be page aligned");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
page = malloc(nand->page_size);
|
||||
|
||||
while (data_size > 0)
|
||||
{
|
||||
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
|
||||
uint32_t page_address;
|
||||
|
||||
memset(page, 0xff, nand->page_size);
|
||||
memcpy(page, data, thisrun_size);
|
||||
|
||||
page_address = address / nand->page_size;
|
||||
|
||||
nand_write_page(nand, page_address, page, nand->page_size, NULL, 0);
|
||||
|
||||
address += thisrun_size;
|
||||
data += thisrun_size;
|
||||
data_size -= thisrun_size;
|
||||
}
|
||||
|
||||
free(page);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
uint32_t block;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
block = page / (nand->erase_size / nand->page_size);
|
||||
if (nand->blocks[block].is_erased == 1)
|
||||
nand->blocks[block].is_erased = 0;
|
||||
|
||||
if (nand->use_raw || nand->controller->write_page == NULL)
|
||||
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||
else
|
||||
return nand->controller->write_page(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
if (nand->use_raw || nand->controller->read_page == NULL)
|
||||
return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||
else
|
||||
return nand->controller->read_page(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
int nand_page_command(struct nand_device *nand, uint32_t page,
|
||||
uint8_t cmd, bool oob_only)
|
||||
{
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
if (oob_only && NAND_CMD_READ0 == cmd && nand->page_size <= 512)
|
||||
cmd = NAND_CMD_READOOB;
|
||||
|
||||
nand->controller->command(nand, cmd);
|
||||
|
||||
if (nand->page_size <= 512) {
|
||||
/* small page device */
|
||||
|
||||
/* column (always 0, we start at the beginning of a page/OOB area) */
|
||||
nand->controller->address(nand, 0x0);
|
||||
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 0xff);
|
||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||
|
||||
/* 4th cycle only on devices with more than 32 MiB */
|
||||
if (nand->address_cycles >= 4)
|
||||
nand->controller->address(nand, (page >> 16) & 0xff);
|
||||
|
||||
/* 5th cycle only on devices with more than 8 GiB */
|
||||
if (nand->address_cycles >= 5)
|
||||
nand->controller->address(nand, (page >> 24) & 0xff);
|
||||
} else {
|
||||
/* large page device */
|
||||
|
||||
/* column (0 when we start at the beginning of a page,
|
||||
* or 2048 for the beginning of OOB area)
|
||||
*/
|
||||
nand->controller->address(nand, 0x0);
|
||||
if (oob_only)
|
||||
nand->controller->address(nand, 0x8);
|
||||
else
|
||||
nand->controller->address(nand, 0x0);
|
||||
|
||||
/* row */
|
||||
nand->controller->address(nand, page & 0xff);
|
||||
nand->controller->address(nand, (page >> 8) & 0xff);
|
||||
|
||||
/* 5th cycle only on devices with more than 128 MiB */
|
||||
if (nand->address_cycles >= 5)
|
||||
nand->controller->address(nand, (page >> 16) & 0xff);
|
||||
|
||||
/* large page devices need a start command if reading */
|
||||
if (NAND_CMD_READ0 == cmd)
|
||||
nand->controller->command(nand, NAND_CMD_READSTART);
|
||||
}
|
||||
|
||||
if (nand->controller->nand_ready) {
|
||||
if (!nand->controller->nand_ready(nand, 100))
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
} else {
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
|
||||
{
|
||||
int retval = ERROR_NAND_NO_BUFFER;
|
||||
|
||||
if (nand->controller->read_block_data != NULL)
|
||||
retval = (nand->controller->read_block_data)(nand, data, size);
|
||||
|
||||
if (ERROR_NAND_NO_BUFFER == retval) {
|
||||
uint32_t i;
|
||||
int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
||||
|
||||
retval = ERROR_OK;
|
||||
for (i = 0; retval == ERROR_OK && i < size; i += incr) {
|
||||
retval = nand->controller->read_data(nand, data);
|
||||
data += incr;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (data)
|
||||
nand_read_data_page(nand, data, data_size);
|
||||
|
||||
if (oob)
|
||||
nand_read_data_page(nand, oob, oob_size);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
|
||||
{
|
||||
int retval = ERROR_NAND_NO_BUFFER;
|
||||
|
||||
if (nand->controller->write_block_data != NULL)
|
||||
retval = (nand->controller->write_block_data)(nand, data, size);
|
||||
|
||||
if (ERROR_NAND_NO_BUFFER == retval) {
|
||||
bool is16bit = nand->device->options & NAND_BUSWIDTH_16;
|
||||
uint32_t incr = is16bit ? 2 : 1;
|
||||
uint16_t write_data;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < size; i += incr) {
|
||||
if (is16bit)
|
||||
write_data = le_to_h_u16(data);
|
||||
else
|
||||
write_data = *data;
|
||||
|
||||
retval = nand->controller->write_data(nand, write_data);
|
||||
if (ERROR_OK != retval)
|
||||
break;
|
||||
|
||||
data += incr;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int nand_write_finish(struct nand_device *nand)
|
||||
{
|
||||
int retval;
|
||||
uint8_t status;
|
||||
|
||||
nand->controller->command(nand, NAND_CMD_PAGEPROG);
|
||||
|
||||
retval = nand->controller->nand_ready ?
|
||||
nand->controller->nand_ready(nand, 100) :
|
||||
nand_poll_ready(nand, 100);
|
||||
if (!retval)
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
|
||||
retval = nand_read_status(nand, &status);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("couldn't read status");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
LOG_ERROR("write operation didn't pass, status: 0x%2.2x",
|
||||
status);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (data) {
|
||||
retval = nand_write_data_page(nand, data, data_size);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("Unable to write data to NAND device");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (oob) {
|
||||
retval = nand_write_data_page(nand, oob, oob_size);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("Unable to write OOB data to NAND device");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return nand_write_finish(nand);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Partially based on linux/include/linux/mtd/nand.h *
|
||||
* Copyright (C) 2000 David Woodhouse <dwmw2@mvhi.com> *
|
||||
@@ -22,67 +22,57 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef NAND_H
|
||||
#define NAND_H
|
||||
#ifndef FLASH_NAND_CORE_H
|
||||
#define FLASH_NAND_CORE_H
|
||||
|
||||
#include "flash.h"
|
||||
#include <flash/common.h>
|
||||
|
||||
struct nand_device_s;
|
||||
|
||||
typedef struct nand_flash_controller_s
|
||||
{
|
||||
char *name;
|
||||
int (*nand_device_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||
int (*init)(struct nand_device_s *device);
|
||||
int (*reset)(struct nand_device_s *device);
|
||||
int (*command)(struct nand_device_s *device, uint8_t command);
|
||||
int (*address)(struct nand_device_s *device, uint8_t address);
|
||||
int (*write_data)(struct nand_device_s *device, uint16_t data);
|
||||
int (*read_data)(struct nand_device_s *device, void *data);
|
||||
int (*write_block_data)(struct nand_device_s *device, uint8_t *data, int size);
|
||||
int (*read_block_data)(struct nand_device_s *device, uint8_t *data, int size);
|
||||
int (*write_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int (*read_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int (*controller_ready)(struct nand_device_s *device, int timeout);
|
||||
int (*nand_ready)(struct nand_device_s *device, int timeout);
|
||||
} nand_flash_controller_t;
|
||||
|
||||
typedef struct nand_block_s
|
||||
/**
|
||||
* Representation of a single NAND block in a NAND device.
|
||||
*/
|
||||
struct nand_block
|
||||
{
|
||||
/** Offset to the block. */
|
||||
uint32_t offset;
|
||||
|
||||
/** Size of the block. */
|
||||
uint32_t size;
|
||||
|
||||
/** True if the block has been erased. */
|
||||
int is_erased;
|
||||
|
||||
/** True if the block is bad. */
|
||||
int is_bad;
|
||||
} nand_block_t;
|
||||
};
|
||||
|
||||
struct nand_oobfree {
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
|
||||
typedef struct nand_ecclayout_s {
|
||||
struct nand_ecclayout {
|
||||
int eccbytes;
|
||||
int eccpos[64];
|
||||
int oobavail;
|
||||
struct nand_oobfree oobfree[2];
|
||||
} nand_ecclayout_t;
|
||||
};
|
||||
|
||||
typedef struct nand_device_s
|
||||
struct nand_device
|
||||
{
|
||||
nand_flash_controller_t *controller;
|
||||
char *name;
|
||||
struct nand_flash_controller *controller;
|
||||
void *controller_priv;
|
||||
struct nand_manufacturer_s *manufacturer;
|
||||
struct nand_info_s *device;
|
||||
struct nand_manufacturer *manufacturer;
|
||||
struct nand_info *device;
|
||||
int bus_width;
|
||||
int address_cycles;
|
||||
int page_size;
|
||||
int erase_size;
|
||||
int use_raw;
|
||||
int num_blocks;
|
||||
nand_block_t *blocks;
|
||||
struct nand_device_s *next;
|
||||
} nand_device_t;
|
||||
struct nand_block *blocks;
|
||||
struct nand_device *next;
|
||||
};
|
||||
|
||||
/* NAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
@@ -98,13 +88,13 @@ enum
|
||||
NAND_MFR_MICRON = 0x2c,
|
||||
};
|
||||
|
||||
typedef struct nand_manufacturer_s
|
||||
struct nand_manufacturer
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
} nand_manufacturer_t;
|
||||
};
|
||||
|
||||
typedef struct nand_info_s
|
||||
struct nand_info
|
||||
{
|
||||
char *name;
|
||||
int id;
|
||||
@@ -112,7 +102,7 @@ typedef struct nand_info_s
|
||||
int chip_size;
|
||||
int erase_size;
|
||||
int options;
|
||||
} nand_info_t;
|
||||
};
|
||||
|
||||
/* Option constants for bizarre disfunctionality and real features
|
||||
*/
|
||||
@@ -206,16 +196,46 @@ enum oob_formats
|
||||
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
|
||||
};
|
||||
|
||||
/* Function prototypes */
|
||||
extern nand_device_t *get_nand_device_by_num(int num);
|
||||
extern int nand_read_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
extern int nand_write_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
extern int nand_read_status(struct nand_device_s *device, uint8_t *status);
|
||||
extern int nand_calculate_ecc(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
|
||||
extern int nand_calculate_ecc_kw(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
|
||||
|
||||
extern int nand_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int nand_init(struct command_context_s *cmd_ctx);
|
||||
/**
|
||||
* Returns the flash bank specified by @a name, which matches the
|
||||
* driver name and a suffix (option) specify the driver-specific
|
||||
* bank number. The suffix consists of the '.' and the driver-specific
|
||||
* bank number: when two davinci banks are defined, then 'davinci.1' refers
|
||||
* to the second (e.g. DM355EVM).
|
||||
*/
|
||||
struct nand_device *get_nand_device_by_name(const char *name);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
int nand_calculate_ecc_kw(struct nand_device *nand,
|
||||
const uint8_t *dat, uint8_t *ecc_code);
|
||||
|
||||
int nand_register_commands(struct command_context *cmd_ctx);
|
||||
int nand_init(struct command_context *cmd_ctx);
|
||||
|
||||
/// helper for parsing a nand device command argument string
|
||||
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||
struct nand_device **nand);
|
||||
|
||||
|
||||
#define ERROR_NAND_DEVICE_INVALID (-1100)
|
||||
#define ERROR_NAND_OPERATION_FAILED (-1101)
|
||||
@@ -225,4 +245,5 @@ extern int nand_init(struct command_context_s *cmd_ctx);
|
||||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
||||
#define ERROR_NAND_NO_BUFFER (-1106)
|
||||
|
||||
#endif /* NAND_H */
|
||||
#endif // FLASH_NAND_CORE_H
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arm_nandio.h"
|
||||
|
||||
#include "imp.h"
|
||||
#include "arm_io.h"
|
||||
#include <target/target.h>
|
||||
|
||||
enum ecc {
|
||||
HWECC1, /* all controllers support 1-bit ECC */
|
||||
@@ -38,7 +39,7 @@ enum ecc {
|
||||
};
|
||||
|
||||
struct davinci_nand {
|
||||
target_t *target;
|
||||
struct target *target;
|
||||
|
||||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
||||
uint8_t eccmode;
|
||||
@@ -55,9 +56,9 @@ struct davinci_nand {
|
||||
struct arm_nand_data io;
|
||||
|
||||
/* page i/o for the relevant flavor of hardware ECC */
|
||||
int (*read_page)(struct nand_device_s *nand, uint32_t page,
|
||||
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 (*write_page)(struct nand_device_s *nand, uint32_t page,
|
||||
int (*write_page)(struct nand_device *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
};
|
||||
|
||||
@@ -69,7 +70,7 @@ struct davinci_nand {
|
||||
#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(target_t *target, const char *label)
|
||||
static int halted(struct target *target, const char *label)
|
||||
{
|
||||
if (target->state == TARGET_HALTED)
|
||||
return true;
|
||||
@@ -78,15 +79,10 @@ static int halted(target_t *target, const char *label)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int davinci_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_init(struct nand_device_s *nand)
|
||||
static int davinci_init(struct nand_device *nand)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
uint32_t nandfcr;
|
||||
|
||||
if (!halted(target, "init"))
|
||||
@@ -108,15 +104,15 @@ static int davinci_init(struct nand_device_s *nand)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_reset(struct nand_device_s *nand)
|
||||
static int davinci_reset(struct nand_device *nand)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
|
||||
static int davinci_nand_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
uint32_t nandfsr;
|
||||
|
||||
/* NOTE: return code is zero/error, else success; not ERROR_* */
|
||||
@@ -136,10 +132,10 @@ static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_command(struct nand_device_s *nand, uint8_t command)
|
||||
static int davinci_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!halted(target, "command"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -148,10 +144,10 @@ static int davinci_command(struct nand_device_s *nand, uint8_t command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_address(struct nand_device_s *nand, uint8_t address)
|
||||
static int davinci_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!halted(target, "address"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -160,10 +156,10 @@ static int davinci_address(struct nand_device_s *nand, uint8_t address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
|
||||
static int davinci_write_data(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!halted(target, "write_data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -172,10 +168,10 @@ static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_read_data(struct nand_device_s *nand, void *data)
|
||||
static int davinci_read_data(struct nand_device *nand, void *data)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
|
||||
if (!halted(target, "read_data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -186,11 +182,11 @@ static int davinci_read_data(struct nand_device_s *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_s *nand,
|
||||
static int davinci_read_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
uint32_t nfdata = info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
@@ -219,11 +215,11 @@ static int davinci_read_block_data(struct nand_device_s *nand,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_block_data(struct nand_device_s *nand,
|
||||
static int davinci_write_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
uint32_t nfdata = info->data;
|
||||
uint32_t tmp;
|
||||
int status;
|
||||
@@ -255,7 +251,7 @@ static int davinci_write_block_data(struct nand_device_s *nand,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
|
||||
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)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
@@ -306,7 +302,7 @@ static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int davinci_read_page(struct nand_device_s *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)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
@@ -319,10 +315,10 @@ static int davinci_read_page(struct nand_device_s *nand, uint32_t page,
|
||||
return info->read_page(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
|
||||
static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
int page3 = nand->address_cycles - (nand->page_size == 512);
|
||||
|
||||
/* write command ({page,otp}x{read,program} */
|
||||
@@ -342,11 +338,11 @@ static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint3
|
||||
target_write_u8(target, info->addr, page >> 24);
|
||||
}
|
||||
|
||||
static int davinci_writepage_tail(struct nand_device_s *nand,
|
||||
static int davinci_writepage_tail(struct nand_device *nand,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
uint8_t status;
|
||||
|
||||
if (oob_size)
|
||||
@@ -374,12 +370,12 @@ static int davinci_writepage_tail(struct nand_device_s *nand,
|
||||
/*
|
||||
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
|
||||
*/
|
||||
static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
|
||||
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)
|
||||
{
|
||||
unsigned oob_offset;
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
|
||||
uint32_t fcr, ecc1;
|
||||
@@ -441,7 +437,7 @@ static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
|
||||
* is read first, so its ECC data can be used incrementally), but the
|
||||
* manufacturer bad block markers are safe. Contrast: old "infix" style.
|
||||
*/
|
||||
static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
|
||||
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)
|
||||
{
|
||||
static const uint8_t ecc512[] = {
|
||||
@@ -467,7 +463,7 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
|
||||
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
const uint8_t *l;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||
uint32_t fcr, ecc4;
|
||||
@@ -543,11 +539,11 @@ static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
|
||||
* older second stage loaders (ABL/U-Boot, etc) or other system software
|
||||
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
|
||||
*/
|
||||
static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
|
||||
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)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||
uint32_t fcr, ecc4;
|
||||
@@ -600,7 +596,7 @@ static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t pag
|
||||
return davinci_writepage_tail(nand, NULL, 0);
|
||||
}
|
||||
|
||||
static int davinci_read_page_ecc4infix(struct nand_device_s *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)
|
||||
{
|
||||
davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
|
||||
@@ -629,16 +625,13 @@ static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **argv, int argc,
|
||||
struct nand_device_s *nand)
|
||||
NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||
{
|
||||
struct davinci_nand *info;
|
||||
target_t *target;
|
||||
struct target *target;
|
||||
unsigned long chip, aemif;
|
||||
enum ecc eccmode;
|
||||
int chipsel;
|
||||
char *ep;
|
||||
|
||||
/* arguments:
|
||||
* - "davinci"
|
||||
@@ -648,39 +641,39 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
|
||||
* - aemif address
|
||||
* Plus someday, optionally, ALE and CLE masks.
|
||||
*/
|
||||
if (argc < 5) {
|
||||
if (CMD_ARGC < 5) {
|
||||
LOG_ERROR("parameters: %s target "
|
||||
"chip_addr hwecc_mode aemif_addr",
|
||||
argv[0]);
|
||||
CMD_ARGV[0]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
target = get_target(argv[1]);
|
||||
target = get_target(CMD_ARGV[1]);
|
||||
if (!target) {
|
||||
LOG_ERROR("invalid target %s", argv[1]);
|
||||
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chip = strtoul(argv[2], &ep, 0);
|
||||
if (*ep || chip == 0 || chip == ULONG_MAX) {
|
||||
LOG_ERROR("Invalid NAND chip address %s", argv[2]);
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||
if (chip == 0) {
|
||||
LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (strcmp(argv[3], "hwecc1") == 0)
|
||||
if (strcmp(CMD_ARGV[3], "hwecc1") == 0)
|
||||
eccmode = HWECC1;
|
||||
else if (strcmp(argv[3], "hwecc4") == 0)
|
||||
else if (strcmp(CMD_ARGV[3], "hwecc4") == 0)
|
||||
eccmode = HWECC4;
|
||||
else if (strcmp(argv[3], "hwecc4_infix") == 0)
|
||||
else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0)
|
||||
eccmode = HWECC4_INFIX;
|
||||
else {
|
||||
LOG_ERROR("Invalid ecc mode %s", argv[3]);
|
||||
LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
aemif = strtoul(argv[4], &ep, 0);
|
||||
if (*ep || aemif == 0 || aemif == ULONG_MAX) {
|
||||
LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif);
|
||||
if (aemif == 0) {
|
||||
LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -718,6 +711,7 @@ static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
|
||||
|
||||
info->io.target = target;
|
||||
info->io.data = info->data;
|
||||
info->io.op = ARM_NAND_NONE;
|
||||
|
||||
/* NOTE: for now we don't do any error correction on read.
|
||||
* Nothing else in OpenOCD currently corrects read errors,
|
||||
@@ -747,10 +741,9 @@ fail:
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
nand_flash_controller_t davinci_nand_controller = {
|
||||
struct nand_flash_controller davinci_nand_controller = {
|
||||
.name = "davinci",
|
||||
.nand_device_command = davinci_nand_device_command,
|
||||
.register_commands = davinci_register_commands,
|
||||
.init = davinci_init,
|
||||
.reset = davinci_reset,
|
||||
.command = davinci_command,
|
||||
83
src/flash/nand/driver.c
Normal file
83
src/flash/nand/driver.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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 "core.h"
|
||||
#include "driver.h"
|
||||
|
||||
/* NAND flash controller
|
||||
*/
|
||||
extern struct nand_flash_controller nonce_nand_controller;
|
||||
extern struct nand_flash_controller davinci_nand_controller;
|
||||
extern struct nand_flash_controller lpc3180_nand_controller;
|
||||
extern struct nand_flash_controller orion_nand_controller;
|
||||
extern struct nand_flash_controller s3c2410_nand_controller;
|
||||
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 imx31_nand_flash_controller;
|
||||
extern struct nand_flash_controller at91sam9_nand_controller;
|
||||
|
||||
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
|
||||
|
||||
static struct nand_flash_controller *nand_flash_controllers[] =
|
||||
{
|
||||
&nonce_nand_controller,
|
||||
&davinci_nand_controller,
|
||||
&lpc3180_nand_controller,
|
||||
&orion_nand_controller,
|
||||
&s3c2410_nand_controller,
|
||||
&s3c2412_nand_controller,
|
||||
&s3c2440_nand_controller,
|
||||
&s3c2443_nand_controller,
|
||||
&s3c6400_nand_controller,
|
||||
&imx31_nand_flash_controller,
|
||||
&at91sam9_nand_controller,
|
||||
/* &boundary_scan_nand_controller, */
|
||||
NULL
|
||||
};
|
||||
|
||||
struct nand_flash_controller *nand_driver_find_by_name(const char *name)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
int nand_driver_walk(nand_driver_walker_t f, void *x)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
106
src/flash/nand/driver.h
Normal file
106
src/flash/nand/driver.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#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)
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/** Driver name that is used to select it from configuration files. */
|
||||
char *name;
|
||||
|
||||
const struct command_registration *commands;
|
||||
|
||||
/** NAND device command called when driver is instantiated during configuration. */
|
||||
__NAND_DEVICE_COMMAND((*nand_device_command));
|
||||
|
||||
/** Register controller specific commands as a TCL interface to the driver. */
|
||||
int (*register_commands)(struct command_context *cmd_ctx);
|
||||
|
||||
/** Initialize the NAND device. */
|
||||
int (*init)(struct nand_device *nand);
|
||||
|
||||
/** Reset the NAND device. */
|
||||
int (*reset)(struct nand_device *nand);
|
||||
|
||||
/** Issue a command to the NAND device. */
|
||||
int (*command)(struct nand_device *nand, uint8_t command);
|
||||
|
||||
/** Write an address to the NAND device. */
|
||||
int (*address)(struct nand_device *nand, uint8_t address);
|
||||
|
||||
/** Write word of data to the NAND device. */
|
||||
int (*write_data)(struct nand_device *nand, uint16_t data);
|
||||
|
||||
/** Read word of data from the NAND device. */
|
||||
int (*read_data)(struct nand_device *nand, void *data);
|
||||
|
||||
/** Write a block of data to the NAND device. */
|
||||
int (*write_block_data)(struct nand_device *nand, uint8_t *data, int size);
|
||||
|
||||
/** Read a block of data from the NAND device. */
|
||||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Check if the controller is ready for more instructions with timeout. */
|
||||
int (*controller_ready)(struct nand_device *nand, int timeout);
|
||||
|
||||
/** Check if the NAND device is ready for more instructions with timeout. */
|
||||
int (*nand_ready)(struct nand_device *nand, int timeout);
|
||||
};
|
||||
|
||||
#define NAND_DEVICE_COMMAND_HANDLER(name) static __NAND_DEVICE_COMMAND(name)
|
||||
|
||||
/**
|
||||
* Find a NAND flash controller by name.
|
||||
* @param name Identifies the NAND controller to find.
|
||||
* @returns The nand_flash_controller named @c name, or NULL if not found.
|
||||
*/
|
||||
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*);
|
||||
/**
|
||||
* Walk the list of drivers, encapsulating the data structure type.
|
||||
* Application state/context can be passed through the @c x pointer.
|
||||
* @param f The callback function to invoke for each function.
|
||||
* @param x For use as private data storate, passed directly to @c f.
|
||||
* @returns ERROR_OK if successful, or the non-zero return value of @c f.
|
||||
* This allows a walker to terminate the loop early.
|
||||
*/
|
||||
int nand_driver_walk(nand_driver_walker_t f, void *x);
|
||||
|
||||
#endif // FLASH_NAND_DRIVER_H
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "nand.h"
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* Pre-calculated 256-way 1 byte column parity
|
||||
@@ -68,7 +68,7 @@ static const uint8_t nand_ecc_precalc_table[] = {
|
||||
/*
|
||||
* nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block
|
||||
*/
|
||||
int nand_calculate_ecc(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code)
|
||||
int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code)
|
||||
{
|
||||
uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
|
||||
int i;
|
||||
@@ -20,9 +20,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "nand.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1.
|
||||
@@ -100,7 +98,7 @@ static void gf_build_log_exp_table(void)
|
||||
* expects the ECC to be computed backward, i.e. from the last byte down
|
||||
* to the first one.
|
||||
*/
|
||||
int nand_calculate_ecc_kw(struct nand_device_s *device, const uint8_t *data, uint8_t *ecc)
|
||||
int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t *ecc)
|
||||
{
|
||||
unsigned int r7, r6, r5, r4, r3, r2, r1, r0;
|
||||
int i;
|
||||
244
src/flash/nand/fileio.c
Normal file
244
src/flash/nand/fileio.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Partially based on drivers/mtd/nand_ids.c from Linux. *
|
||||
* *
|
||||
* 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 "core.h"
|
||||
#include "fileio.h"
|
||||
|
||||
static struct nand_ecclayout nand_oob_16 = {
|
||||
.eccbytes = 6,
|
||||
.eccpos = {0, 1, 2, 3, 6, 7},
|
||||
.oobfree = {
|
||||
{.offset = 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},
|
||||
.oobfree = {
|
||||
{.offset = 2,
|
||||
.length = 38}}
|
||||
};
|
||||
|
||||
void nand_fileio_init(struct nand_fileio_state *state)
|
||||
{
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->oob_format = NAND_OOB_NONE;
|
||||
}
|
||||
|
||||
int nand_fileio_start(struct command_context *cmd_ctx,
|
||||
struct nand_device *nand, const char *filename, int filemode,
|
||||
struct nand_fileio_state *state)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
|
||||
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);
|
||||
return retval;
|
||||
}
|
||||
state->file_opened = true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
state->oob_size = 16;
|
||||
state->eccpos = nand_oob_16.eccpos;
|
||||
}
|
||||
else if (nand->page_size == 2048)
|
||||
{
|
||||
state->oob_size = 64;
|
||||
state->eccpos = nand_oob_64.eccpos;
|
||||
}
|
||||
state->oob = malloc(state->oob_size);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
int nand_fileio_cleanup(struct nand_fileio_state *state)
|
||||
{
|
||||
if (state->file_opened)
|
||||
fileio_close(&state->fileio);
|
||||
|
||||
if (state->oob)
|
||||
{
|
||||
free(state->oob);
|
||||
state->oob = NULL;
|
||||
}
|
||||
if (state->page)
|
||||
{
|
||||
free(state->page);
|
||||
state->page = NULL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
int nand_fileio_finish(struct nand_fileio_state *state)
|
||||
{
|
||||
nand_fileio_cleanup(state);
|
||||
return duration_measure(&state->bench);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
nand_fileio_init(state);
|
||||
|
||||
unsigned minargs = need_size ? 4 : 3;
|
||||
if (CMD_ARGC < minargs)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct nand_device *nand;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
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 (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"))
|
||||
state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
|
||||
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc"))
|
||||
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
|
||||
{
|
||||
command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = nand_fileio_start(CMD_CTX, nand, CMD_ARGV[1], filemode, state);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (!need_size)
|
||||
state->size = state->fileio.size;
|
||||
|
||||
*dev = nand;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns If no error occurred, returns number of bytes consumed;
|
||||
* otherwise, returns a negative error code.)
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint8_t ecc[3];
|
||||
memset(s->oob, 0xff, s->oob_size);
|
||||
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)
|
||||
{
|
||||
/*
|
||||
* In this case eccpos is not used as
|
||||
* the ECC data is always stored contigously
|
||||
* at the end of the OOB area. It consists
|
||||
* of 10 bytes per 512-byte data block.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
nand_calculate_ecc_kw(nand, s->page + i, ecc);
|
||||
ecc += 10;
|
||||
}
|
||||
}
|
||||
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);
|
||||
total_read += one_read;
|
||||
}
|
||||
return total_read;
|
||||
}
|
||||
|
||||
57
src/flash/nand/fileio.h
Normal file
57
src/flash/nand/fileio.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_NAND_FILEIO_H
|
||||
#define FLASH_NAND_FILEIO_H
|
||||
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/fileio.h>
|
||||
|
||||
struct nand_fileio_state {
|
||||
uint32_t address;
|
||||
uint32_t size;
|
||||
|
||||
uint8_t *page;
|
||||
uint32_t page_size;
|
||||
|
||||
enum oob_formats oob_format;
|
||||
uint8_t *oob;
|
||||
uint32_t oob_size;
|
||||
|
||||
const int *eccpos;
|
||||
|
||||
bool file_opened;
|
||||
struct fileio fileio;
|
||||
|
||||
struct duration bench;
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s);
|
||||
|
||||
#endif // FLASH_NAND_FILEIO_H
|
||||
39
src/flash/nand/imp.h
Normal file
39
src/flash/nand/imp.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_NAND_IMP_H
|
||||
#define FLASH_NAND_IMP_H
|
||||
|
||||
#include "core.h"
|
||||
#include "driver.h"
|
||||
|
||||
void nand_device_add(struct nand_device *c);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
@@ -21,64 +21,41 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "lpc3180_nand_controller.h"
|
||||
#include "nand.h"
|
||||
#include "imp.h"
|
||||
#include "lpc3180.h"
|
||||
#include <target/target.h>
|
||||
|
||||
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int lpc3180_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc3180_init(struct nand_device_s *device);
|
||||
static int lpc3180_reset(struct nand_device_s *device);
|
||||
static int lpc3180_command(struct nand_device_s *device, uint8_t command);
|
||||
static int lpc3180_address(struct nand_device_s *device, uint8_t address);
|
||||
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data);
|
||||
static int lpc3180_read_data(struct nand_device_s *device, void *data);
|
||||
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
|
||||
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
nand_flash_controller_t lpc3180_nand_controller =
|
||||
{
|
||||
.name = "lpc3180",
|
||||
.nand_device_command = lpc3180_nand_device_command,
|
||||
.register_commands = lpc3180_register_commands,
|
||||
.init = lpc3180_init,
|
||||
.reset = lpc3180_reset,
|
||||
.command = lpc3180_command,
|
||||
.address = lpc3180_address,
|
||||
.write_data = lpc3180_write_data,
|
||||
.read_data = lpc3180_read_data,
|
||||
.write_page = lpc3180_write_page,
|
||||
.read_page = lpc3180_read_page,
|
||||
.controller_ready = lpc3180_controller_ready,
|
||||
.nand_ready = lpc3180_nand_ready,
|
||||
};
|
||||
static int lpc3180_reset(struct nand_device *nand);
|
||||
static int lpc3180_controller_ready(struct nand_device *nand, int timeout);
|
||||
|
||||
/* nand device lpc3180 <target#> <oscillator_frequency>
|
||||
*/
|
||||
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
|
||||
NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info;
|
||||
|
||||
if (argc < 3)
|
||||
if (CMD_ARGC < 3)
|
||||
{
|
||||
LOG_WARNING("incomplete 'lpc3180' nand flash configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));
|
||||
device->controller_priv = lpc3180_info;
|
||||
|
||||
lpc3180_info->target = get_target(args[1]);
|
||||
if (!lpc3180_info->target)
|
||||
struct target *target = get_target(CMD_ARGV[1]);
|
||||
if (NULL == target)
|
||||
{
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
lpc3180_info->osc_freq = strtoul(args[2], NULL, 0);
|
||||
uint32_t osc_freq;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq);
|
||||
|
||||
struct lpc3180_nand_controller *lpc3180_info;
|
||||
lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller));
|
||||
nand->controller_priv = lpc3180_info;
|
||||
|
||||
lpc3180_info->target = target;
|
||||
lpc3180_info->osc_freq = osc_freq;
|
||||
|
||||
if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
|
||||
{
|
||||
LOG_WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq);
|
||||
@@ -91,15 +68,6 @@ static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");
|
||||
|
||||
register_command(cmd_ctx, lpc3180_cmd, "select", handle_lpc3180_select_command, COMMAND_EXEC, "select <'mlc'|'slc'> controller (default is mlc)");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_pll(int fclkin, uint32_t pll_ctrl)
|
||||
{
|
||||
int bypass = (pll_ctrl & 0x8000) >> 15;
|
||||
@@ -128,9 +96,9 @@ static int lpc3180_pll(int fclkin, uint32_t pll_ctrl)
|
||||
return (m / (2 * p)) * (fclkin / n);
|
||||
}
|
||||
|
||||
static float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
|
||||
static float lpc3180_cycle_time(struct lpc3180_nand_controller *lpc3180_info)
|
||||
{
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct target *target = lpc3180_info->target;
|
||||
uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
|
||||
int sysclk;
|
||||
int hclk;
|
||||
@@ -178,13 +146,13 @@ static float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
|
||||
return cycle;
|
||||
}
|
||||
|
||||
static int lpc3180_init(struct nand_device_s *device)
|
||||
static int lpc3180_init(struct nand_device *nand)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
int bus_width = (device->bus_width) ? (device->bus_width) : 8;
|
||||
int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;
|
||||
int page_size = (device->page_size) ? (device->page_size) : 512;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
int bus_width = nand->bus_width ? : 8;
|
||||
int address_cycles = nand->address_cycles ? : 3;
|
||||
int page_size = nand->page_size ? : 512;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -208,7 +176,7 @@ static int lpc3180_init(struct nand_device_s *device)
|
||||
}
|
||||
|
||||
/* inform calling code about selected bus width */
|
||||
device->bus_width = bus_width;
|
||||
nand->bus_width = bus_width;
|
||||
|
||||
if ((address_cycles != 3) && (address_cycles != 4))
|
||||
{
|
||||
@@ -274,7 +242,7 @@ static int lpc3180_init(struct nand_device_s *device)
|
||||
((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) |
|
||||
((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24));
|
||||
|
||||
lpc3180_reset(device);
|
||||
lpc3180_reset(nand);
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
@@ -302,16 +270,16 @@ static int lpc3180_init(struct nand_device_s *device)
|
||||
((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) |
|
||||
((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28));
|
||||
|
||||
lpc3180_reset(device);
|
||||
lpc3180_reset(nand);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_reset(struct nand_device_s *device)
|
||||
static int lpc3180_reset(struct nand_device *nand)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -329,7 +297,7 @@ static int lpc3180_reset(struct nand_device_s *device)
|
||||
/* MLC_CMD = 0xff (reset controller and NAND device) */
|
||||
target_write_u32(target, 0x200b8000, 0xff);
|
||||
|
||||
if (!lpc3180_controller_ready(device, 100))
|
||||
if (!lpc3180_controller_ready(nand, 100))
|
||||
{
|
||||
LOG_ERROR("LPC3180 NAND controller timed out after reset");
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
@@ -340,7 +308,7 @@ static int lpc3180_reset(struct nand_device_s *device)
|
||||
/* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */
|
||||
target_write_u32(target, 0x20020010, 0x6);
|
||||
|
||||
if (!lpc3180_controller_ready(device, 100))
|
||||
if (!lpc3180_controller_ready(nand, 100))
|
||||
{
|
||||
LOG_ERROR("LPC3180 NAND controller timed out after reset");
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
@@ -350,10 +318,10 @@ static int lpc3180_reset(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_command(struct nand_device_s *device, uint8_t command)
|
||||
static int lpc3180_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -380,10 +348,10 @@ static int lpc3180_command(struct nand_device_s *device, uint8_t command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_address(struct nand_device_s *device, uint8_t address)
|
||||
static int lpc3180_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -410,10 +378,10 @@ static int lpc3180_address(struct nand_device_s *device, uint8_t address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data)
|
||||
static int lpc3180_write_data(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -440,10 +408,10 @@ static int lpc3180_write_data(struct nand_device_s *device, uint16_t data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
static int lpc3180_read_data(struct nand_device *nand, void *data)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -459,12 +427,12 @@ static int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
/* data = MLC_DATA, use sized access */
|
||||
if (device->bus_width == 8)
|
||||
if (nand->bus_width == 8)
|
||||
{
|
||||
uint8_t *data8 = data;
|
||||
target_read_u8(target, 0x200b0000, data8);
|
||||
}
|
||||
else if (device->bus_width == 16)
|
||||
else if (nand->bus_width == 16)
|
||||
{
|
||||
uint16_t *data16 = data;
|
||||
target_read_u16(target, 0x200b0000, data16);
|
||||
@@ -482,12 +450,12 @@ static int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
/* data = SLC_DATA, must use 32-bit access */
|
||||
target_read_u32(target, 0x20020000, &data32);
|
||||
|
||||
if (device->bus_width == 8)
|
||||
if (nand->bus_width == 8)
|
||||
{
|
||||
uint8_t *data8 = data;
|
||||
*data8 = data32 & 0xff;
|
||||
}
|
||||
else if (device->bus_width == 16)
|
||||
else if (nand->bus_width == 16)
|
||||
{
|
||||
uint16_t *data16 = data;
|
||||
*data16 = data32 & 0xffff;
|
||||
@@ -502,10 +470,10 @@ static int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
int retval;
|
||||
uint8_t status;
|
||||
|
||||
@@ -532,13 +500,14 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (oob && (oob_size > 6))
|
||||
if (oob && (oob_size > 24))
|
||||
{
|
||||
LOG_ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");
|
||||
LOG_ERROR("LPC3180 MLC controller can't write more "
|
||||
"than 6 bytes for each quarter's OOB data");
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (data_size > (uint32_t)device->page_size)
|
||||
if (data_size > (uint32_t)nand->page_size)
|
||||
{
|
||||
LOG_ERROR("data size exceeds page size");
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
@@ -550,7 +519,7 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
page_buffer = malloc(512);
|
||||
oob_buffer = malloc(6);
|
||||
|
||||
if (device->page_size == 512)
|
||||
if (nand->page_size == 512)
|
||||
{
|
||||
/* MLC_ADDR = 0x0 (one column cycle) */
|
||||
target_write_u32(target, 0x200b8004, 0x0);
|
||||
@@ -559,7 +528,7 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
target_write_u32(target, 0x200b8004, page & 0xff);
|
||||
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
|
||||
|
||||
if (device->address_cycles == 4)
|
||||
if (nand->address_cycles == 4)
|
||||
target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
|
||||
}
|
||||
else
|
||||
@@ -576,7 +545,7 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
/* when using the MLC controller, we have to treat a large page device
|
||||
* as being made out of four quarters, each the size of a small page device
|
||||
*/
|
||||
num_quarters = (device->page_size == 2048) ? 4 : 1;
|
||||
num_quarters = (nand->page_size == 2048) ? 4 : 1;
|
||||
|
||||
for (quarter = 0; quarter < num_quarters; quarter++)
|
||||
{
|
||||
@@ -591,10 +560,10 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
data += thisrun_data_size;
|
||||
}
|
||||
|
||||
memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);
|
||||
memset(oob_buffer, 0xff, 6);
|
||||
if (oob)
|
||||
{
|
||||
memcpy(page_buffer, oob, thisrun_oob_size);
|
||||
memcpy(oob_buffer, oob, thisrun_oob_size);
|
||||
oob_size -= thisrun_oob_size;
|
||||
oob += thisrun_oob_size;
|
||||
}
|
||||
@@ -602,13 +571,15 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
/* write MLC_ECC_ENC_REG to start encode cycle */
|
||||
target_write_u32(target, 0x200b8008, 0x0);
|
||||
|
||||
target_write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
|
||||
target_write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
|
||||
target_write_memory(target, 0x200a8000,
|
||||
4, 128, page_buffer);
|
||||
target_write_memory(target, 0x200a8000,
|
||||
1, 6, oob_buffer);
|
||||
|
||||
/* write MLC_ECC_AUTO_ENC_REG to start auto encode */
|
||||
target_write_u32(target, 0x200b8010, 0x0);
|
||||
|
||||
if (!lpc3180_controller_ready(device, 1000))
|
||||
if (!lpc3180_controller_ready(nand, 1000))
|
||||
{
|
||||
LOG_ERROR("timeout while waiting for completion of auto encode cycle");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -618,7 +589,7 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
/* MLC_CMD = auto program command */
|
||||
target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);
|
||||
|
||||
if ((retval = nand_read_status(device, &status)) != ERROR_OK)
|
||||
if ((retval = nand_read_status(nand, &status)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("couldn't read status");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -635,16 +606,16 @@ static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
|
||||
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -673,13 +644,13 @@ static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data_size > (uint32_t)device->page_size)
|
||||
if (data_size > (uint32_t)nand->page_size)
|
||||
{
|
||||
LOG_ERROR("data size exceeds page size");
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (device->page_size == 2048)
|
||||
if (nand->page_size == 2048)
|
||||
{
|
||||
page_buffer = malloc(2048);
|
||||
oob_buffer = malloc(64);
|
||||
@@ -705,7 +676,7 @@ static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_
|
||||
target_write_u32(target, 0x200b8000, NAND_CMD_READ0);
|
||||
}
|
||||
|
||||
if (device->page_size == 512)
|
||||
if (nand->page_size == 512)
|
||||
{
|
||||
/* small page device */
|
||||
/* MLC_ADDR = 0x0 (one column cycle) */
|
||||
@@ -715,7 +686,7 @@ static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_
|
||||
target_write_u32(target, 0x200b8004, page & 0xff);
|
||||
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
|
||||
|
||||
if (device->address_cycles == 4)
|
||||
if (nand->address_cycles == 4)
|
||||
target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
|
||||
}
|
||||
else
|
||||
@@ -733,12 +704,12 @@ static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_
|
||||
target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);
|
||||
}
|
||||
|
||||
while (page_bytes_done < (uint32_t)device->page_size)
|
||||
while (page_bytes_done < (uint32_t)nand->page_size)
|
||||
{
|
||||
/* MLC_ECC_AUTO_DEC_REG = dummy */
|
||||
target_write_u32(target, 0x200b8014, 0xaa55aa55);
|
||||
|
||||
if (!lpc3180_controller_ready(device, 1000))
|
||||
if (!lpc3180_controller_ready(nand, 1000))
|
||||
{
|
||||
LOG_ERROR("timeout while waiting for completion of auto decode cycle");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
@@ -782,17 +753,16 @@ static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
|
||||
return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
static int lpc3180_controller_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
uint8_t status = 0x0;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -800,20 +770,35 @@ static int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("lpc3180_controller_ready count start=%d", timeout);
|
||||
|
||||
do
|
||||
{
|
||||
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* Read MLC_ISR, wait for controller to become ready */
|
||||
target_read_u8(target, 0x200b8048, &status);
|
||||
|
||||
if (status & 2)
|
||||
if (status & 2) {
|
||||
LOG_DEBUG("lpc3180_controller_ready count=%d",
|
||||
timeout);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
/* we pretend that the SLC controller is always ready */
|
||||
return 1;
|
||||
uint32_t status;
|
||||
|
||||
/* Read SLC_STAT and check READY bit */
|
||||
target_read_u32(target, 0x20020018, &status);
|
||||
|
||||
if (status & 1) {
|
||||
LOG_DEBUG("lpc3180_controller_ready count=%d",
|
||||
timeout);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
@@ -822,10 +807,10 @@ static int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
static int lpc3180_nand_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||
struct target *target = lpc3180_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -833,6 +818,8 @@ static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("lpc3180_nand_ready count start=%d", timeout);
|
||||
|
||||
do
|
||||
{
|
||||
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
@@ -842,8 +829,11 @@ static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
/* Read MLC_ISR, wait for NAND flash device to become ready */
|
||||
target_read_u8(target, 0x200b8048, &status);
|
||||
|
||||
if (status & 1)
|
||||
if (status & 1) {
|
||||
LOG_DEBUG("lpc3180_nand_ready count end=%d",
|
||||
timeout);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
@@ -852,8 +842,11 @@ static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
/* Read SLC_STAT and check READY bit */
|
||||
target_read_u32(target, 0x20020018, &status);
|
||||
|
||||
if (status & 1)
|
||||
if (status & 1) {
|
||||
LOG_DEBUG("lpc3180_nand_ready count end=%d",
|
||||
timeout);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
@@ -862,36 +855,37 @@ static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(handle_lpc3180_select_command)
|
||||
{
|
||||
nand_device_t *device = NULL;
|
||||
lpc3180_nand_controller_t *lpc3180_info = NULL;
|
||||
struct lpc3180_nand_controller *lpc3180_info = NULL;
|
||||
char *selected[] =
|
||||
{
|
||||
"no", "mlc", "slc"
|
||||
};
|
||||
|
||||
if ((argc < 1) || (argc > 2))
|
||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
device = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!device)
|
||||
unsigned num;
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
|
||||
struct nand_device *nand = get_nand_device_by_num(num);
|
||||
if (!nand)
|
||||
{
|
||||
command_print(cmd_ctx, "nand device '#%s' is out of bounds", args[0]);
|
||||
command_print(CMD_CTX, "nand device '#%s' is out of bounds", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
lpc3180_info = device->controller_priv;
|
||||
lpc3180_info = nand->controller_priv;
|
||||
|
||||
if (argc == 2)
|
||||
if (CMD_ARGC == 2)
|
||||
{
|
||||
if (strcmp(args[1], "mlc") == 0)
|
||||
if (strcmp(CMD_ARGV[1], "mlc") == 0)
|
||||
{
|
||||
lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
|
||||
}
|
||||
else if (strcmp(args[1], "slc") == 0)
|
||||
else if (strcmp(CMD_ARGV[1], "slc") == 0)
|
||||
{
|
||||
lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
|
||||
}
|
||||
@@ -901,7 +895,43 @@ static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char
|
||||
}
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "%s controller selected", selected[lpc3180_info->selected_controller]);
|
||||
command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration lpc3180_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "select",
|
||||
.handler = handle_lpc3180_select_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "select MLC or SLC controller (default is MLC)",
|
||||
.usage = "bank_id ['mlc'|'slc']",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration lpc3180_command_handler[] = {
|
||||
{
|
||||
.name = "lpc3180",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "LPC3180 NAND flash controller commands",
|
||||
.chain = lpc3180_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct nand_flash_controller lpc3180_nand_controller = {
|
||||
.name = "lpc3180",
|
||||
.commands = lpc3180_command_handler,
|
||||
.nand_device_command = lpc3180_nand_device_command,
|
||||
.init = lpc3180_init,
|
||||
.reset = lpc3180_reset,
|
||||
.command = lpc3180_command,
|
||||
.address = lpc3180_address,
|
||||
.write_data = lpc3180_write_data,
|
||||
.read_data = lpc3180_read_data,
|
||||
.write_page = lpc3180_write_page,
|
||||
.read_page = lpc3180_read_page,
|
||||
.controller_ready = lpc3180_controller_ready,
|
||||
.nand_ready = lpc3180_nand_ready,
|
||||
};
|
||||
@@ -20,8 +20,6 @@
|
||||
#ifndef LPC3180_NAND_CONTROLLER_H
|
||||
#define LPC3180_NAND_CONTROLLER_H
|
||||
|
||||
#include "target.h"
|
||||
|
||||
enum lpc3180_selected_controller
|
||||
{
|
||||
LPC3180_NO_CONTROLLER,
|
||||
@@ -29,14 +27,14 @@ enum lpc3180_selected_controller
|
||||
LPC3180_SLC_CONTROLLER,
|
||||
};
|
||||
|
||||
typedef struct lpc3180_nand_controller_s
|
||||
struct lpc3180_nand_controller
|
||||
{
|
||||
struct target_s *target;
|
||||
struct target *target;
|
||||
int osc_freq;
|
||||
enum lpc3180_selected_controller selected_controller;
|
||||
int sw_write_protection;
|
||||
uint32_t sw_wp_lower_bound;
|
||||
uint32_t sw_wp_upper_bound;
|
||||
} lpc3180_nand_controller_t;
|
||||
};
|
||||
|
||||
#endif /*LPC3180_NAND_CONTROLLER_H */
|
||||
@@ -35,7 +35,9 @@ get_next_halfword_from_sram_buffer() not tested
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mx3_nand.h"
|
||||
#include "imp.h"
|
||||
#include "mx3.h"
|
||||
#include <target/target.h>
|
||||
|
||||
static const char target_not_halted_err_msg[] =
|
||||
"target must be halted to use mx3 NAND flash controller";
|
||||
@@ -47,72 +49,39 @@ static const char get_status_register_err_msg[] = "can't get NAND status";
|
||||
static uint32_t in_sram_address;
|
||||
unsigned char sign_of_sequental_byte_read;
|
||||
|
||||
static int test_iomux_settings (target_t * target, uint32_t value,
|
||||
static int test_iomux_settings (struct target * target, uint32_t value,
|
||||
uint32_t mask, const char *text);
|
||||
static int initialize_nf_controller (struct nand_device_s *device);
|
||||
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value);
|
||||
static int get_next_halfword_from_sram_buffer (target_t * target,
|
||||
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 (target_t * target, const char *text);
|
||||
static int validate_target_state (struct nand_device_s *device);
|
||||
static int do_data_output (struct nand_device_s *device);
|
||||
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 imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct nand_device_s *device);
|
||||
static int imx31_init (struct nand_device_s *device);
|
||||
static int imx31_read_data (struct nand_device_s *device, void *data);
|
||||
static int imx31_write_data (struct nand_device_s *device, uint16_t data);
|
||||
static int imx31_nand_ready (struct nand_device_s *device, int timeout);
|
||||
static int imx31_register_commands (struct command_context_s *cmd_ctx);
|
||||
static int imx31_reset (struct nand_device_s *device);
|
||||
static int imx31_command (struct nand_device_s *device, uint8_t command);
|
||||
static int imx31_address (struct nand_device_s *device, uint8_t address);
|
||||
static int imx31_controller_ready (struct nand_device_s *device, int tout);
|
||||
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size);
|
||||
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size);
|
||||
static int imx31_command (struct nand_device *nand, uint8_t command);
|
||||
static int imx31_address (struct nand_device *nand, uint8_t address);
|
||||
static int imx31_controller_ready (struct nand_device *nand, int tout);
|
||||
|
||||
nand_flash_controller_t imx31_nand_flash_controller = {
|
||||
.name = "imx31",
|
||||
.nand_device_command = imx31_nand_device_command,
|
||||
.register_commands = imx31_register_commands,
|
||||
.init = imx31_init,
|
||||
.reset = imx31_reset,
|
||||
.command = imx31_command,
|
||||
.address = imx31_address,
|
||||
.write_data = imx31_write_data,
|
||||
.read_data = imx31_read_data,
|
||||
.write_page = imx31_write_page,
|
||||
.read_page = imx31_read_page,
|
||||
.controller_ready = imx31_controller_ready,
|
||||
.nand_ready = imx31_nand_ready,
|
||||
};
|
||||
|
||||
static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info;
|
||||
mx3_nf_info = malloc (sizeof (mx3_nf_controller_t));
|
||||
struct mx3_nf_controller *mx3_nf_info;
|
||||
mx3_nf_info = malloc (sizeof (struct mx3_nf_controller));
|
||||
if (mx3_nf_info == NULL)
|
||||
{
|
||||
LOG_ERROR ("no memory for nand controller");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
device->controller_priv = mx3_nf_info;
|
||||
nand->controller_priv = mx3_nf_info;
|
||||
|
||||
mx3_nf_info->target = get_target (args[1]);
|
||||
mx3_nf_info->target = get_target (CMD_ARGV[1]);
|
||||
if (mx3_nf_info->target == NULL)
|
||||
{
|
||||
LOG_ERROR ("target '%s' not defined", args[1]);
|
||||
LOG_ERROR ("target '%s' not defined", CMD_ARGV[1]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (argc < 3)
|
||||
if (CMD_ARGC < 3)
|
||||
{
|
||||
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
|
||||
return ERROR_FAIL;
|
||||
@@ -122,7 +91,7 @@ static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
*/
|
||||
{
|
||||
int hwecc_needed;
|
||||
hwecc_needed = strcmp (args[2], "hwecc");
|
||||
hwecc_needed = strcmp (CMD_ARGV[2], "hwecc");
|
||||
if (hwecc_needed == 0)
|
||||
{
|
||||
mx3_nf_info->flags.hw_ecc_enabled = 1;
|
||||
@@ -154,17 +123,17 @@ static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_init (struct nand_device_s *device)
|
||||
static int imx31_init (struct nand_device *nand)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state(nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
@@ -180,30 +149,30 @@ static int imx31_init (struct nand_device_s *device)
|
||||
{
|
||||
uint32_t pcsr_register_content;
|
||||
target_read_u32 (target, MX3_PCSR, &pcsr_register_content);
|
||||
if (!device->bus_width)
|
||||
if (!nand->bus_width)
|
||||
{
|
||||
device->bus_width =
|
||||
nand->bus_width =
|
||||
(pcsr_register_content & 0x80000000) ? 16 : 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcsr_register_content |=
|
||||
((device->bus_width == 16) ? 0x80000000 : 0x00000000);
|
||||
((nand->bus_width == 16) ? 0x80000000 : 0x00000000);
|
||||
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
|
||||
}
|
||||
|
||||
if (!device->page_size)
|
||||
if (!nand->page_size)
|
||||
{
|
||||
device->page_size =
|
||||
nand->page_size =
|
||||
(pcsr_register_content & 0x40000000) ? 2048 : 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcsr_register_content |=
|
||||
((device->page_size == 2048) ? 0x40000000 : 0x00000000);
|
||||
((nand->page_size == 2048) ? 0x40000000 : 0x00000000);
|
||||
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
|
||||
}
|
||||
if (mx3_nf_info->flags.one_kb_sram && (device->page_size == 2048))
|
||||
if (mx3_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");
|
||||
@@ -243,7 +212,7 @@ static int imx31_init (struct nand_device_s *device)
|
||||
test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7");
|
||||
if (device->bus_width == 16)
|
||||
if (nand->bus_width == 16)
|
||||
{
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00,
|
||||
@@ -266,15 +235,15 @@ static int imx31_init (struct nand_device_s *device)
|
||||
}
|
||||
}
|
||||
|
||||
initialize_nf_controller (device);
|
||||
initialize_nf_controller (nand);
|
||||
|
||||
{
|
||||
int retval;
|
||||
uint16_t nand_status_content;
|
||||
retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_STATUS);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= do_data_output (device);
|
||||
retval |= imx31_command (nand, NAND_CMD_STATUS);
|
||||
retval |= imx31_address (nand, 0x00);
|
||||
retval |= do_data_output (nand);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR (get_status_register_err_msg);
|
||||
@@ -297,16 +266,16 @@ static int imx31_init (struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_read_data (struct nand_device_s *device, void *data)
|
||||
static int imx31_read_data (struct nand_device *nand, void *data)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state (nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
@@ -318,14 +287,14 @@ static int imx31_read_data (struct nand_device_s *device, void *data)
|
||||
* get data from nand chip
|
||||
*/
|
||||
int try_data_output_from_nand_chip;
|
||||
try_data_output_from_nand_chip = do_data_output (device);
|
||||
try_data_output_from_nand_chip = do_data_output (nand);
|
||||
if (try_data_output_from_nand_chip != ERROR_OK)
|
||||
{
|
||||
return try_data_output_from_nand_chip;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->bus_width == 16)
|
||||
if (nand->bus_width == 16)
|
||||
{
|
||||
get_next_halfword_from_sram_buffer (target, data);
|
||||
}
|
||||
@@ -337,47 +306,42 @@ static int imx31_read_data (struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_write_data (struct nand_device_s *device, uint16_t data)
|
||||
static int imx31_write_data (struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
LOG_ERROR ("write_data() not implemented");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
static int imx31_nand_ready (struct nand_device_s *device, int timeout)
|
||||
static int imx31_nand_ready (struct nand_device *nand, int timeout)
|
||||
{
|
||||
return imx31_controller_ready (device, timeout);
|
||||
return imx31_controller_ready (nand, timeout);
|
||||
}
|
||||
|
||||
static int imx31_register_commands (struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_reset (struct nand_device_s *device)
|
||||
static int imx31_reset (struct nand_device *nand)
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state (nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
initialize_nf_controller (device);
|
||||
initialize_nf_controller (nand);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_command (struct nand_device_s *device, uint8_t command)
|
||||
static int imx31_command (struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state (nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
@@ -400,7 +364,7 @@ static int imx31_command (struct nand_device_s *device, uint8_t command)
|
||||
* offset == one half of page size
|
||||
*/
|
||||
in_sram_address =
|
||||
MX3_NF_MAIN_BUFFER0 + (device->page_size >> 1);
|
||||
MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
||||
default:
|
||||
in_sram_address = MX3_NF_MAIN_BUFFER0;
|
||||
}
|
||||
@@ -442,16 +406,16 @@ static int imx31_command (struct nand_device_s *device, uint8_t command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_address (struct nand_device_s *device, uint8_t address)
|
||||
static int imx31_address (struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state (nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
@@ -474,18 +438,18 @@ static int imx31_address (struct nand_device_s *device, uint8_t address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_controller_ready (struct nand_device_s *device, int tout)
|
||||
static int imx31_controller_ready (struct nand_device *nand, int tout)
|
||||
{
|
||||
uint16_t poll_complete_status;
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
validate_target_result = validate_target_state (nand);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
@@ -505,12 +469,12 @@ static int imx31_controller_ready (struct nand_device_s *device, int tout)
|
||||
return tout;
|
||||
}
|
||||
|
||||
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
|
||||
if (data_size % 2)
|
||||
{
|
||||
@@ -532,7 +496,7 @@ static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
* validate target state
|
||||
*/
|
||||
int retval;
|
||||
retval = validate_target_state (device);
|
||||
retval = validate_target_state (nand);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -540,16 +504,16 @@ static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
}
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_SEQIN);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= imx31_address (device, page & 0xff);
|
||||
retval |= imx31_address (device, (page >> 8) & 0xff);
|
||||
if (device->address_cycles >= 4)
|
||||
retval |= imx31_command(nand, NAND_CMD_SEQIN);
|
||||
retval |= imx31_address(nand, 0x00);
|
||||
retval |= imx31_address(nand, page & 0xff);
|
||||
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
||||
if (nand->address_cycles >= 4)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 16) & 0xff);
|
||||
if (device->address_cycles >= 5)
|
||||
retval |= imx31_address (nand, (page >> 16) & 0xff);
|
||||
if (nand->address_cycles >= 5)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 24) & 0xff);
|
||||
retval |= imx31_address (nand, (page >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
target_write_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, data);
|
||||
@@ -579,7 +543,7 @@ static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
return poll_result;
|
||||
}
|
||||
}
|
||||
retval |= imx31_command (device, NAND_CMD_PAGEPROG);
|
||||
retval |= imx31_command (nand, NAND_CMD_PAGEPROG);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -591,9 +555,9 @@ static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
{
|
||||
uint16_t nand_status_content;
|
||||
retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_STATUS);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= do_data_output (device);
|
||||
retval |= imx31_command(nand, NAND_CMD_STATUS);
|
||||
retval |= imx31_address(nand, 0x00);
|
||||
retval |= do_data_output(nand);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR (get_status_register_err_msg);
|
||||
@@ -612,12 +576,12 @@ static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
static int imx31_read_page (struct nand_device *nand, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
|
||||
if (data_size % 2)
|
||||
{
|
||||
@@ -635,7 +599,7 @@ static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
* validate target state
|
||||
*/
|
||||
int retval;
|
||||
retval = validate_target_state (device);
|
||||
retval = validate_target_state(nand);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -643,20 +607,20 @@ static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
}
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_READ0);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= imx31_address (device, page & 0xff);
|
||||
retval |= imx31_address (device, (page >> 8) & 0xff);
|
||||
if (device->address_cycles >= 4)
|
||||
retval |= imx31_command(nand, NAND_CMD_READ0);
|
||||
retval |= imx31_address(nand, 0x00);
|
||||
retval |= imx31_address(nand, page & 0xff);
|
||||
retval |= imx31_address(nand, (page >> 8) & 0xff);
|
||||
if (nand->address_cycles >= 4)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 16) & 0xff);
|
||||
if (device->address_cycles >= 5)
|
||||
retval |= imx31_address(nand, (page >> 16) & 0xff);
|
||||
if (nand->address_cycles >= 5)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 24) & 0xff);
|
||||
retval |= imx31_command (device, NAND_CMD_READSTART);
|
||||
retval |= imx31_address(nand, (page >> 24) & 0xff);
|
||||
retval |= imx31_command(nand, NAND_CMD_READSTART);
|
||||
}
|
||||
}
|
||||
retval |= do_data_output (device);
|
||||
retval |= do_data_output (nand);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -676,7 +640,7 @@ static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int test_iomux_settings (target_t * target, uint32_t address,
|
||||
static int test_iomux_settings (struct target * target, uint32_t address,
|
||||
uint32_t mask, const char *text)
|
||||
{
|
||||
uint32_t register_content;
|
||||
@@ -689,10 +653,10 @@ static int test_iomux_settings (target_t * target, uint32_t address,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int initialize_nf_controller (struct nand_device_s *device)
|
||||
static int initialize_nf_controller (struct nand_device *nand)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
/*
|
||||
* resets NAND flash controller in zero time ? I dont know.
|
||||
*/
|
||||
@@ -742,7 +706,7 @@ static int initialize_nf_controller (struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value)
|
||||
static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value)
|
||||
{
|
||||
static uint8_t even_byte = 0;
|
||||
/*
|
||||
@@ -780,7 +744,7 @@ static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int get_next_halfword_from_sram_buffer (target_t * target,
|
||||
static int get_next_halfword_from_sram_buffer (struct target * target,
|
||||
uint16_t * value)
|
||||
{
|
||||
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR)
|
||||
@@ -797,7 +761,7 @@ static int get_next_halfword_from_sram_buffer (target_t * target,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int poll_for_complete_op (target_t * target, const char *text)
|
||||
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++)
|
||||
@@ -817,10 +781,10 @@ static int poll_for_complete_op (target_t * target, const char *text)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int validate_target_state (struct nand_device_s *device)
|
||||
static int validate_target_state (struct nand_device *nand)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -839,10 +803,10 @@ static int validate_target_state (struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int do_data_output (struct nand_device_s *device)
|
||||
static int do_data_output (struct nand_device *nand)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||
struct target *target = mx3_nf_info->target;
|
||||
switch (mx3_nf_info->fin)
|
||||
{
|
||||
case MX3_NF_FIN_DATAOUT:
|
||||
@@ -900,3 +864,18 @@ static int do_data_output (struct nand_device_s *device)
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct nand_flash_controller imx31_nand_flash_controller = {
|
||||
.name = "imx31",
|
||||
.nand_device_command = &imx31_nand_device_command,
|
||||
.init = &imx31_init,
|
||||
.reset = &imx31_reset,
|
||||
.command = &imx31_command,
|
||||
.address = &imx31_address,
|
||||
.write_data = &imx31_write_data,
|
||||
.read_data = &imx31_read_data,
|
||||
.write_page = &imx31_write_page,
|
||||
.read_page = &imx31_read_page,
|
||||
.controller_ready = &imx31_controller_ready,
|
||||
.nand_ready = &imx31_nand_ready,
|
||||
};
|
||||
@@ -25,7 +25,6 @@
|
||||
*
|
||||
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||
*/
|
||||
#include <nand.h>
|
||||
|
||||
#define MX3_NF_BASE_ADDR 0xb8000000
|
||||
#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00)
|
||||
@@ -108,10 +107,10 @@ struct mx3_nf_flags
|
||||
unsigned hw_ecc_enabled:1;
|
||||
};
|
||||
|
||||
typedef struct mx3_nf_controller_s
|
||||
struct mx3_nf_controller
|
||||
{
|
||||
struct target_s *target;
|
||||
struct target *target;
|
||||
enum mx_dataout_type optype;
|
||||
enum mx_nf_finalize_action fin;
|
||||
struct mx3_nf_flags flags;
|
||||
} mx3_nf_controller_t;
|
||||
};
|
||||
83
src/flash/nand/nonce.c
Normal file
83
src/flash/nand/nonce.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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 "hello.h"
|
||||
|
||||
|
||||
static int nonce_nand_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int nonce_nand_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int nonce_nand_read(struct nand_device *nand, void *data)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int nonce_nand_write(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int nonce_nand_fast_block_write(struct nand_device *nand,
|
||||
uint8_t *data, int size)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nonce_nand_reset(struct nand_device *nand)
|
||||
{
|
||||
return nonce_nand_command(nand, NAND_CMD_RESET);
|
||||
}
|
||||
|
||||
static int nonce_nand_controller_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &nonce_nand_controller_ready,
|
||||
};
|
||||
@@ -26,20 +26,21 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arm_nandio.h"
|
||||
#include "armv4_5.h"
|
||||
#include "imp.h"
|
||||
#include "arm_io.h"
|
||||
#include <target/arm.h>
|
||||
|
||||
|
||||
typedef struct orion_nand_controller_s
|
||||
struct orion_nand_controller
|
||||
{
|
||||
struct target_s *target;
|
||||
struct target *target;
|
||||
|
||||
struct arm_nand_data io;
|
||||
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t data;
|
||||
} orion_nand_controller_t;
|
||||
};
|
||||
|
||||
#define CHECK_HALTED \
|
||||
do { \
|
||||
@@ -49,91 +50,84 @@ typedef struct orion_nand_controller_s
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int orion_nand_command(struct nand_device_s *device, uint8_t command)
|
||||
static int orion_nand_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
struct orion_nand_controller *hw = nand->controller_priv;
|
||||
struct target *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->cmd, command);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_address(struct nand_device_s *device, uint8_t address)
|
||||
static int orion_nand_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
struct orion_nand_controller *hw = nand->controller_priv;
|
||||
struct target *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->addr, address);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_read(struct nand_device_s *device, void *data)
|
||||
static int orion_nand_read(struct nand_device *nand, void *data)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
struct orion_nand_controller *hw = nand->controller_priv;
|
||||
struct target *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_read_u8(target, hw->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_write(struct nand_device_s *device, uint16_t data)
|
||||
static int orion_nand_write(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
struct orion_nand_controller *hw = nand->controller_priv;
|
||||
struct target *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_slow_block_write(struct nand_device_s *device, uint8_t *data, int size)
|
||||
static int orion_nand_slow_block_write(struct nand_device *nand, uint8_t *data, int size)
|
||||
{
|
||||
while (size--)
|
||||
orion_nand_write(device, *data++);
|
||||
orion_nand_write(nand, *data++);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_fast_block_write(struct nand_device_s *device, uint8_t *data, int size)
|
||||
static int orion_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
struct orion_nand_controller *hw = nand->controller_priv;
|
||||
int retval;
|
||||
|
||||
hw->io.chunk_size = device->page_size;
|
||||
hw->io.chunk_size = nand->page_size;
|
||||
|
||||
retval = arm_nandwrite(&hw->io, data, size);
|
||||
if (retval == ERROR_NAND_NO_BUFFER)
|
||||
retval = orion_nand_slow_block_write(device, data, size);
|
||||
retval = orion_nand_slow_block_write(nand, data, size);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int orion_nand_reset(struct nand_device_s *device)
|
||||
static int orion_nand_reset(struct nand_device *nand)
|
||||
{
|
||||
return orion_nand_command(device, NAND_CMD_RESET);
|
||||
return orion_nand_command(nand, NAND_CMD_RESET);
|
||||
}
|
||||
|
||||
static int orion_nand_controller_ready(struct nand_device_s *device, int timeout)
|
||||
static int orion_nand_controller_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int orion_nand_register_commands(struct command_context_s *cmd_ctx)
|
||||
NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int orion_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
orion_nand_controller_t *hw;
|
||||
struct orion_nand_controller *hw;
|
||||
uint32_t base;
|
||||
uint8_t ale, cle;
|
||||
|
||||
if (argc != 3) {
|
||||
if (CMD_ARGC != 3) {
|
||||
LOG_ERROR("arguments must be: <target_id> <NAND_address>\n");
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
@@ -144,15 +138,15 @@ int orion_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
device->controller_priv = hw;
|
||||
hw->target = get_target(args[1]);
|
||||
nand->controller_priv = hw;
|
||||
hw->target = get_target(CMD_ARGV[1]);
|
||||
if (!hw->target) {
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
||||
free(hw);
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
base = strtoul(args[2], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base);
|
||||
cle = 0;
|
||||
ale = 1;
|
||||
|
||||
@@ -162,16 +156,17 @@ int orion_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
|
||||
hw->io.target = hw->target;
|
||||
hw->io.data = hw->data;
|
||||
hw->io.op = ARM_NAND_NONE;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_init(struct nand_device_s *device)
|
||||
static int orion_nand_init(struct nand_device *nand)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
nand_flash_controller_t orion_nand_controller =
|
||||
struct nand_flash_controller orion_nand_controller =
|
||||
{
|
||||
.name = "orion",
|
||||
.command = orion_nand_command,
|
||||
@@ -182,7 +177,6 @@ nand_flash_controller_t orion_nand_controller =
|
||||
.reset = orion_nand_reset,
|
||||
.controller_ready = orion_nand_controller_ready,
|
||||
.nand_device_command = orion_nand_device_command,
|
||||
.register_commands = orion_nand_register_commands,
|
||||
.init = orion_nand_init,
|
||||
};
|
||||
|
||||
@@ -28,42 +28,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
static int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2410_init(struct nand_device_s *device);
|
||||
static int s3c2410_read_data(struct nand_device_s *device, void *data);
|
||||
static int s3c2410_write_data(struct nand_device_s *device, uint16_t data);
|
||||
static int s3c2410_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
nand_flash_controller_t s3c2410_nand_controller =
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command)
|
||||
{
|
||||
.name = "s3c2410",
|
||||
.nand_device_command = s3c2410_nand_device_command,
|
||||
.register_commands = s3c24xx_register_commands,
|
||||
.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,
|
||||
.controller_ready = s3c24xx_controller_ready,
|
||||
.nand_ready = s3c2410_nand_ready,
|
||||
};
|
||||
|
||||
static int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *info;
|
||||
|
||||
info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);
|
||||
if (info == NULL) {
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
struct s3c24xx_nand_controller *info;
|
||||
CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
|
||||
|
||||
/* fill in the address fields for the core device */
|
||||
info->cmd = S3C2410_NFCMD;
|
||||
@@ -74,10 +44,10 @@ static int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2410_init(struct nand_device_s *device)
|
||||
static int s3c2410_init(struct nand_device *nand)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
target_write_u32(target, S3C2410_NFCONF,
|
||||
S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) |
|
||||
@@ -86,10 +56,10 @@ static int s3c2410_init(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2410_write_data(struct nand_device_s *device, uint16_t data)
|
||||
static int s3c2410_write_data(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -100,10 +70,10 @@ static int s3c2410_write_data(struct nand_device_s *device, uint16_t data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2410_read_data(struct nand_device_s *device, void *data)
|
||||
static int s3c2410_read_data(struct nand_device *nand, void *data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -114,10 +84,10 @@ static int s3c2410_read_data(struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2410_nand_ready(struct nand_device_s *device, int timeout)
|
||||
static int s3c2410_nand_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
uint8_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
@@ -136,3 +106,18 @@ static int s3c2410_nand_ready(struct nand_device_s *device, int timeout)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &s3c24xx_controller_ready,
|
||||
.nand_ready = &s3c2410_nand_ready,
|
||||
};
|
||||
@@ -28,41 +28,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
static int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2412_init(struct nand_device_s *device);
|
||||
|
||||
nand_flash_controller_t s3c2412_nand_controller =
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command)
|
||||
{
|
||||
.name = "s3c2412",
|
||||
.nand_device_command = s3c2412_nand_device_command,
|
||||
.register_commands = s3c24xx_register_commands,
|
||||
.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,
|
||||
.controller_ready = s3c24xx_controller_ready,
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
static int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *info;
|
||||
|
||||
info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);
|
||||
if (info == NULL) {
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
struct s3c24xx_nand_controller *info;
|
||||
CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
|
||||
|
||||
/* fill in the address fields for the core device */
|
||||
info->cmd = S3C2440_NFCMD;
|
||||
@@ -73,10 +44,10 @@ static int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2412_init(struct nand_device_s *device)
|
||||
static int s3c2412_init(struct nand_device *nand)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
target_write_u32(target, S3C2410_NFCONF,
|
||||
S3C2440_NFCONF_TACLS(3) |
|
||||
@@ -89,3 +60,20 @@ static int s3c2412_init(struct nand_device_s *device)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &s3c24xx_controller_ready,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
@@ -28,42 +28,13 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
static int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2440_init(struct nand_device_s *device);
|
||||
//static int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
nand_flash_controller_t s3c2440_nand_controller =
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command)
|
||||
{
|
||||
.name = "s3c2440",
|
||||
.nand_device_command = s3c2440_nand_device_command,
|
||||
.register_commands = s3c24xx_register_commands,
|
||||
.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,
|
||||
.controller_ready = s3c24xx_controller_ready,
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
static int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *info;
|
||||
|
||||
info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);
|
||||
if (info == NULL) {
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
struct s3c24xx_nand_controller *info;
|
||||
CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
|
||||
|
||||
/* fill in the address fields for the core device */
|
||||
info->cmd = S3C2440_NFCMD;
|
||||
@@ -74,10 +45,10 @@ static int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2440_init(struct nand_device_s *device)
|
||||
static int s3c2440_init(struct nand_device *nand)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
target_write_u32(target, S3C2410_NFCONF,
|
||||
S3C2440_NFCONF_TACLS(3) |
|
||||
@@ -90,10 +61,10 @@ static int s3c2440_init(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2440_nand_ready(struct nand_device_s *device, int timeout)
|
||||
int s3c2440_nand_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
uint8_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
@@ -116,14 +87,14 @@ int s3c2440_nand_ready(struct nand_device_s *device, int timeout)
|
||||
|
||||
/* use the fact we can read/write 4 bytes in one go via a single 32bit op */
|
||||
|
||||
int s3c2440_read_block_data(struct nand_device_s *device, uint8_t *data, int data_size)
|
||||
int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
uint32_t nfdata = s3c24xx_info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, device, data, data_size);
|
||||
LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, nand, data, data_size);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -152,10 +123,10 @@ int s3c2440_read_block_data(struct nand_device_s *device, uint8_t *data, int dat
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2440_write_block_data(struct nand_device_s *device, uint8_t *data, int data_size)
|
||||
int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
uint32_t nfdata = s3c24xx_info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
@@ -181,3 +152,20 @@ int s3c2440_write_block_data(struct nand_device_s *device, uint8_t *data, int da
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &s3c24xx_controller_ready,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
@@ -28,41 +28,13 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
static int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2443_init(struct nand_device_s *device);
|
||||
|
||||
nand_flash_controller_t s3c2443_nand_controller =
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command)
|
||||
{
|
||||
.name = "s3c2443",
|
||||
.nand_device_command = s3c2443_nand_device_command,
|
||||
.register_commands = s3c24xx_register_commands,
|
||||
.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,
|
||||
.controller_ready = s3c24xx_controller_ready,
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
static int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *info;
|
||||
|
||||
info = s3c24xx_nand_device_command(cmd_ctx, cmd, args, argc, device);
|
||||
if (info == NULL) {
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
struct s3c24xx_nand_controller *info;
|
||||
CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
|
||||
|
||||
/* fill in the address fields for the core device */
|
||||
info->cmd = S3C2440_NFCMD;
|
||||
@@ -73,10 +45,10 @@ static int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c2443_init(struct nand_device_s *device)
|
||||
static int s3c2443_init(struct nand_device *nand)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
target_write_u32(target, S3C2410_NFCONF,
|
||||
S3C2440_NFCONF_TACLS(3) |
|
||||
@@ -89,3 +61,20 @@ static int s3c2443_init(struct nand_device_s *device)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &s3c24xx_controller_ready,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
@@ -28,42 +28,37 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "s3c24xx.h"
|
||||
|
||||
|
||||
s3c24xx_nand_controller_t *
|
||||
s3c24xx_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
S3C24XX_DEVICE_COMMAND()
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info;
|
||||
*info = NULL;
|
||||
|
||||
s3c24xx_info = malloc(sizeof(s3c24xx_nand_controller_t));
|
||||
struct s3c24xx_nand_controller *s3c24xx_info;
|
||||
s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller));
|
||||
if (s3c24xx_info == NULL) {
|
||||
LOG_ERROR("no memory for nand controller\n");
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
device->controller_priv = s3c24xx_info;
|
||||
nand->controller_priv = s3c24xx_info;
|
||||
|
||||
s3c24xx_info->target = get_target(args[1]);
|
||||
s3c24xx_info->target = get_target(CMD_ARGV[1]);
|
||||
if (s3c24xx_info->target == NULL) {
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
return NULL;
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
return s3c24xx_info;
|
||||
}
|
||||
*info = s3c24xx_info;
|
||||
|
||||
int s3c24xx_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_reset(struct nand_device_s *device)
|
||||
int s3c24xx_reset(struct nand_device *nand)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -75,10 +70,10 @@ int s3c24xx_reset(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_command(struct nand_device_s *device, uint8_t command)
|
||||
int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -90,10 +85,10 @@ int s3c24xx_command(struct nand_device_s *device, uint8_t command)
|
||||
}
|
||||
|
||||
|
||||
int s3c24xx_address(struct nand_device_s *device, uint8_t address)
|
||||
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -104,10 +99,10 @@ int s3c24xx_address(struct nand_device_s *device, uint8_t address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_write_data(struct nand_device_s *device, uint16_t data)
|
||||
int s3c24xx_write_data(struct nand_device *nand, uint16_t data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -118,10 +113,10 @@ int s3c24xx_write_data(struct nand_device_s *device, uint16_t data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_read_data(struct nand_device_s *device, void *data)
|
||||
int s3c24xx_read_data(struct nand_device *nand, void *data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -132,7 +127,7 @@ int s3c24xx_read_data(struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_controller_ready(struct nand_device_s *device, int timeout)
|
||||
int s3c24xx_controller_ready(struct nand_device *nand, int timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -18,46 +18,68 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef S3C24xx_NAND_H
|
||||
#define S3C24xx_NAND_H
|
||||
|
||||
/*
|
||||
* S3C24XX Series OpenOCD NAND Flash controller support.
|
||||
*
|
||||
* Many thanks to Simtec Electronics for sponsoring this work.
|
||||
*/
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_regs_nand.h"
|
||||
#include "imp.h"
|
||||
#include "s3c24xx_regs.h"
|
||||
#include <target/target.h>
|
||||
|
||||
typedef struct s3c24xx_nand_controller_s
|
||||
struct s3c24xx_nand_controller
|
||||
{
|
||||
struct target_s *target;
|
||||
struct target *target;
|
||||
|
||||
/* register addresses */
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t data;
|
||||
uint32_t nfstat;
|
||||
} s3c24xx_nand_controller_t;
|
||||
};
|
||||
|
||||
/* Default to using the un-translated NAND register based address */
|
||||
#undef S3C2410_NFREG
|
||||
#define S3C2410_NFREG(x) ((x) + 0x4e000000)
|
||||
|
||||
extern s3c24xx_nand_controller_t *s3c24xx_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
#define S3C24XX_DEVICE_COMMAND() \
|
||||
COMMAND_HELPER(s3c24xx_nand_device_command, \
|
||||
struct nand_device *nand, \
|
||||
struct s3c24xx_nand_controller **info)
|
||||
|
||||
extern int s3c24xx_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int s3c24xx_reset(struct nand_device_s *device);
|
||||
extern int s3c24xx_command(struct nand_device_s *device, uint8_t command);
|
||||
extern int s3c24xx_address(struct nand_device_s *device, uint8_t address);
|
||||
extern int s3c24xx_write_data(struct nand_device_s *device, uint16_t data);
|
||||
extern int s3c24xx_read_data(struct nand_device_s *device, void *data);
|
||||
extern int s3c24xx_controller_ready(struct nand_device_s *device, int tout);
|
||||
S3C24XX_DEVICE_COMMAND();
|
||||
|
||||
#define CALL_S3C24XX_DEVICE_COMMAND(d, i) \
|
||||
do { \
|
||||
int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \
|
||||
if (ERROR_OK != retval) \
|
||||
return retval; \
|
||||
} while (0)
|
||||
|
||||
int s3c24xx_reset(struct nand_device *nand);
|
||||
|
||||
int s3c24xx_command(struct nand_device *nand, uint8_t command);
|
||||
int s3c24xx_address(struct nand_device *nand, uint8_t address);
|
||||
|
||||
int s3c24xx_write_data(struct nand_device *nand, uint16_t data);
|
||||
int s3c24xx_read_data(struct nand_device *nand, void *data);
|
||||
|
||||
int s3c24xx_controller_ready(struct nand_device *nand, int tout);
|
||||
|
||||
#define s3c24xx_write_page NULL
|
||||
#define s3c24xx_read_page NULL
|
||||
|
||||
/* code shared between different controllers */
|
||||
|
||||
extern int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
|
||||
int s3c2440_nand_ready(struct nand_device *nand, int timeout);
|
||||
|
||||
extern int s3c2440_read_block_data(struct nand_device_s *, uint8_t *data, int data_size);
|
||||
extern int s3c2440_write_block_data(struct nand_device_s *, uint8_t *data, int data_size);
|
||||
int s3c2440_read_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size);
|
||||
int s3c2440_write_block_data(struct nand_device *nand,
|
||||
uint8_t *data, int data_size);
|
||||
|
||||
#endif // S3C24xx_NAND_H
|
||||
76
src/flash/nand/s3c6400.c
Normal file
76
src/flash/nand/s3c6400.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Peter Korsgaard <jacmet@sunsite.dk> *
|
||||
* Heavily based on s3c2412.c by Ben Dooks <ben@fluff.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "s3c24xx.h"
|
||||
/* s3c64xx uses another base address for the nand controller than 24xx */
|
||||
#undef S3C2410_NFREG
|
||||
#define S3C2410_NFREG(x) ((x) + 0x70200000)
|
||||
|
||||
NAND_DEVICE_COMMAND_HANDLER(s3c6400_nand_device_command)
|
||||
{
|
||||
struct s3c24xx_nand_controller *info;
|
||||
CALL_S3C24XX_DEVICE_COMMAND(nand, &info);
|
||||
|
||||
/* fill in the address fields for the core device */
|
||||
info->cmd = S3C2440_NFCMD;
|
||||
info->addr = S3C2440_NFADDR;
|
||||
info->data = S3C2440_NFDATA;
|
||||
info->nfstat = S3C2412_NFSTAT;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int s3c6400_init(struct nand_device *nand)
|
||||
{
|
||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||
struct target *target = s3c24xx_info->target;
|
||||
|
||||
target_write_u32(target, S3C2410_NFCONF,
|
||||
S3C2440_NFCONF_TACLS(3) |
|
||||
S3C2440_NFCONF_TWRPH0(7) |
|
||||
S3C2440_NFCONF_TWRPH1(7) | 4);
|
||||
|
||||
target_write_u32(target, S3C2440_NFCONT,
|
||||
S3C2412_NFCONT_INIT_MAIN_ECC |
|
||||
S3C2440_NFCONT_ENABLE);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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,
|
||||
.controller_ready = &s3c24xx_controller_ready,
|
||||
.nand_ready = &s3c2440_nand_ready,
|
||||
};
|
||||
647
src/flash/nand/tcl.c
Normal file
647
src/flash/nand/tcl.c
Normal file
@@ -0,0 +1,647 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Partially based on drivers/mtd/nand_ids.c from Linux. *
|
||||
* *
|
||||
* 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 "core.h"
|
||||
#include "imp.h"
|
||||
#include "fileio.h"
|
||||
|
||||
// to be removed
|
||||
extern struct nand_device *nand_devices;
|
||||
|
||||
COMMAND_HANDLER(handle_nand_list_command)
|
||||
{
|
||||
struct nand_device *p;
|
||||
int i;
|
||||
|
||||
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++)
|
||||
{
|
||||
if (p->device)
|
||||
command_print(CMD_CTX, "#%i: %s (%s) "
|
||||
"pagesize: %i, buswidth: %i,\n\t"
|
||||
"blocksize: %i, blocks: %i",
|
||||
i, p->device->name, p->manufacturer->name,
|
||||
p->page_size, p->bus_width,
|
||||
p->erase_size, p->num_blocks);
|
||||
else
|
||||
command_print(CMD_CTX, "#%i: not probed", i);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_info_command)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int first = -1;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (first >= p->num_blocks)
|
||||
first = p->num_blocks - 1;
|
||||
|
||||
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);
|
||||
|
||||
for (j = first; j <= last; j++)
|
||||
{
|
||||
char *erase_state, *bad_state;
|
||||
|
||||
if (p->blocks[j].is_erased == 0)
|
||||
erase_state = "not erased";
|
||||
else if (p->blocks[j].is_erased == 1)
|
||||
erase_state = "erased";
|
||||
else
|
||||
erase_state = "erase state unknown";
|
||||
|
||||
if (p->blocks[j].is_bad == 0)
|
||||
bad_state = "";
|
||||
else if (p->blocks[j].is_bad == 1)
|
||||
bad_state = " (marked bad)";
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
command_print(CMD_CTX, "NAND flash device '%s' found", p->device->name);
|
||||
}
|
||||
else if (retval == ERROR_NAND_OPERATION_FAILED)
|
||||
{
|
||||
command_print(CMD_CTX, "probing failed for NAND flash device");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(CMD_CTX, "unknown error when probing NAND flash device");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
return retval;
|
||||
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
|
||||
/* erase specified part of the chip; or else everything */
|
||||
if (CMD_ARGC == 3) {
|
||||
unsigned long size = p->erase_size * p->num_blocks;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||
if ((offset % p->erase_size) != 0 || offset >= size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
||||
if ((length == 0) || (length % p->erase_size) != 0
|
||||
|| (length + offset) > size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
offset /= p->erase_size;
|
||||
length /= p->erase_size;
|
||||
} else {
|
||||
offset = 0;
|
||||
length = p->num_blocks;
|
||||
}
|
||||
|
||||
retval = nand_erase(p, offset, offset + length - 1);
|
||||
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);
|
||||
}
|
||||
else if (retval == ERROR_NAND_OPERATION_FAILED)
|
||||
{
|
||||
command_print(CMD_CTX, "erase failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(CMD_CTX, "unknown error when erasing NAND flash device");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
||||
{
|
||||
int first = -1;
|
||||
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)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset);
|
||||
if (offset % p->erase_size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
offset /= p->erase_size;
|
||||
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length);
|
||||
if (length % p->erase_size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
length -= 1;
|
||||
length /= p->erase_size;
|
||||
|
||||
first = offset;
|
||||
last = offset + length;
|
||||
}
|
||||
|
||||
retval = nand_build_bbt(p, first, last);
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
|
||||
"use \"nand info\" command to list blocks");
|
||||
}
|
||||
else if (retval == ERROR_NAND_OPERATION_FAILED)
|
||||
{
|
||||
command_print(CMD_CTX, "error when checking for bad blocks on "
|
||||
"NAND flash device");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(CMD_CTX, "unknown error when checking for bad "
|
||||
"blocks on NAND flash device");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_write_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct nand_fileio_state s;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
|
||||
&s, &nand, FILEIO_READ, false, true);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
uint32_t total_bytes = s.size;
|
||||
while (s.size > 0)
|
||||
{
|
||||
int bytes_read = nand_fileio_read(nand, &s);
|
||||
if (bytes_read <= 0)
|
||||
{
|
||||
command_print(CMD_CTX, "error while reading file");
|
||||
return nand_fileio_cleanup(&s);
|
||||
}
|
||||
s.size -= bytes_read;
|
||||
|
||||
retval = nand_write_page(nand, s.address / nand->page_size,
|
||||
s.page, s.page_size, s.oob, s.oob_size);
|
||||
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);
|
||||
return nand_fileio_cleanup(&s);
|
||||
}
|
||||
s.address += s.page_size;
|
||||
}
|
||||
|
||||
if (nand_fileio_finish(&s))
|
||||
{
|
||||
command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
|
||||
"offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
|
||||
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, total_bytes));
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_verify_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct nand_fileio_state file;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
|
||||
&file, &nand, FILEIO_READ, false, true);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct nand_fileio_state dev;
|
||||
nand_fileio_init(&dev);
|
||||
dev.address = file.address;
|
||||
dev.size = file.size;
|
||||
dev.oob_format = file.oob_format;
|
||||
retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
while (file.size > 0)
|
||||
{
|
||||
int retval = nand_read_page(nand, dev.address / dev.page_size,
|
||||
dev.page, dev.page_size, dev.oob, dev.oob_size);
|
||||
if (ERROR_OK != retval)
|
||||
{
|
||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||
nand_fileio_cleanup(&dev);
|
||||
return nand_fileio_cleanup(&file);
|
||||
}
|
||||
|
||||
int bytes_read = nand_fileio_read(nand, &file);
|
||||
if (bytes_read <= 0)
|
||||
{
|
||||
command_print(CMD_CTX, "error while reading file");
|
||||
nand_fileio_cleanup(&dev);
|
||||
return nand_fileio_cleanup(&file);
|
||||
}
|
||||
|
||||
if ((dev.page && memcmp(dev.page, file.page, dev.page_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);
|
||||
nand_fileio_cleanup(&dev);
|
||||
return nand_fileio_cleanup(&file);
|
||||
}
|
||||
|
||||
file.size -= bytes_read;
|
||||
dev.address += nand->page_size;
|
||||
}
|
||||
|
||||
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 kb/s)",
|
||||
CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
|
||||
duration_kbps(&file.bench, dev.size));
|
||||
}
|
||||
|
||||
return nand_fileio_cleanup(&dev);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_dump_command)
|
||||
{
|
||||
struct nand_device *nand = NULL;
|
||||
struct nand_fileio_state s;
|
||||
int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
|
||||
&s, &nand, FILEIO_WRITE, true, false);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
while (s.size > 0)
|
||||
{
|
||||
size_t size_written;
|
||||
int retval = nand_read_page(nand, s.address / nand->page_size,
|
||||
s.page, s.page_size, s.oob, s.oob_size);
|
||||
if (ERROR_OK != retval)
|
||||
{
|
||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||
return nand_fileio_cleanup(&s);
|
||||
}
|
||||
|
||||
if (NULL != s.page)
|
||||
fileio_write(&s.fileio, s.page_size, s.page, &size_written);
|
||||
|
||||
if (NULL != s.oob)
|
||||
fileio_write(&s.fileio, s.oob_size, s.oob, &size_written);
|
||||
|
||||
s.size -= nand->page_size;
|
||||
s.address += nand->page_size;
|
||||
}
|
||||
|
||||
if (nand_fileio_finish(&s) == ERROR_OK)
|
||||
{
|
||||
command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f kb/s)",
|
||||
(long)s.fileio.size, duration_elapsed(&s.bench),
|
||||
duration_kbps(&s.bench, s.fileio.size));
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (CMD_ARGC == 2)
|
||||
COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw);
|
||||
|
||||
const char *msg = p->use_raw ? "enabled" : "disabled";
|
||||
command_print(CMD_CTX, "raw access is %s", msg);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration nand_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "list",
|
||||
.handler = handle_nand_list_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "list configured NAND flash devices",
|
||||
},
|
||||
{
|
||||
.name = "info",
|
||||
.handler = handle_nand_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "[banknum | first_bank_num last_bank_num]",
|
||||
.help = "print info about one or more NAND flash devices",
|
||||
},
|
||||
{
|
||||
.name = "probe",
|
||||
.handler = handle_nand_probe_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "identify NAND flash device",
|
||||
},
|
||||
{
|
||||
.name = "check_bad_blocks",
|
||||
.handler = handle_nand_check_bad_blocks_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id [offset length]",
|
||||
.help = "check all or part of NAND flash device for bad blocks",
|
||||
},
|
||||
{
|
||||
.name = "erase",
|
||||
.handler = handle_nand_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id [offset length]",
|
||||
.help = "erase all or subset of blocks on NAND flash device",
|
||||
},
|
||||
{
|
||||
.name = "dump",
|
||||
.handler = handle_nand_dump_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id filename offset length "
|
||||
"['oob_raw'|'oob_only']",
|
||||
.help = "dump from NAND flash device",
|
||||
},
|
||||
{
|
||||
.name = "verify",
|
||||
.handler = handle_nand_verify_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id filename offset "
|
||||
"['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
|
||||
.help = "verify NAND flash device",
|
||||
},
|
||||
{
|
||||
.name = "write",
|
||||
.handler = handle_nand_write_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id filename offset "
|
||||
"['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']",
|
||||
.help = "write to NAND flash device",
|
||||
},
|
||||
{
|
||||
.name = "raw_access",
|
||||
.handler = handle_nand_raw_access_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id ['enable'|'disable']",
|
||||
.help = "raw access to NAND flash device",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
int nand_init(struct command_context *cmd_ctx)
|
||||
{
|
||||
if (!nand_devices)
|
||||
return ERROR_OK;
|
||||
struct command *parent = command_find_in_context(cmd_ctx, "nand");
|
||||
return register_commands(cmd_ctx, parent, nand_exec_command_handlers);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_init_command)
|
||||
{
|
||||
if (CMD_ARGC != 0)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
static bool nand_initialized = false;
|
||||
if (nand_initialized)
|
||||
{
|
||||
LOG_INFO("'nand init' has already been called");
|
||||
return ERROR_OK;
|
||||
}
|
||||
nand_initialized = true;
|
||||
|
||||
LOG_DEBUG("Initializing NAND devices...");
|
||||
return nand_init(CMD_CTX);
|
||||
}
|
||||
int nand_list_walker(struct nand_flash_controller *c, void *x)
|
||||
{
|
||||
struct command_context *cmd_ctx = (struct command_context *)x;
|
||||
command_print(cmd_ctx, " %s", c->name);
|
||||
return ERROR_OK;
|
||||
}
|
||||
COMMAND_HANDLER(handle_nand_list_drivers)
|
||||
{
|
||||
command_print(CMD_CTX, "Available NAND flash controller drivers:");
|
||||
return nand_driver_walk(&nand_list_walker, CMD_CTX);
|
||||
}
|
||||
|
||||
static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
||||
struct nand_flash_controller *controller)
|
||||
{
|
||||
if (NULL != controller->commands)
|
||||
{
|
||||
int retval = register_commands(CMD_CTX, NULL,
|
||||
controller->commands);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
struct nand_device *c = malloc(sizeof(struct nand_device));
|
||||
|
||||
c->name = strdup(bank_name);
|
||||
c->controller = controller;
|
||||
c->controller_priv = NULL;
|
||||
c->manufacturer = NULL;
|
||||
c->device = NULL;
|
||||
c->bus_width = 0;
|
||||
c->address_cycles = 0;
|
||||
c->page_size = 0;
|
||||
c->use_raw = 0;
|
||||
c->next = NULL;
|
||||
|
||||
int retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
||||
if (ERROR_OK != retval)
|
||||
{
|
||||
LOG_ERROR("'%s' driver rejected nand flash", controller->name);
|
||||
free(c);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
nand_device_add(c);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_nand_device_command)
|
||||
{
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
LOG_ERROR("incomplete nand device configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
LOG_ERROR("No valid NAND flash driver found (%s)", driver_name);
|
||||
return CALL_COMMAND_HANDLER(handle_nand_list_drivers);
|
||||
}
|
||||
return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller);
|
||||
}
|
||||
|
||||
static const struct command_registration nand_config_command_handlers[] = {
|
||||
{
|
||||
.name = "device",
|
||||
.handler = &handle_nand_device_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "defines a new NAND bank",
|
||||
.usage = "bank_id driver target [driver_options ...]",
|
||||
},
|
||||
{
|
||||
.name = "drivers",
|
||||
.handler = &handle_nand_list_drivers,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "lists available NAND drivers",
|
||||
},
|
||||
{
|
||||
.name = "init",
|
||||
.mode = COMMAND_CONFIG,
|
||||
.handler = &handle_nand_init_command,
|
||||
.help = "initialize NAND devices",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration nand_command_handlers[] = {
|
||||
{
|
||||
.name = "nand",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "NAND flash command group",
|
||||
.chain = nand_config_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
int nand_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL, nand_command_handlers);
|
||||
}
|
||||
|
||||
|
||||
53
src/flash/nor/Makefile.am
Normal file
53
src/flash/nor/Makefile.am
Normal file
@@ -0,0 +1,53 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_builddir)/src
|
||||
|
||||
noinst_LTLIBRARIES = libocdflashnor.la
|
||||
libocdflashnor_la_SOURCES = \
|
||||
core.c \
|
||||
tcl.c \
|
||||
$(NOR_DRIVERS) \
|
||||
drivers.c
|
||||
|
||||
NOR_DRIVERS = \
|
||||
aduc702x.c \
|
||||
at91sam3.c \
|
||||
at91sam7.c \
|
||||
avrf.c \
|
||||
cfi.c \
|
||||
ecos.c \
|
||||
faux.c \
|
||||
lpc2000.c \
|
||||
lpc288x.c \
|
||||
lpc2900.c \
|
||||
non_cfi.c \
|
||||
ocl.c \
|
||||
pic32mx.c \
|
||||
stellaris.c \
|
||||
stm32x.c \
|
||||
str7x.c \
|
||||
str9x.c \
|
||||
str9xpec.c \
|
||||
tms470.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
at91sam7.h \
|
||||
at91sam3.h \
|
||||
avrf.h \
|
||||
core.h \
|
||||
cfi.h \
|
||||
driver.h \
|
||||
imp.h \
|
||||
lpc2000.h \
|
||||
lpc288x.h \
|
||||
non_cfi.h \
|
||||
ocl.h \
|
||||
pic32mx.h \
|
||||
stellaris.h \
|
||||
stm32x.h \
|
||||
str7x.h \
|
||||
str9x.h \
|
||||
str9xpec.h \
|
||||
tms470.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
@@ -23,25 +23,16 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "flash.h"
|
||||
#include "armv4_5.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "time_support.h"
|
||||
#include "imp.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/arm.h>
|
||||
|
||||
|
||||
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int aduc702x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_probe(struct flash_bank_s *bank);
|
||||
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int aduc702x_protect_check(struct flash_bank_s *bank);
|
||||
static int aduc702x_build_sector_list(struct flash_bank_s *bank);
|
||||
static int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms);
|
||||
static int aduc702x_set_write_enable(target_t *target, int enable);
|
||||
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_set_write_enable(struct target *target, int enable);
|
||||
|
||||
#define ADUC702x_FLASH 0xfffff800
|
||||
#define ADUC702x_FLASH_FEESTA (0*4)
|
||||
@@ -53,49 +44,17 @@ static int aduc702x_set_write_enable(target_t *target, int enable);
|
||||
#define ADUC702x_FLASH_FEEPRO (6*4)
|
||||
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
||||
|
||||
typedef struct {
|
||||
uint32_t feesta;
|
||||
uint32_t feemod;
|
||||
uint32_t feecon;
|
||||
uint32_t feedat;
|
||||
uint32_t feeadr;
|
||||
uint32_t feesign;
|
||||
uint32_t feepro;
|
||||
uint32_t feehide;
|
||||
} ADUC702x_FLASH_MMIO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
working_area_t *write_algorithm;
|
||||
} aduc702x_flash_bank_t;
|
||||
|
||||
flash_driver_t aduc702x_flash =
|
||||
{
|
||||
.name = "aduc702x",
|
||||
.register_commands = aduc702x_register_commands,
|
||||
.flash_bank_command = aduc702x_flash_bank_command,
|
||||
.erase = aduc702x_erase,
|
||||
.protect = aduc702x_protect,
|
||||
.write = aduc702x_write,
|
||||
.probe = aduc702x_probe,
|
||||
.auto_probe = aduc702x_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = aduc702x_protect_check,
|
||||
.info = aduc702x_info
|
||||
struct aduc702x_flash_bank {
|
||||
struct working_area *write_algorithm;
|
||||
};
|
||||
|
||||
static int aduc702x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash bank aduc702x 0 0 0 0 <target#>
|
||||
* The ADC7019-28 devices all have the same flash layout */
|
||||
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
|
||||
{
|
||||
aduc702x_flash_bank_t *nbank;
|
||||
struct aduc702x_flash_bank *nbank;
|
||||
|
||||
nbank = malloc(sizeof(aduc702x_flash_bank_t));
|
||||
nbank = malloc(sizeof(struct aduc702x_flash_bank));
|
||||
|
||||
bank->base = 0x80000;
|
||||
bank->size = 0xF800; // top 4k not accessible
|
||||
@@ -106,16 +65,16 @@ static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aduc702x_build_sector_list(struct flash_bank_s *bank)
|
||||
static int aduc702x_build_sector_list(struct flash_bank *bank)
|
||||
{
|
||||
//aduc7026_flash_bank_t *aduc7026_info = bank->driver_priv;
|
||||
//aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv;
|
||||
|
||||
int i = 0;
|
||||
uint32_t offset = 0;
|
||||
|
||||
// sector size is 512
|
||||
bank->num_sectors = bank->size / 512;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
for (i = 0; i < bank->num_sectors; ++i)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
@@ -128,19 +87,19 @@ static int aduc702x_build_sector_list(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aduc702x_protect_check(struct flash_bank_s *bank)
|
||||
static int aduc702x_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
printf("aduc702x_protect_check not implemented yet.\n");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
//int res;
|
||||
int x;
|
||||
int count;
|
||||
//uint32_t v;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
|
||||
@@ -187,7 +146,7 @@ static int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
printf("aduc702x_protect not implemented yet.\n");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -198,15 +157,15 @@ static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int l
|
||||
*
|
||||
* Caller should not check for other return values specifically
|
||||
*/
|
||||
static int aduc702x_write_block(struct flash_bank_s *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)
|
||||
{
|
||||
aduc702x_flash_bank_t *aduc702x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t buffer_size = 7000;
|
||||
working_area_t *source;
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[6];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
struct reg_param reg_params[6];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (((count%2)!=0)||((offset%2)!=0))
|
||||
@@ -282,9 +241,9 @@ static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint
|
||||
}
|
||||
}
|
||||
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
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_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
@@ -343,11 +302,11 @@ static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint
|
||||
|
||||
/* All-JTAG, single-access method. Very slow. Used only if there is no
|
||||
* working area available. */
|
||||
static int aduc702x_write_single(struct flash_bank_s *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;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
|
||||
@@ -384,7 +343,7 @@ static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uin
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -408,12 +367,12 @@ int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int aduc702x_probe(struct flash_bank_s *bank)
|
||||
static int aduc702x_probe(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "aduc702x flash driver info");
|
||||
return ERROR_OK;
|
||||
@@ -421,7 +380,7 @@ static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
|
||||
/* sets FEEMOD bit 3
|
||||
* enable = 1 enables writes & erases, 0 disables them */
|
||||
static int aduc702x_set_write_enable(target_t *target, int enable)
|
||||
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);
|
||||
@@ -434,7 +393,7 @@ static int aduc702x_set_write_enable(target_t *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(target_t* target, unsigned int timeout_ms)
|
||||
static int aduc702x_check_flash_completion(struct target* target, unsigned int timeout_ms)
|
||||
{
|
||||
uint8_t v = 4;
|
||||
|
||||
@@ -452,3 +411,15 @@ static int aduc702x_check_flash_completion(target_t* target, unsigned int timeou
|
||||
else return ERROR_OK;
|
||||
}
|
||||
|
||||
struct flash_driver aduc702x_flash = {
|
||||
.name = "aduc702x",
|
||||
.flash_bank_command = aduc702x_flash_bank_command,
|
||||
.erase = aduc702x_erase,
|
||||
.protect = aduc702x_protect,
|
||||
.write = aduc702x_write,
|
||||
.probe = aduc702x_probe,
|
||||
.auto_probe = aduc702x_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = aduc702x_protect_check,
|
||||
.info = aduc702x_info
|
||||
};
|
||||
@@ -57,16 +57,10 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "membuf.h"
|
||||
#include "imp.h"
|
||||
#include "at91sam3.h"
|
||||
#include "time_support.h"
|
||||
#include <helper/membuf.h>
|
||||
#include <helper/time_support.h>
|
||||
|
||||
#define REG_NAME_WIDTH (12)
|
||||
|
||||
@@ -175,7 +169,7 @@ struct sam3_bank_private {
|
||||
// so we can find the chip we belong to
|
||||
struct sam3_chip *pChip;
|
||||
// so we can find the orginal bank pointer
|
||||
flash_bank_t *pBank;
|
||||
struct flash_bank *pBank;
|
||||
unsigned bank_number;
|
||||
uint32_t controller_address;
|
||||
uint32_t base_address;
|
||||
@@ -215,7 +209,7 @@ struct sam3_chip {
|
||||
|
||||
// this is "initialized" from the global const structure
|
||||
struct sam3_chip_details details;
|
||||
target_t *target;
|
||||
struct target *target;
|
||||
struct sam3_cfg cfg;
|
||||
|
||||
struct membuf *mbuf;
|
||||
@@ -231,9 +225,9 @@ struct sam3_reg_list {
|
||||
static struct sam3_chip *all_sam3_chips;
|
||||
|
||||
static struct sam3_chip *
|
||||
get_current_sam3(struct command_context_s *cmd_ctx)
|
||||
get_current_sam3(struct command_context *cmd_ctx)
|
||||
{
|
||||
target_t *t;
|
||||
struct target *t;
|
||||
static struct sam3_chip *p;
|
||||
|
||||
t = get_current_target(cmd_ctx);
|
||||
@@ -1393,7 +1387,7 @@ sam3_explain_mckr(struct sam3_chip *pChip)
|
||||
|
||||
#if 0
|
||||
static struct sam3_chip *
|
||||
target2sam3(target_t *pTarget)
|
||||
target2sam3(struct target *pTarget)
|
||||
{
|
||||
struct sam3_chip *pChip;
|
||||
|
||||
@@ -1456,7 +1450,7 @@ static const struct sam3_reg_list sam3_all_regs[] = {
|
||||
|
||||
|
||||
static struct sam3_bank_private *
|
||||
get_sam3_bank_private(flash_bank_t *bank)
|
||||
get_sam3_bank_private(struct flash_bank *bank)
|
||||
{
|
||||
return (struct sam3_bank_private *)(bank->driver_priv);
|
||||
}
|
||||
@@ -1582,7 +1576,7 @@ sam3_GetInfo(struct sam3_chip *pChip)
|
||||
|
||||
|
||||
static int
|
||||
sam3_erase_check(struct flash_bank_s *bank)
|
||||
sam3_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
int x;
|
||||
|
||||
@@ -1606,7 +1600,7 @@ sam3_erase_check(struct flash_bank_s *bank)
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_protect_check(struct flash_bank_s *bank)
|
||||
sam3_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
int r;
|
||||
uint32_t v=0;
|
||||
@@ -1641,12 +1635,7 @@ sam3_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_flash_bank_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd,
|
||||
char **args,
|
||||
int argc,
|
||||
struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
|
||||
{
|
||||
struct sam3_chip *pChip;
|
||||
|
||||
@@ -1714,7 +1703,7 @@ sam3_GetDetails(struct sam3_bank_private *pPrivate)
|
||||
const struct sam3_chip_details *pDetails;
|
||||
struct sam3_chip *pChip;
|
||||
void *vp;
|
||||
flash_bank_t *saved_banks[SAM3_MAX_FLASH_BANKS];
|
||||
struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS];
|
||||
|
||||
unsigned x;
|
||||
const char *cp;
|
||||
@@ -1782,7 +1771,7 @@ sam3_GetDetails(struct sam3_bank_private *pPrivate)
|
||||
|
||||
|
||||
static int
|
||||
_sam3_probe(struct flash_bank_s *bank, int noise)
|
||||
_sam3_probe(struct flash_bank *bank, int noise)
|
||||
{
|
||||
unsigned x;
|
||||
int r;
|
||||
@@ -1866,13 +1855,13 @@ _sam3_probe(struct flash_bank_s *bank, int noise)
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_probe(struct flash_bank_s *bank)
|
||||
sam3_probe(struct flash_bank *bank)
|
||||
{
|
||||
return _sam3_probe(bank, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_auto_probe(struct flash_bank_s *bank)
|
||||
sam3_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
return _sam3_probe(bank, 0);
|
||||
}
|
||||
@@ -1880,7 +1869,7 @@ sam3_auto_probe(struct flash_bank_s *bank)
|
||||
|
||||
|
||||
static int
|
||||
sam3_erase(struct flash_bank_s *bank, int first, int last)
|
||||
sam3_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct sam3_bank_private *pPrivate;
|
||||
int r;
|
||||
@@ -1912,7 +1901,7 @@ sam3_erase(struct flash_bank_s *bank, int first, int last)
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
sam3_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
struct sam3_bank_private *pPrivate;
|
||||
int r;
|
||||
@@ -1941,7 +1930,7 @@ sam3_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
|
||||
|
||||
static int
|
||||
sam3_info(flash_bank_t *bank, char *buf, int buf_size)
|
||||
sam3_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
@@ -2109,7 +2098,7 @@ sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *b
|
||||
|
||||
|
||||
static int
|
||||
sam3_write(struct flash_bank_s *bank,
|
||||
sam3_write(struct flash_bank *bank,
|
||||
uint8_t *buffer,
|
||||
uint32_t offset,
|
||||
uint32_t count)
|
||||
@@ -2266,8 +2255,7 @@ sam3_write(struct flash_bank_s *bank,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_handle_info_command(struct command_context_s *cmd_ctx, char *cmd, char **argv, int argc)
|
||||
COMMAND_HANDLER(sam3_handle_info_command)
|
||||
{
|
||||
struct sam3_chip *pChip;
|
||||
void *vp;
|
||||
@@ -2275,7 +2263,7 @@ sam3_handle_info_command(struct command_context_s *cmd_ctx, char *cmd, char **ar
|
||||
unsigned x;
|
||||
int r;
|
||||
|
||||
pChip = get_current_sam3(cmd_ctx);
|
||||
pChip = get_current_sam3(CMD_CTX);
|
||||
if (!pChip) {
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -2286,7 +2274,7 @@ sam3_handle_info_command(struct command_context_s *cmd_ctx, char *cmd, char **ar
|
||||
if (pChip->details.bank[0].pBank == NULL) {
|
||||
x = 0;
|
||||
need_define:
|
||||
command_print(cmd_ctx,
|
||||
command_print(CMD_CTX,
|
||||
"Please define bank %d via command: flash bank %s ... ",
|
||||
x,
|
||||
at91sam3_flash.name);
|
||||
@@ -2300,7 +2288,7 @@ sam3_handle_info_command(struct command_context_s *cmd_ctx, char *cmd, char **ar
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
// above garentees the "chip details" structure is valid
|
||||
// above guarantees the "chip details" structure is valid
|
||||
// and thus, bank private areas are valid
|
||||
// and we have a SAM3 chip, what a concept!
|
||||
|
||||
@@ -2337,21 +2325,19 @@ sam3_handle_info_command(struct command_context_s *cmd_ctx, char *cmd, char **ar
|
||||
// print results
|
||||
cp = membuf_strtok(pChip->mbuf, "\n", &vp);
|
||||
while (cp) {
|
||||
command_print(cmd_ctx,"%s", cp);
|
||||
command_print(CMD_CTX,"%s", cp);
|
||||
cp = membuf_strtok(NULL, "\n", &vp);
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **argv, int argc)
|
||||
COMMAND_HANDLER(sam3_handle_gpnvm_command)
|
||||
{
|
||||
unsigned x,v;
|
||||
uint32_t v32;
|
||||
int r,who;
|
||||
struct sam3_chip *pChip;
|
||||
|
||||
pChip = get_current_sam3(cmd_ctx);
|
||||
pChip = get_current_sam3(CMD_CTX);
|
||||
if (!pChip) {
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -2363,7 +2349,7 @@ sam3_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **a
|
||||
|
||||
|
||||
if (pChip->details.bank[0].pBank == NULL) {
|
||||
command_print(cmd_ctx, "Bank0 must be defined first via: flash bank %s ...",
|
||||
command_print(CMD_CTX, "Bank0 must be defined first via: flash bank %s ...",
|
||||
at91sam3_flash.name);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -2375,9 +2361,9 @@ sam3_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **a
|
||||
}
|
||||
|
||||
|
||||
switch (argc) {
|
||||
switch (CMD_ARGC) {
|
||||
default:
|
||||
command_print(cmd_ctx,"Too many parameters\n");
|
||||
command_print(CMD_CTX,"Too many parameters\n");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
case 0:
|
||||
@@ -2388,144 +2374,142 @@ sam3_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **a
|
||||
who = -1;
|
||||
break;
|
||||
case 2:
|
||||
if ((0 == strcmp(argv[0], "show")) && (0 == strcmp(argv[1], "all"))) {
|
||||
if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) {
|
||||
who = -1;
|
||||
} else {
|
||||
r = parse_u32(argv[1], &v32);
|
||||
if (r != ERROR_OK) {
|
||||
command_print(cmd_ctx, "Not a number: %s", argv[1]);
|
||||
return r;
|
||||
}
|
||||
uint32_t v32;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32);
|
||||
who = v32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 == strcmp("show", argv[0])) {
|
||||
if (0 == strcmp("show", CMD_ARGV[0])) {
|
||||
if (who == -1) {
|
||||
showall:
|
||||
showall:
|
||||
r = ERROR_OK;
|
||||
for (x = 0 ; x < pChip->details.n_gpnvms ; x++) {
|
||||
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v);
|
||||
if (r != ERROR_OK) {
|
||||
break;
|
||||
}
|
||||
command_print(cmd_ctx, "sam3-gpnvm%u: %u", x, v);
|
||||
command_print(CMD_CTX, "sam3-gpnvm%u: %u", x, v);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
|
||||
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
|
||||
command_print(cmd_ctx, "sam3-gpnvm%u: %u", who, v);
|
||||
command_print(CMD_CTX, "sam3-gpnvm%u: %u", who, v);
|
||||
return r;
|
||||
} else {
|
||||
command_print(cmd_ctx, "sam3-gpnvm invalid GPNVM: %u", who);
|
||||
command_print(CMD_CTX, "sam3-gpnvm invalid GPNVM: %u", who);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (who == -1) {
|
||||
command_print(cmd_ctx, "Missing GPNVM number");
|
||||
command_print(CMD_CTX, "Missing GPNVM number");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (0 == strcmp("set", argv[0])) {
|
||||
if (0 == strcmp("set", CMD_ARGV[0])) {
|
||||
r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who);
|
||||
} else if ((0 == strcmp("clr", argv[0])) ||
|
||||
(0 == strcmp("clear", argv[0]))) { // quietly accept both
|
||||
} else if ((0 == strcmp("clr", CMD_ARGV[0])) ||
|
||||
(0 == strcmp("clear", CMD_ARGV[0]))) { // quietly accept both
|
||||
r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who);
|
||||
} else {
|
||||
command_print(cmd_ctx, "Unkown command: %s", argv[0]);
|
||||
command_print(CMD_CTX, "Unkown command: %s", CMD_ARGV[0]);
|
||||
r = ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
sam3_handle_slowclk_command(struct command_context_s *cmd_ctx, char *cmd, char **argv, int argc)
|
||||
COMMAND_HANDLER(sam3_handle_slowclk_command)
|
||||
{
|
||||
uint32_t v;
|
||||
int r;
|
||||
|
||||
struct sam3_chip *pChip;
|
||||
|
||||
pChip = get_current_sam3(cmd_ctx);
|
||||
pChip = get_current_sam3(CMD_CTX);
|
||||
if (!pChip) {
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
switch (argc) {
|
||||
switch (CMD_ARGC) {
|
||||
case 0:
|
||||
// show
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
// set
|
||||
r = parse_u32(argv[0], &v);
|
||||
uint32_t v;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v);
|
||||
if (v > 200000) {
|
||||
// absurd slow clock of 200Khz?
|
||||
command_print(cmd_ctx,"Absurd/illegal slow clock freq: %d\n", (int)(v));
|
||||
command_print(CMD_CTX,"Absurd/illegal slow clock freq: %d\n", (int)(v));
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
pChip->cfg.slow_freq = v;
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
// error
|
||||
command_print(cmd_ctx,"Too many parameters");
|
||||
command_print(CMD_CTX,"Too many parameters");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
command_print(cmd_ctx, "Slowclk freq: %d.%03dkhz",
|
||||
command_print(CMD_CTX, "Slowclk freq: %d.%03dkhz",
|
||||
(int)(pChip->cfg.slow_freq/ 1000),
|
||||
(int)(pChip->cfg.slow_freq% 1000));
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
static int sam3_registered;
|
||||
static int
|
||||
sam3_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *pCmd;
|
||||
|
||||
// only register once
|
||||
if (!sam3_registered) {
|
||||
sam3_registered++;
|
||||
|
||||
pCmd = register_command(cmd_ctx, NULL, "at91sam3", NULL, COMMAND_ANY, NULL);
|
||||
register_command(cmd_ctx, pCmd,
|
||||
"gpnvm",
|
||||
sam3_handle_gpnvm_command,
|
||||
COMMAND_EXEC,
|
||||
"at91sam3 gpnvm [action [<BIT>], by default 'show', otherwise set | clear BIT");
|
||||
register_command(cmd_ctx, pCmd,
|
||||
"info",
|
||||
sam3_handle_info_command,
|
||||
COMMAND_EXEC,
|
||||
"at91sam3 info - print information about the current sam3 chip");
|
||||
register_command(cmd_ctx, pCmd,
|
||||
"slowclk",
|
||||
sam3_handle_slowclk_command,
|
||||
COMMAND_EXEC,
|
||||
"at91sam3 slowclk [VALUE] set the slowclock frequency (default 32768hz)");
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
flash_driver_t at91sam3_flash =
|
||||
{
|
||||
.name = "at91sam3",
|
||||
.register_commands = sam3_register_commands,
|
||||
|
||||
.flash_bank_command = sam3_flash_bank_command,
|
||||
.erase = sam3_erase,
|
||||
.protect = sam3_protect,
|
||||
.write = sam3_write,
|
||||
.probe = sam3_probe,
|
||||
.auto_probe = sam3_auto_probe,
|
||||
.erase_check = sam3_erase_check,
|
||||
.protect_check = sam3_protect_check,
|
||||
.info = sam3_info
|
||||
static const struct command_registration at91sam3_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "gpnvm",
|
||||
.handler = sam3_handle_gpnvm_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "[('clr'|'set'|'show') bitnum]",
|
||||
.help = "Without arguments, shows all bits in the gpnvm "
|
||||
"register. Otherwise, clears, sets, or shows one "
|
||||
"General Purpose Non-Volatile Memory (gpnvm) bit.",
|
||||
},
|
||||
{
|
||||
.name = "info",
|
||||
.handler = sam3_handle_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Print information about the current at91sam3 chip"
|
||||
"and its flash configuration.",
|
||||
},
|
||||
{
|
||||
.name = "slowclk",
|
||||
.handler = sam3_handle_slowclk_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "[clock_hz]",
|
||||
.help = "Display or set the slowclock frequency "
|
||||
"(default 32768 Hz).",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration at91sam3_command_handlers[] = {
|
||||
{
|
||||
.name = "at91sam3",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "at91sam3 flash command group",
|
||||
.chain = at91sam3_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver at91sam3_flash = {
|
||||
.name = "at91sam3",
|
||||
.commands = at91sam3_command_handlers,
|
||||
.flash_bank_command = sam3_flash_bank_command,
|
||||
.erase = sam3_erase,
|
||||
.protect = sam3_protect,
|
||||
.write = sam3_write,
|
||||
.probe = sam3_probe,
|
||||
.auto_probe = sam3_auto_probe,
|
||||
.erase_check = sam3_erase_check,
|
||||
.protect_check = sam3_protect_check,
|
||||
.info = sam3_info,
|
||||
};
|
||||
@@ -20,4 +20,4 @@
|
||||
|
||||
|
||||
// nothing to do here other then export this.
|
||||
extern flash_driver_t at91sam3_flash;
|
||||
extern struct flash_driver at91sam3_flash;
|
||||
@@ -49,41 +49,17 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "at91sam7.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
|
||||
static int at91sam7_protect_check(struct flash_bank *bank);
|
||||
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
|
||||
static int at91sam7_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int at91sam7_probe(struct flash_bank_s *bank);
|
||||
//static int at91sam7_auto_probe(struct flash_bank_s *bank);
|
||||
static int at91sam7_erase_check(struct flash_bank_s *bank);
|
||||
static int at91sam7_protect_check(struct flash_bank_s *bank);
|
||||
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number);
|
||||
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode);
|
||||
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
|
||||
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen);
|
||||
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t at91sam7_flash =
|
||||
{
|
||||
.name = "at91sam7",
|
||||
.register_commands = at91sam7_register_commands,
|
||||
.flash_bank_command = at91sam7_flash_bank_command,
|
||||
.erase = at91sam7_erase,
|
||||
.protect = at91sam7_protect,
|
||||
.write = at91sam7_write,
|
||||
.probe = at91sam7_probe,
|
||||
.auto_probe = at91sam7_probe,
|
||||
.erase_check = at91sam7_erase_check,
|
||||
.protect_check = at91sam7_protect_check,
|
||||
.info = at91sam7_info
|
||||
};
|
||||
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
|
||||
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
|
||||
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
|
||||
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen);
|
||||
|
||||
static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
|
||||
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
||||
@@ -112,16 +88,8 @@ static long SRAMSIZ[16] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static int at91sam7_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,
|
||||
"at91sam7 gpnvm <bit> set | clear, set or clear one gpnvm bit");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number)
|
||||
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
|
||||
{
|
||||
uint32_t fsr;
|
||||
target_read_u32(target, MC_FSR[bank_number], &fsr);
|
||||
@@ -130,10 +98,10 @@ static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number)
|
||||
}
|
||||
|
||||
/* Read clock configuration and set at91sam7_info->mck_freq */
|
||||
static void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
static void at91sam7_read_clock_info(struct flash_bank *bank)
|
||||
{
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t mckr, mcfr, pllr, mor;
|
||||
unsigned long tmp = 0, mainfreq;
|
||||
|
||||
@@ -209,11 +177,11 @@ static void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
}
|
||||
|
||||
/* Setup the timimg registers for nvbits or normal flash */
|
||||
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
|
||||
{
|
||||
uint32_t fmr, fmcn = 0, fws = 0;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
|
||||
if (mode && (mode != at91sam7_info->flashmode))
|
||||
{
|
||||
@@ -257,7 +225,7 @@ static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
at91sam7_info->flashmode = mode;
|
||||
}
|
||||
|
||||
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
|
||||
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
@@ -284,11 +252,11 @@ static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits,
|
||||
}
|
||||
|
||||
/* Send one command to the AT91SAM flash controller */
|
||||
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen)
|
||||
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen)
|
||||
{
|
||||
uint32_t fcr;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
|
||||
fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
|
||||
target_write_u32(target, MC_FCR[bank->bank_number], fcr);
|
||||
@@ -313,11 +281,11 @@ static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16
|
||||
}
|
||||
|
||||
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||
static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
static int at91sam7_read_part_info(struct flash_bank *bank)
|
||||
{
|
||||
flash_bank_t *t_bank = bank;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
target_t *target = t_bank->target;
|
||||
struct flash_bank *t_bank = bank;
|
||||
struct at91sam7_flash_bank *at91sam7_info;
|
||||
struct target *target = t_bank->target;
|
||||
|
||||
uint16_t bnk, sec;
|
||||
uint16_t arch;
|
||||
@@ -337,7 +305,7 @@ static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
if (at91sam7_info->cidr != 0)
|
||||
{
|
||||
/* flash already configured, update clock and check for protected sectors */
|
||||
flash_bank_t *fb = bank;
|
||||
struct flash_bank *fb = bank;
|
||||
t_bank = fb;
|
||||
|
||||
while (t_bank)
|
||||
@@ -369,7 +337,7 @@ static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
if (at91sam7_info->flash_autodetection == 0)
|
||||
{
|
||||
/* banks and sectors are already created, based on data from input file */
|
||||
flash_bank_t *fb = bank;
|
||||
struct flash_bank *fb = bank;
|
||||
t_bank = fb;
|
||||
while (t_bank)
|
||||
{
|
||||
@@ -565,10 +533,10 @@ static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
if (bnk > 0)
|
||||
{
|
||||
/* create a new flash bank element */
|
||||
flash_bank_t *fb = malloc(sizeof(flash_bank_t));
|
||||
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
||||
fb->target = target;
|
||||
fb->driver = &at91sam7_flash;
|
||||
fb->driver_priv = malloc(sizeof(at91sam7_flash_bank_t));
|
||||
fb->driver = bank->driver;
|
||||
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
||||
fb->next = NULL;
|
||||
|
||||
/* link created bank in 'flash_banks' list and redirect t_bank */
|
||||
@@ -584,7 +552,7 @@ static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
t_bank->num_sectors = sectors_num;
|
||||
|
||||
/* allocate sectors */
|
||||
t_bank->sectors = malloc(sectors_num * sizeof(flash_sector_t));
|
||||
t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
|
||||
for (sec = 0; sec < sectors_num; sec++)
|
||||
{
|
||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||
@@ -628,9 +596,9 @@ static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
static int at91sam7_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint16_t retval;
|
||||
uint32_t blank;
|
||||
uint16_t fast_check;
|
||||
@@ -694,12 +662,12 @@ static int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
static int at91sam7_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t lock_pos, gpnvm_pos;
|
||||
uint32_t status;
|
||||
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_info->cidr == 0)
|
||||
{
|
||||
@@ -744,15 +712,15 @@ static int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
||||
{
|
||||
flash_bank_t *t_bank = bank;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
target_t *target = t_bank->target;
|
||||
struct flash_bank *t_bank = bank;
|
||||
struct at91sam7_flash_bank *at91sam7_info;
|
||||
struct target *target = t_bank->target;
|
||||
|
||||
uint32_t base_address;
|
||||
uint32_t bank_size;
|
||||
uint32_t ext_freq;
|
||||
uint32_t ext_freq = 0;
|
||||
|
||||
int chip_width;
|
||||
int bus_width;
|
||||
@@ -767,7 +735,7 @@ static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
|
||||
int bnk, sec;
|
||||
|
||||
at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
|
||||
at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
|
||||
t_bank->driver_priv = at91sam7_info;
|
||||
|
||||
/* part wasn't probed for info yet */
|
||||
@@ -776,35 +744,39 @@ static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
at91sam7_info->ext_freq = 0;
|
||||
at91sam7_info->flash_autodetection = 0;
|
||||
|
||||
if (argc == 14)
|
||||
{
|
||||
ext_freq = atol(args[13]) * 1000;
|
||||
at91sam7_info->ext_freq = ext_freq;
|
||||
}
|
||||
|
||||
if ((argc != 14) ||
|
||||
(atoi(args[4]) == 0) || /* bus width */
|
||||
(atoi(args[8]) == 0) || /* banks number */
|
||||
(atoi(args[9]) == 0) || /* sectors per bank */
|
||||
(atoi(args[10]) == 0) || /* pages per sector */
|
||||
(atoi(args[11]) == 0) || /* page size */
|
||||
(atoi(args[12]) == 0)) /* nvmbits number */
|
||||
if (CMD_ARGC < 13)
|
||||
{
|
||||
at91sam7_info->flash_autodetection = 1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
base_address = strtoul(args[1], NULL, 0);
|
||||
chip_width = atoi(args[3]);
|
||||
bus_width = atoi(args[4]);
|
||||
banks_num = atoi(args[8]);
|
||||
num_sectors = atoi(args[9]);
|
||||
pages_per_sector = atoi(args[10]);
|
||||
page_size = atoi(args[11]);
|
||||
num_nvmbits = atoi(args[12]);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address);
|
||||
|
||||
target_name = calloc(strlen(args[7]) + 1, sizeof(char));
|
||||
strcpy(target_name, args[7]);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width);
|
||||
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors);
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector);
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size);
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits);
|
||||
|
||||
if (CMD_ARGC == 14) {
|
||||
unsigned long freq;
|
||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq);
|
||||
ext_freq = freq * 1000;
|
||||
at91sam7_info->ext_freq = ext_freq;
|
||||
}
|
||||
|
||||
if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
|
||||
(pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
|
||||
{
|
||||
at91sam7_info->flash_autodetection = 1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
target_name = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
|
||||
strcpy(target_name, CMD_ARGV[7]);
|
||||
|
||||
/* calculate bank size */
|
||||
bank_size = num_sectors * pages_per_sector * page_size;
|
||||
@@ -814,10 +786,10 @@ static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
if (bnk > 0)
|
||||
{
|
||||
/* create a new bank element */
|
||||
flash_bank_t *fb = malloc(sizeof(flash_bank_t));
|
||||
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
|
||||
fb->target = target;
|
||||
fb->driver = &at91sam7_flash;
|
||||
fb->driver_priv = malloc(sizeof(at91sam7_flash_bank_t));
|
||||
fb->driver = bank->driver;
|
||||
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
|
||||
fb->next = NULL;
|
||||
|
||||
/* link created bank in 'flash_banks' list and redirect t_bank */
|
||||
@@ -833,7 +805,7 @@ static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
t_bank->num_sectors = num_sectors;
|
||||
|
||||
/* allocate sectors */
|
||||
t_bank->sectors = malloc(num_sectors * sizeof(flash_sector_t));
|
||||
t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
|
||||
for (sec = 0; sec < num_sectors; sec++)
|
||||
{
|
||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||
@@ -856,9 +828,9 @@ static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int at91sam7_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
int sec;
|
||||
uint32_t nbytes, pos;
|
||||
uint8_t *buffer;
|
||||
@@ -924,13 +896,13 @@ static int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
uint32_t cmd;
|
||||
int sector;
|
||||
uint32_t pagen;
|
||||
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_info->cidr == 0)
|
||||
{
|
||||
@@ -974,11 +946,11 @@ static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int l
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t dst_min_alignment, wcount, bytes_remaining = count;
|
||||
uint32_t first_page, last_page, pagen, buffer_pos;
|
||||
|
||||
@@ -1008,7 +980,7 @@ static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t o
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
first_page = offset/dst_min_alignment;
|
||||
last_page = CEIL(offset + count, dst_min_alignment);
|
||||
last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
|
||||
|
||||
LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
|
||||
|
||||
@@ -1026,7 +998,7 @@ static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t o
|
||||
|
||||
/* Write one block to the PageWriteBuffer */
|
||||
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
||||
wcount = CEIL(count,4);
|
||||
wcount = DIV_ROUND_UP(count,4);
|
||||
if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -1043,7 +1015,7 @@ static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t o
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_probe(struct flash_bank_s *bank)
|
||||
static int at91sam7_probe(struct flash_bank *bank)
|
||||
{
|
||||
/* we can't probe on an at91sam7
|
||||
* if this is an at91sam7, it has the configured flash */
|
||||
@@ -1062,10 +1034,10 @@ static int at91sam7_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_info->cidr == 0)
|
||||
{
|
||||
@@ -1127,18 +1099,18 @@ static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
* The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes
|
||||
* Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
|
||||
*/
|
||||
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
struct flash_bank *bank;
|
||||
int bit;
|
||||
uint8_t flashcmd;
|
||||
uint32_t status;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
struct at91sam7_flash_bank *at91sam7_info;
|
||||
int retval;
|
||||
|
||||
if (argc != 2)
|
||||
if (CMD_ARGC != 2)
|
||||
{
|
||||
command_print(cmd_ctx, "at91sam7 gpnvm <bit> <set | clear>");
|
||||
command_print(CMD_CTX, "at91sam7 gpnvm <bit> <set | clear>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1147,9 +1119,9 @@ static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char
|
||||
{
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
if (bank->driver != &at91sam7_flash)
|
||||
if (strcmp(bank->driver->name, "at91sam7"))
|
||||
{
|
||||
command_print(cmd_ctx, "not an at91sam7 flash bank '%s'", args[0]);
|
||||
command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -1158,11 +1130,11 @@ static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (strcmp(args[1], "set") == 0)
|
||||
if (strcmp(CMD_ARGV[1], "set") == 0)
|
||||
{
|
||||
flashcmd = SGPB;
|
||||
}
|
||||
else if (strcmp(args[1], "clear") == 0)
|
||||
else if (strcmp(CMD_ARGV[1], "clear") == 0)
|
||||
{
|
||||
flashcmd = CGPB;
|
||||
}
|
||||
@@ -1181,10 +1153,10 @@ static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char
|
||||
}
|
||||
}
|
||||
|
||||
bit = atoi(args[0]);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
|
||||
if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits))
|
||||
{
|
||||
command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[0], at91sam7_info->target_name);
|
||||
command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1206,3 +1178,38 @@ static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration at91sam7_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "gpnvm",
|
||||
.handler = at91sam7_handle_gpnvm_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "set or clear one General Purpose Non-Volatile Memory "
|
||||
"(gpnvm) bit",
|
||||
.usage = "bitnum ('set'|'clear')",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration at91sam7_command_handlers[] = {
|
||||
{
|
||||
.name = "at91sam7",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "at91sam7 flash command group",
|
||||
.chain = at91sam7_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver at91sam7_flash = {
|
||||
.name = "at91sam7",
|
||||
.commands = at91sam7_command_handlers,
|
||||
.flash_bank_command = at91sam7_flash_bank_command,
|
||||
.erase = at91sam7_erase,
|
||||
.protect = at91sam7_protect,
|
||||
.write = at91sam7_write,
|
||||
.probe = at91sam7_probe,
|
||||
.auto_probe = at91sam7_probe,
|
||||
.erase_check = at91sam7_erase_check,
|
||||
.protect_check = at91sam7_protect_check,
|
||||
.info = at91sam7_info,
|
||||
};
|
||||
@@ -23,9 +23,7 @@
|
||||
#ifndef AT91SAM7_H
|
||||
#define AT91SAM7_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct at91sam7_flash_bank_s
|
||||
struct at91sam7_flash_bank
|
||||
{
|
||||
/* chip id register */
|
||||
uint32_t cidr;
|
||||
@@ -67,7 +65,7 @@ typedef struct at91sam7_flash_bank_s
|
||||
/* external clock frequency */
|
||||
uint32_t ext_freq;
|
||||
|
||||
} at91sam7_flash_bank_t;
|
||||
};
|
||||
|
||||
|
||||
/* AT91SAM7 control registers */
|
||||
@@ -21,9 +21,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "avrf.h"
|
||||
#include "avrt.h"
|
||||
#include "flash.h"
|
||||
#include <target/avrt.h>
|
||||
|
||||
|
||||
/* AVR_JTAG_Instructions */
|
||||
@@ -50,55 +50,27 @@
|
||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||
|
||||
avrf_type_t avft_chips_info[] =
|
||||
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},
|
||||
};
|
||||
|
||||
static int avrf_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int avrf_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int avrf_probe(struct flash_bank_s *bank);
|
||||
static int avrf_auto_probe(struct flash_bank_s *bank);
|
||||
//static int avrf_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int avrf_protect_check(struct flash_bank_s *bank);
|
||||
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out);
|
||||
int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len);
|
||||
|
||||
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
extern int avr_jtag_sendinstr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out);
|
||||
extern int avr_jtag_senddat(jtag_tap_t *tap, uint32_t *dr_in, uint32_t dr_out, int len);
|
||||
|
||||
extern int mcu_write_ir(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_execute_queue(void);
|
||||
|
||||
flash_driver_t avr_flash =
|
||||
{
|
||||
.name = "avr",
|
||||
.register_commands = avrf_register_commands,
|
||||
.flash_bank_command = avrf_flash_bank_command,
|
||||
.erase = avrf_erase,
|
||||
.protect = avrf_protect,
|
||||
.write = avrf_write,
|
||||
.probe = avrf_probe,
|
||||
.auto_probe = avrf_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = avrf_protect_check,
|
||||
.info = avrf_info
|
||||
};
|
||||
int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
|
||||
int mcu_write_dr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
|
||||
int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
|
||||
int mcu_write_dr_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
|
||||
int mcu_write_ir_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
|
||||
int mcu_write_dr_u16(struct jtag_tap *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
|
||||
int mcu_write_ir_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
|
||||
int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
|
||||
int mcu_execute_queue(void);
|
||||
|
||||
/* avr program functions */
|
||||
static int avr_jtag_reset(avr_common_t *avr, uint32_t reset)
|
||||
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);
|
||||
@@ -106,7 +78,7 @@ static int avr_jtag_reset(avr_common_t *avr, uint32_t reset)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtag_read_jtagid(avr_common_t *avr, uint32_t *id)
|
||||
static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len);
|
||||
@@ -114,7 +86,7 @@ static int avr_jtag_read_jtagid(avr_common_t *avr, uint32_t *id)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_enterprogmode(avr_common_t *avr)
|
||||
static int avr_jtagprg_enterprogmode(struct avr_common *avr)
|
||||
{
|
||||
avr_jtag_reset(avr, 1);
|
||||
|
||||
@@ -124,7 +96,7 @@ static int avr_jtagprg_enterprogmode(avr_common_t *avr)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_leaveprogmode(avr_common_t *avr)
|
||||
static int avr_jtagprg_leaveprogmode(struct avr_common *avr)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
@@ -138,7 +110,7 @@ static int avr_jtagprg_leaveprogmode(avr_common_t *avr)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_chiperase(avr_common_t *avr)
|
||||
static int avr_jtagprg_chiperase(struct avr_common *avr)
|
||||
{
|
||||
uint32_t poll_value;
|
||||
|
||||
@@ -161,7 +133,7 @@ static int avr_jtagprg_chiperase(avr_common_t *avr)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_writeflashpage(avr_common_t *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;
|
||||
|
||||
@@ -208,28 +180,17 @@ static int avr_jtagprg_writeflashpage(avr_common_t *avr, uint8_t *page_buf, uint
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* interface command */
|
||||
static int avrf_register_commands(struct command_context_s *cmd_ctx)
|
||||
FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
|
||||
{
|
||||
command_t *avr_cmd = register_command(cmd_ctx, NULL, "avr", NULL, COMMAND_ANY, "avr flash specific commands");
|
||||
struct avrf_flash_bank *avrf_info;
|
||||
|
||||
register_command(cmd_ctx, avr_cmd, "mass_erase", avrf_handle_mass_erase_command, COMMAND_EXEC,
|
||||
"mass erase device");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
avrf_flash_bank_t *avrf_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank avr configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
avrf_info = malloc(sizeof(avrf_flash_bank_t));
|
||||
avrf_info = malloc(sizeof(struct avrf_flash_bank));
|
||||
bank->driver_priv = avrf_info;
|
||||
|
||||
avrf_info->probed = 0;
|
||||
@@ -237,22 +198,22 @@ static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int avrf_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
uint32_t cur_size, cur_buffer_size, page_size;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -300,12 +261,12 @@ static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offse
|
||||
#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_s *bank)
|
||||
static int avrf_probe(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avrf_flash_bank_t *avrf_info = bank->driver_priv;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
avrf_type_t *avr_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
struct avrf_flash_bank *avrf_info = bank->driver_priv;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
struct avrf_type *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
@@ -329,7 +290,7 @@ static int avrf_probe(struct flash_bank_s *bank)
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
@@ -345,7 +306,7 @@ static int avrf_probe(struct flash_bank_s *bank)
|
||||
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(flash_sector_t) * 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++)
|
||||
{
|
||||
@@ -368,25 +329,25 @@ static int avrf_probe(struct flash_bank_s *bank)
|
||||
}
|
||||
}
|
||||
|
||||
static int avrf_auto_probe(struct flash_bank_s *bank)
|
||||
static int avrf_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
avrf_flash_bank_t *avrf_info = bank->driver_priv;
|
||||
struct avrf_flash_bank *avrf_info = bank->driver_priv;
|
||||
if (avrf_info->probed)
|
||||
return ERROR_OK;
|
||||
return avrf_probe(bank);
|
||||
}
|
||||
|
||||
static int avrf_protect_check(struct flash_bank_s *bank)
|
||||
static int avrf_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
avrf_type_t *avr_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
struct avrf_type *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
@@ -408,7 +369,7 @@ static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
@@ -433,10 +394,10 @@ static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
}
|
||||
}
|
||||
|
||||
static int avrf_mass_erase(struct flash_bank_s *bank)
|
||||
static int avrf_mass_erase(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -454,23 +415,20 @@ static int avrf_mass_erase(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(avrf_handle_mass_erase_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "avr mass_erase <bank>");
|
||||
command_print(CMD_CTX, "avr mass_erase <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -480,13 +438,46 @@ static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, cha
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "avr mass erase complete");
|
||||
command_print(CMD_CTX, "avr mass erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "avr mass erase failed");
|
||||
command_print(CMD_CTX, "avr mass erase failed");
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration avrf_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "mass_erase",
|
||||
.handler = avrf_handle_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "erase entire device",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration avrf_command_handlers[] = {
|
||||
{
|
||||
.name = "avrf",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "AVR flash command group",
|
||||
.chain = avrf_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver avr_flash = {
|
||||
.name = "avr",
|
||||
.commands = avrf_command_handlers,
|
||||
.flash_bank_command = avrf_flash_bank_command,
|
||||
.erase = avrf_erase,
|
||||
.protect = avrf_protect,
|
||||
.write = avrf_write,
|
||||
.probe = avrf_probe,
|
||||
.auto_probe = avrf_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = avrf_protect_check,
|
||||
.info = avrf_info,
|
||||
};
|
||||
@@ -20,9 +20,7 @@
|
||||
#ifndef AVRF_H
|
||||
#define AVRF_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct avrf_type_s
|
||||
struct avrf_type
|
||||
{
|
||||
char name[15];
|
||||
uint16_t chip_id;
|
||||
@@ -30,12 +28,12 @@ typedef struct avrf_type_s
|
||||
int flash_page_num;
|
||||
int eeprom_page_size;
|
||||
int eeprom_page_num;
|
||||
} avrf_type_t;
|
||||
};
|
||||
|
||||
typedef struct avrf_flash_bank_s
|
||||
struct avrf_flash_bank
|
||||
{
|
||||
int ppage_size;
|
||||
int probed;
|
||||
} avrf_flash_bank_t;
|
||||
};
|
||||
|
||||
#endif /* AVRF_H */
|
||||
@@ -23,58 +23,33 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "cfi.h"
|
||||
#include "non_cfi.h"
|
||||
#include "armv4_5.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <target/arm.h>
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
|
||||
|
||||
static int cfi_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int cfi_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int cfi_probe(struct flash_bank_s *bank);
|
||||
static int cfi_auto_probe(struct flash_bank_s *bank);
|
||||
static int cfi_protect_check(struct flash_bank_s *bank);
|
||||
static int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
//static int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
#define CFI_MAX_BUS_WIDTH 4
|
||||
#define CFI_MAX_CHIP_WIDTH 4
|
||||
|
||||
/* defines internal maximum size for code fragment in cfi_intel_write_block() */
|
||||
#define CFI_MAX_INTEL_CODESIZE 256
|
||||
|
||||
flash_driver_t cfi_flash =
|
||||
{
|
||||
.name = "cfi",
|
||||
.register_commands = cfi_register_commands,
|
||||
.flash_bank_command = cfi_flash_bank_command,
|
||||
.erase = cfi_erase,
|
||||
.protect = cfi_protect,
|
||||
.write = cfi_write,
|
||||
.probe = cfi_probe,
|
||||
.auto_probe = cfi_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = cfi_protect_check,
|
||||
.info = cfi_info
|
||||
};
|
||||
|
||||
static cfi_unlock_addresses_t cfi_unlock_addresses[] =
|
||||
static struct cfi_unlock_addresses cfi_unlock_addresses[] =
|
||||
{
|
||||
[CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa },
|
||||
[CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa },
|
||||
};
|
||||
|
||||
/* CFI fixups foward declarations */
|
||||
static void cfi_fixup_0002_erase_regions(flash_bank_t *flash, void *param);
|
||||
static void cfi_fixup_0002_unlock_addresses(flash_bank_t *flash, void *param);
|
||||
static void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *flash, void *param);
|
||||
static void cfi_fixup_0002_erase_regions(struct flash_bank *flash, void *param);
|
||||
static void cfi_fixup_0002_unlock_addresses(struct flash_bank *flash, void *param);
|
||||
static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *flash, void *param);
|
||||
|
||||
/* fixup after reading cmdset 0002 primary query table */
|
||||
static const cfi_fixup_t cfi_0002_fixups[] = {
|
||||
static const struct cfi_fixup cfi_0002_fixups[] = {
|
||||
{CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
|
||||
{CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
|
||||
{CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]},
|
||||
@@ -90,14 +65,14 @@ static const cfi_fixup_t cfi_0002_fixups[] = {
|
||||
};
|
||||
|
||||
/* fixup after reading cmdset 0001 primary query table */
|
||||
static const cfi_fixup_t cfi_0001_fixups[] = {
|
||||
static const struct cfi_fixup cfi_0001_fixups[] = {
|
||||
{0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static void cfi_fixup(flash_bank_t *bank, const cfi_fixup_t *fixups)
|
||||
static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
const cfi_fixup_t *f;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
const struct cfi_fixup *f;
|
||||
|
||||
for (f = fixups; f->fixup; f++)
|
||||
{
|
||||
@@ -109,10 +84,10 @@ static void cfi_fixup(flash_bank_t *bank, const cfi_fixup_t *fixups)
|
||||
}
|
||||
}
|
||||
|
||||
/* inline uint32_t flash_address(flash_bank_t *bank, int sector, uint32_t offset) */
|
||||
static __inline__ uint32_t flash_address(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
/* inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) */
|
||||
static __inline__ uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (cfi_info->x16_as_x8) offset *= 2;
|
||||
|
||||
@@ -131,7 +106,7 @@ static __inline__ uint32_t flash_address(flash_bank_t *bank, int sector, uint32_
|
||||
|
||||
}
|
||||
|
||||
static void cfi_command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -161,9 +136,9 @@ static void cfi_command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
* flash banks are expected to be made of similar chips
|
||||
* the query result should be the same for all
|
||||
*/
|
||||
static uint8_t cfi_query_u8(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
static uint8_t cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint8_t data[CFI_MAX_BUS_WIDTH];
|
||||
|
||||
target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
|
||||
@@ -178,9 +153,9 @@ static uint8_t cfi_query_u8(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
* in case of a bank made of multiple chips,
|
||||
* the individual values are ORed
|
||||
*/
|
||||
static uint8_t cfi_get_u8(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
static uint8_t cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint8_t data[CFI_MAX_BUS_WIDTH];
|
||||
int i;
|
||||
|
||||
@@ -203,10 +178,10 @@ static uint8_t cfi_get_u8(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t cfi_query_u16(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
static uint16_t cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
uint8_t data[CFI_MAX_BUS_WIDTH * 2];
|
||||
|
||||
if (cfi_info->x16_as_x8)
|
||||
@@ -225,10 +200,10 @@ static uint16_t cfi_query_u16(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
|
||||
}
|
||||
|
||||
static uint32_t cfi_query_u32(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
static uint32_t cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
uint8_t data[CFI_MAX_BUS_WIDTH * 4];
|
||||
|
||||
if (cfi_info->x16_as_x8)
|
||||
@@ -248,9 +223,9 @@ static uint32_t cfi_query_u32(flash_bank_t *bank, int sector, uint32_t offset)
|
||||
data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
|
||||
}
|
||||
|
||||
static void cfi_intel_clear_status_register(flash_bank_t *bank)
|
||||
static void cfi_intel_clear_status_register(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
@@ -263,7 +238,7 @@ static void cfi_intel_clear_status_register(flash_bank_t *bank)
|
||||
target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
|
||||
}
|
||||
|
||||
uint8_t cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
uint8_t cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
@@ -304,10 +279,10 @@ uint8_t cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
return status;
|
||||
}
|
||||
|
||||
int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
uint8_t status, oldstatus;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
oldstatus = cfi_get_u8(bank, 0, 0x0);
|
||||
|
||||
@@ -339,12 +314,12 @@ int cfi_spansion_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
return(ERROR_FLASH_BUSY);
|
||||
}
|
||||
|
||||
static int cfi_read_intel_pri_ext(flash_bank_t *bank)
|
||||
static int cfi_read_intel_pri_ext(struct flash_bank *bank)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t));
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_intel_pri_ext *pri_ext = malloc(sizeof(struct cfi_intel_pri_ext));
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
cfi_info->pri_ext = pri_ext;
|
||||
@@ -405,12 +380,12 @@ static int cfi_read_intel_pri_ext(flash_bank_t *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_read_spansion_pri_ext(flash_bank_t *bank)
|
||||
static int cfi_read_spansion_pri_ext(struct flash_bank *bank)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
cfi_info->pri_ext = pri_ext;
|
||||
@@ -470,13 +445,13 @@ static int cfi_read_spansion_pri_ext(flash_bank_t *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_read_atmel_pri_ext(flash_bank_t *bank)
|
||||
static int cfi_read_atmel_pri_ext(struct flash_bank *bank)
|
||||
{
|
||||
int retval;
|
||||
cfi_atmel_pri_ext_t atmel_pri_ext;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
|
||||
target_t *target = bank->target;
|
||||
struct cfi_atmel_pri_ext atmel_pri_ext;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
/* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion,
|
||||
@@ -484,7 +459,7 @@ static int cfi_read_atmel_pri_ext(flash_bank_t *bank)
|
||||
* We read the atmel table, and prepare a valid AMD/Spansion query table.
|
||||
*/
|
||||
|
||||
memset(pri_ext, 0, sizeof(cfi_spansion_pri_ext_t));
|
||||
memset(pri_ext, 0, sizeof(struct cfi_spansion_pri_ext));
|
||||
|
||||
cfi_info->pri_ext = pri_ext;
|
||||
|
||||
@@ -537,9 +512,9 @@ static int cfi_read_atmel_pri_ext(flash_bank_t *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_read_0002_pri_ext(flash_bank_t *bank)
|
||||
static int cfi_read_0002_pri_ext(struct flash_bank *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (cfi_info->manufacturer == CFI_MFR_ATMEL)
|
||||
{
|
||||
@@ -551,11 +526,11 @@ static int cfi_read_0002_pri_ext(flash_bank_t *bank)
|
||||
}
|
||||
}
|
||||
|
||||
static int cfi_spansion_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int cfi_spansion_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
|
||||
printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n");
|
||||
buf += printed;
|
||||
@@ -586,11 +561,11 @@ static int cfi_spansion_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
|
||||
printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
|
||||
buf += printed;
|
||||
@@ -615,40 +590,30 @@ static int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
/*command_t *cfi_cmd = */
|
||||
register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, "flash bank cfi <base> <size> <chip_width> <bus_width> <targetNum> [jedec_probe/x16_as_x8]");
|
||||
/*
|
||||
register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
|
||||
"print part id of cfi flash bank <num>");
|
||||
*/
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#> [options]
|
||||
*/
|
||||
static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info;
|
||||
int i;
|
||||
(void) cmd_ctx;
|
||||
(void) cmd;
|
||||
struct cfi_flash_bank *cfi_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank cfi configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if ((strtoul(args[4], NULL, 0) > CFI_MAX_CHIP_WIDTH)
|
||||
|| (strtoul(args[3], NULL, 0) > CFI_MAX_BUS_WIDTH))
|
||||
uint16_t chip_width, bus_width;
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], bus_width);
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[4], chip_width);
|
||||
|
||||
if ((chip_width > CFI_MAX_CHIP_WIDTH)
|
||||
|| (bus_width > CFI_MAX_BUS_WIDTH))
|
||||
{
|
||||
LOG_ERROR("chip and bus width have to specified in bytes");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
cfi_info = malloc(sizeof(cfi_flash_bank_t));
|
||||
cfi_info = malloc(sizeof(struct cfi_flash_bank));
|
||||
cfi_info->probed = 0;
|
||||
bank->driver_priv = cfi_info;
|
||||
|
||||
@@ -658,13 +623,13 @@ static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
cfi_info->jedec_probe = 0;
|
||||
cfi_info->not_cfi = 0;
|
||||
|
||||
for (i = 6; i < argc; i++)
|
||||
for (unsigned i = 6; i < CMD_ARGC; i++)
|
||||
{
|
||||
if (strcmp(args[i], "x16_as_x8") == 0)
|
||||
if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0)
|
||||
{
|
||||
cfi_info->x16_as_x8 = 1;
|
||||
}
|
||||
else if (strcmp(args[i], "jedec_probe") == 0)
|
||||
else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0)
|
||||
{
|
||||
cfi_info->jedec_probe = 1;
|
||||
}
|
||||
@@ -678,11 +643,11 @@ static int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int cfi_intel_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
int i;
|
||||
|
||||
@@ -722,12 +687,12 @@ static int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
|
||||
|
||||
}
|
||||
|
||||
static int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int cfi_spansion_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
int i;
|
||||
|
||||
@@ -788,9 +753,9 @@ static int cfi_spansion_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
|
||||
}
|
||||
|
||||
static int cfi_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int cfi_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -823,12 +788,12 @@ static int cfi_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
int retry = 0;
|
||||
int i;
|
||||
@@ -940,9 +905,9 @@ static int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int
|
||||
return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
|
||||
}
|
||||
|
||||
static int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -973,9 +938,9 @@ static int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
}
|
||||
|
||||
/* FIXME Replace this by a simple memcpy() - still unsure about sideeffects */
|
||||
static void cfi_add_byte(struct flash_bank_s *bank, uint8_t *word, uint8_t byte)
|
||||
static void cfi_add_byte(struct flash_bank *bank, uint8_t *word, uint8_t byte)
|
||||
{
|
||||
/* target_t *target = bank->target; */
|
||||
/* struct target *target = bank->target; */
|
||||
|
||||
int i;
|
||||
|
||||
@@ -1008,7 +973,7 @@ static void cfi_add_byte(struct flash_bank_s *bank, uint8_t *word, uint8_t byte)
|
||||
|
||||
/* Convert code image to target endian */
|
||||
/* FIXME create general block conversion fcts in target.c?) */
|
||||
static void cfi_fix_code_endian(target_t *target, uint8_t *dest, const uint32_t *src, uint32_t count)
|
||||
static void cfi_fix_code_endian(struct target *target, uint8_t *dest, const uint32_t *src, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i< count; i++)
|
||||
@@ -1019,9 +984,9 @@ static void cfi_fix_code_endian(target_t *target, uint8_t *dest, const uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t cfi_command_val(flash_bank_t *bank, uint8_t cmd)
|
||||
static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
uint8_t buf[CFI_MAX_BUS_WIDTH];
|
||||
cfi_command(bank, cmd, buf);
|
||||
@@ -1042,13 +1007,13 @@ static uint32_t cfi_command_val(flash_bank_t *bank, uint8_t cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t address, uint32_t count)
|
||||
static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
reg_param_t reg_params[7];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
working_area_t *source;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct reg_param reg_params[7];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
struct working_area *source;
|
||||
uint32_t buffer_size = 32768;
|
||||
uint32_t write_command_val, busy_pattern_val, error_pattern_val;
|
||||
|
||||
@@ -1120,9 +1085,9 @@ static int cfi_intel_write_block(struct flash_bank_s *bank, uint8_t *buffer, uin
|
||||
|
||||
cfi_intel_clear_status_register(bank);
|
||||
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
|
||||
/* If we are setting up the write_algorith, we need target_code_src */
|
||||
/* if not we only need target_code_size. */
|
||||
@@ -1286,14 +1251,14 @@ cleanup:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t address, uint32_t count)
|
||||
static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
reg_param_t reg_params[10];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
working_area_t *source;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
struct reg_param reg_params[10];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
struct working_area *source;
|
||||
uint32_t buffer_size = 32768;
|
||||
uint32_t status;
|
||||
int retval, retvaltemp;
|
||||
@@ -1443,9 +1408,9 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
0xeafffffe /* b 8204 <sp_8_done> */
|
||||
};
|
||||
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
|
||||
int target_code_size;
|
||||
const uint32_t *target_code_src;
|
||||
@@ -1585,11 +1550,11 @@ static int cfi_spansion_write_block(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static int cfi_intel_write_word(struct flash_bank_s *bank, uint8_t *word, uint32_t address)
|
||||
static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
cfi_intel_clear_status_register(bank);
|
||||
@@ -1619,11 +1584,11 @@ static int cfi_intel_write_word(struct flash_bank_s *bank, uint8_t *word, uint32
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_intel_write_words(struct flash_bank_s *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
/* Calculate buffer size and boundary mask */
|
||||
@@ -1712,12 +1677,12 @@ static int cfi_intel_write_words(struct flash_bank_s *bank, uint8_t *word, uint3
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_spansion_write_word(struct flash_bank_s *bank, uint8_t *word, uint32_t address)
|
||||
static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
|
||||
cfi_command(bank, 0xaa, command);
|
||||
@@ -1758,13 +1723,13 @@ static int cfi_spansion_write_word(struct flash_bank_s *bank, uint8_t *word, uin
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_spansion_write_words(struct flash_bank_s *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
|
||||
/* Calculate buffer size and boundary mask */
|
||||
uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width);
|
||||
@@ -1850,9 +1815,9 @@ static int cfi_spansion_write_words(struct flash_bank_s *bank, uint8_t *word, ui
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_write_word(struct flash_bank_s *bank, uint8_t *word, uint32_t address)
|
||||
static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
switch (cfi_info->pri_id)
|
||||
{
|
||||
@@ -1871,9 +1836,9 @@ static int cfi_write_word(struct flash_bank_s *bank, uint8_t *word, uint32_t add
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
static int cfi_write_words(struct flash_bank_s *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
static int cfi_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
switch (cfi_info->pri_id)
|
||||
{
|
||||
@@ -1892,10 +1857,10 @@ static int cfi_write_words(struct flash_bank_s *bank, uint8_t *word, uint32_t wo
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t address = bank->base + offset; /* address of first byte to be programmed */
|
||||
uint32_t write_p, copy_p;
|
||||
int align; /* number of unaligned bytes */
|
||||
@@ -2101,20 +2066,20 @@ int cfi_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint3
|
||||
return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
|
||||
}
|
||||
|
||||
static void cfi_fixup_atmel_reversed_erase_regions(flash_bank_t *bank, void *param)
|
||||
static void cfi_fixup_atmel_reversed_erase_regions(struct flash_bank *bank, void *param)
|
||||
{
|
||||
(void) param;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
|
||||
pri_ext->_reversed_geometry = 1;
|
||||
}
|
||||
|
||||
static void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param)
|
||||
static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param)
|
||||
{
|
||||
int i;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
(void) param;
|
||||
|
||||
if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3))
|
||||
@@ -2133,21 +2098,21 @@ static void cfi_fixup_0002_erase_regions(flash_bank_t *bank, void *param)
|
||||
}
|
||||
}
|
||||
|
||||
static void cfi_fixup_0002_unlock_addresses(flash_bank_t *bank, void *param)
|
||||
static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
cfi_unlock_addresses_t *unlock_addresses = param;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct cfi_unlock_addresses *unlock_addresses = param;
|
||||
|
||||
pri_ext->_unlock1 = unlock_addresses->unlock1;
|
||||
pri_ext->_unlock2 = unlock_addresses->unlock2;
|
||||
}
|
||||
|
||||
|
||||
static int cfi_query_string(struct flash_bank_s *bank, int address)
|
||||
static int cfi_query_string(struct flash_bank *bank, int address)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
int retval;
|
||||
uint8_t command[8];
|
||||
|
||||
@@ -2182,10 +2147,10 @@ static int cfi_query_string(struct flash_bank_s *bank, int address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_probe(struct flash_bank_s *bank)
|
||||
static int cfi_probe(struct flash_bank *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
int num_sectors = 0;
|
||||
int i;
|
||||
@@ -2417,7 +2382,7 @@ static int cfi_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* a device might have only one erase block, spanning the whole device */
|
||||
bank->num_sectors = 1;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t));
|
||||
bank->sectors = malloc(sizeof(struct flash_sector));
|
||||
|
||||
bank->sectors[sector].offset = 0x0;
|
||||
bank->sectors[sector].size = bank->size;
|
||||
@@ -2434,7 +2399,7 @@ static int cfi_probe(struct flash_bank_s *bank)
|
||||
}
|
||||
|
||||
bank->num_sectors = num_sectors;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
|
||||
|
||||
for (i = 0; i < cfi_info->num_erase_regions; i++)
|
||||
{
|
||||
@@ -2461,21 +2426,21 @@ static int cfi_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_auto_probe(struct flash_bank_s *bank)
|
||||
static int cfi_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
if (cfi_info->probed)
|
||||
return ERROR_OK;
|
||||
return cfi_probe(bank);
|
||||
}
|
||||
|
||||
|
||||
static int cfi_intel_protect_check(struct flash_bank_s *bank)
|
||||
static int cfi_intel_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[CFI_MAX_BUS_WIDTH];
|
||||
int i;
|
||||
|
||||
@@ -2503,12 +2468,12 @@ static int cfi_intel_protect_check(struct flash_bank_s *bank)
|
||||
return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
|
||||
}
|
||||
|
||||
static int cfi_spansion_protect_check(struct flash_bank_s *bank)
|
||||
static int cfi_spansion_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
int retval;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
cfi_spansion_pri_ext_t *pri_ext = cfi_info->pri_ext;
|
||||
target_t *target = bank->target;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
struct target *target = bank->target;
|
||||
uint8_t command[8];
|
||||
int i;
|
||||
|
||||
@@ -2544,9 +2509,9 @@ static int cfi_spansion_protect_check(struct flash_bank_s *bank)
|
||||
return target_write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
|
||||
}
|
||||
|
||||
static int cfi_protect_check(struct flash_bank_s *bank)
|
||||
static int cfi_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -2574,10 +2539,10 @@ static int cfi_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int cfi_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
|
||||
if (cfi_info->qry[0] == (char)-1)
|
||||
{
|
||||
@@ -2651,3 +2616,16 @@ static int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct flash_driver cfi_flash = {
|
||||
.name = "cfi",
|
||||
.flash_bank_command = cfi_flash_bank_command,
|
||||
.erase = cfi_erase,
|
||||
.protect = cfi_protect,
|
||||
.write = cfi_write,
|
||||
.probe = cfi_probe,
|
||||
.auto_probe = cfi_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = cfi_protect_check,
|
||||
.info = cfi_info,
|
||||
};
|
||||
@@ -20,14 +20,12 @@
|
||||
#ifndef CFI_H
|
||||
#define CFI_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
|
||||
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
|
||||
|
||||
typedef struct cfi_flash_bank_s
|
||||
struct cfi_flash_bank
|
||||
{
|
||||
working_area_t *write_algorithm;
|
||||
struct working_area *write_algorithm;
|
||||
|
||||
int x16_as_x8;
|
||||
int jedec_probe;
|
||||
@@ -70,13 +68,13 @@ typedef struct cfi_flash_bank_s
|
||||
|
||||
void *pri_ext;
|
||||
void *alt_ext;
|
||||
} cfi_flash_bank_t;
|
||||
};
|
||||
|
||||
/* Intel primary extended query table
|
||||
* as defined for the Advanced+ Boot Block Flash Memory (C3)
|
||||
* and used by the linux kernel cfi driver (as of 2.6.14)
|
||||
*/
|
||||
typedef struct cfi_intel_pri_ext_s
|
||||
struct cfi_intel_pri_ext
|
||||
{
|
||||
char pri[3];
|
||||
uint8_t major_version;
|
||||
@@ -91,12 +89,12 @@ typedef struct cfi_intel_pri_ext_s
|
||||
uint8_t fact_prot_reg_size;
|
||||
uint8_t user_prot_reg_size;
|
||||
uint8_t extra[0];
|
||||
} cfi_intel_pri_ext_t;
|
||||
};
|
||||
|
||||
/* Spansion primary extended query table as defined for and used by
|
||||
* the linux kernel cfi driver (as of 2.6.15)
|
||||
*/
|
||||
typedef struct cfi_spansion_pri_ext_s
|
||||
struct cfi_spansion_pri_ext
|
||||
{
|
||||
uint8_t pri[3];
|
||||
uint8_t major_version;
|
||||
@@ -115,12 +113,12 @@ typedef struct cfi_spansion_pri_ext_s
|
||||
int _reversed_geometry;
|
||||
uint32_t _unlock1;
|
||||
uint32_t _unlock2;
|
||||
} cfi_spansion_pri_ext_t;
|
||||
};
|
||||
|
||||
/* Atmel primary extended query table as defined for and used by
|
||||
* the linux kernel cfi driver (as of 2.6.20+)
|
||||
*/
|
||||
typedef struct cfi_atmel_pri_ext_s
|
||||
struct cfi_atmel_pri_ext
|
||||
{
|
||||
uint8_t pri[3];
|
||||
uint8_t major_version;
|
||||
@@ -129,26 +127,26 @@ typedef struct cfi_atmel_pri_ext_s
|
||||
uint8_t bottom_boot;
|
||||
uint8_t burst_mode;
|
||||
uint8_t page_mode;
|
||||
} cfi_atmel_pri_ext_t;
|
||||
};
|
||||
|
||||
enum {
|
||||
CFI_UNLOCK_555_2AA,
|
||||
CFI_UNLOCK_5555_2AAA,
|
||||
};
|
||||
|
||||
typedef struct cfi_unlock_addresses_s
|
||||
struct cfi_unlock_addresses
|
||||
{
|
||||
uint32_t unlock1;
|
||||
uint32_t unlock2;
|
||||
} cfi_unlock_addresses_t;
|
||||
};
|
||||
|
||||
typedef struct cfi_fixup_s
|
||||
struct cfi_fixup
|
||||
{
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
void (*fixup)(flash_bank_t *flash, void *param);
|
||||
void (*fixup)(struct flash_bank *flash, void *param);
|
||||
void *param;
|
||||
} cfi_fixup_t;
|
||||
};
|
||||
|
||||
#define CFI_MFR_AMD 0x0001
|
||||
#define CFI_MFR_FUJITSU 0x0004
|
||||
659
src/flash/nor/core.c
Normal file
659
src/flash/nor/core.c
Normal file
@@ -0,0 +1,659 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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 <flash/common.h>
|
||||
#include <flash/nor/core.h>
|
||||
#include <flash/nor/imp.h>
|
||||
#include <target/image.h>
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Upper level of NOR flash framework.
|
||||
* The lower level interfaces are to drivers. These upper level ones
|
||||
* primarily support access from Tcl scripts or from GDB.
|
||||
*/
|
||||
|
||||
struct flash_bank *flash_banks;
|
||||
|
||||
int flash_driver_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = bank->driver->erase(bank, first, last);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = bank->driver->protect(bank, set, first, last);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_driver_write(struct flash_bank *bank,
|
||||
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 " (%d)",
|
||||
bank->base, offset, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void flash_bank_add(struct flash_bank *bank)
|
||||
{
|
||||
/* put flash bank in linked list */
|
||||
unsigned bank_num = 0;
|
||||
if (flash_banks)
|
||||
{
|
||||
/* find last flash bank */
|
||||
struct flash_bank *p = flash_banks;
|
||||
while (NULL != p->next)
|
||||
{
|
||||
bank_num += 1;
|
||||
p = p->next;
|
||||
}
|
||||
p->next = bank;
|
||||
bank_num += 1;
|
||||
}
|
||||
else
|
||||
flash_banks = bank;
|
||||
|
||||
bank->bank_number = bank_num;
|
||||
}
|
||||
|
||||
struct flash_bank *flash_bank_list(void)
|
||||
{
|
||||
return flash_banks;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (i++ == num)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
LOG_ERROR("flash bank %d does not exist", num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int flash_get_bank_count(void)
|
||||
{
|
||||
struct flash_bank *p;
|
||||
int i = 0;
|
||||
for (p = flash_banks; p; p = p->next)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
struct flash_bank *get_flash_bank_by_name(const char *name)
|
||||
{
|
||||
unsigned requested = get_flash_name_index(name);
|
||||
unsigned found = 0;
|
||||
|
||||
struct flash_bank *bank;
|
||||
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))
|
||||
continue;
|
||||
if (++found < requested)
|
||||
continue;
|
||||
return bank;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct flash_bank *get_flash_bank_by_num(int num)
|
||||
{
|
||||
struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
|
||||
int retval;
|
||||
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
retval = p->driver->auto_probe(p);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("auto_probe failed %d\n", retval);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* lookup flash bank by address */
|
||||
struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
|
||||
{
|
||||
struct flash_bank *c;
|
||||
|
||||
/* cycle through bank list */
|
||||
for (c = flash_banks; c; c = c->next)
|
||||
{
|
||||
int retval;
|
||||
retval = c->driver->auto_probe(c);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("auto_probe failed %d\n", retval);
|
||||
return NULL;
|
||||
}
|
||||
/* check whether address belongs to this flash bank */
|
||||
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
|
||||
return c;
|
||||
}
|
||||
LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int default_flash_mem_blank_check(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
const int buffer_size = 1024;
|
||||
int i;
|
||||
uint32_t nBytes;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
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++)
|
||||
{
|
||||
uint32_t j;
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
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);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (nBytes = 0; nBytes < chunk; nBytes++)
|
||||
{
|
||||
if (buffer[nBytes] != 0xFF)
|
||||
{
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
free(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int default_flash_blank_check(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
int retval;
|
||||
int fast_check = 0;
|
||||
uint32_t blank;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
fast_check = 0;
|
||||
break;
|
||||
}
|
||||
if (blank == 0xFF)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
else
|
||||
bank->sectors[i].is_erased = 0;
|
||||
fast_check = 1;
|
||||
}
|
||||
|
||||
if (!fast_check)
|
||||
{
|
||||
LOG_USER("Running slow fallback erase check - add working memory");
|
||||
return default_flash_mem_blank_check(bank);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Manipulate given flash region, selecting the bank according to target
|
||||
* and address. Maps an address range to a set of sectors, and issues
|
||||
* the callback() on that set ... e.g. to erase or unprotect its members.
|
||||
*
|
||||
* (Note a current bad assumption: that protection operates on the same
|
||||
* size sectors as erase operations use.)
|
||||
*
|
||||
* The "pad_reason" parameter is a kind of boolean: when it's NULL, the
|
||||
* range must fit those sectors exactly. This is clearly safe; it can't
|
||||
* erase data which the caller said to leave alone, for example. If it's
|
||||
* non-NULL, rather than failing, extra data in the first and/or last
|
||||
* sectors will be added to the range, and that reason string is used when
|
||||
* warning about those additions.
|
||||
*/
|
||||
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))
|
||||
{
|
||||
struct flash_bank *c;
|
||||
uint32_t last_addr = addr + length; /* first address AFTER end */
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
int i;
|
||||
|
||||
if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */
|
||||
|
||||
if (c->size == 0 || c->num_sectors == 0)
|
||||
{
|
||||
LOG_ERROR("Bank is invalid");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
/* special case, erase whole bank when length is zero */
|
||||
if (addr != c->base)
|
||||
{
|
||||
LOG_ERROR("Whole bank access must start at beginning of bank.");
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
return callback(c, 0, c->num_sectors - 1);
|
||||
}
|
||||
|
||||
/* check whether it all fits in this bank */
|
||||
if (addr + length - 1 > c->base + c->size - 1)
|
||||
{
|
||||
LOG_ERROR("Flash access does not fit into bank.");
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
/** @todo: handle erasures that cross into adjacent banks */
|
||||
|
||||
addr -= c->base;
|
||||
last_addr -= c->base;
|
||||
|
||||
for (i = 0; i < c->num_sectors; i++)
|
||||
{
|
||||
struct flash_sector *f = c->sectors + i;
|
||||
uint32_t end = f->offset + f->size;
|
||||
|
||||
/* start only on a sector boundary */
|
||||
if (first < 0) {
|
||||
/* scanned past the first sector? */
|
||||
if (addr < f->offset)
|
||||
break;
|
||||
|
||||
/* is this the first sector? */
|
||||
if (addr == f->offset)
|
||||
first = i;
|
||||
|
||||
/* Does this need head-padding? If so, pad and warn;
|
||||
* or else force an error.
|
||||
*
|
||||
* Such padding can make trouble, since *WE* can't
|
||||
* ever know if that data was in use. The warning
|
||||
* should help users sort out messes later.
|
||||
*/
|
||||
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",
|
||||
pad_reason,
|
||||
(unsigned) f->offset,
|
||||
(unsigned) addr - 1);
|
||||
first = i;
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* is this (also?) the last sector? */
|
||||
if (last_addr == end) {
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Does this need tail-padding? If so, pad and warn;
|
||||
* or else force an error.
|
||||
*/
|
||||
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",
|
||||
pad_reason,
|
||||
(unsigned) last_addr,
|
||||
(unsigned) end - 1);
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
|
||||
/* MUST finish on a sector boundary */
|
||||
if (last_addr <= f->offset)
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
/* The NOR driver may trim this range down, based on what
|
||||
* sectors are already erased/unprotected. GDB currently
|
||||
* blocks such optimizations.
|
||||
*/
|
||||
return callback(c, first, last);
|
||||
}
|
||||
|
||||
int flash_erase_address_range(struct target *target,
|
||||
bool pad, uint32_t addr, uint32_t length)
|
||||
{
|
||||
return flash_iterate_address_range(target, pad ? "erase" : NULL,
|
||||
addr, length, &flash_driver_erase);
|
||||
}
|
||||
|
||||
static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
return flash_driver_protect(bank, 0, first, last);
|
||||
}
|
||||
|
||||
static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
|
||||
{
|
||||
/* By default, pad to sector boundaries ... the real issue here
|
||||
* is that our (only) caller *permanently* removes protection,
|
||||
* and doesn't restore it.
|
||||
*/
|
||||
return flash_iterate_address_range(target, "unprotect",
|
||||
addr, length, &flash_driver_unprotect);
|
||||
}
|
||||
|
||||
int flash_write_unlock(struct target *target, struct image *image,
|
||||
uint32_t *written, int erase, bool unlock)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
int section;
|
||||
uint32_t section_offset;
|
||||
struct flash_bank *c;
|
||||
int *padding;
|
||||
|
||||
/* REVISIT do_pad should perhaps just be another parameter.
|
||||
* GDB wouldn't ever need it, since it erases separately.
|
||||
* But "flash write_image" commands might want that option.
|
||||
*/
|
||||
bool do_pad = false;
|
||||
|
||||
section = 0;
|
||||
section_offset = 0;
|
||||
|
||||
if (written)
|
||||
*written = 0;
|
||||
|
||||
if (erase)
|
||||
{
|
||||
/* assume all sectors need erasing - stops any problems
|
||||
* when flash_write is called multiple times */
|
||||
|
||||
flash_set_dirty();
|
||||
}
|
||||
|
||||
/* allocate padding array */
|
||||
padding = calloc(image->num_sections, sizeof(*padding));
|
||||
|
||||
/* loop until we reach end of the image */
|
||||
while (section < image->num_sections)
|
||||
{
|
||||
uint32_t buffer_size;
|
||||
uint8_t *buffer;
|
||||
int section_first;
|
||||
int section_last;
|
||||
uint32_t run_address = image->sections[section].base_address + section_offset;
|
||||
uint32_t run_size = image->sections[section].size - section_offset;
|
||||
int pad_bytes = 0;
|
||||
|
||||
if (image->sections[section].size == 0)
|
||||
{
|
||||
LOG_WARNING("empty section %d", section);
|
||||
section++;
|
||||
section_offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the corresponding flash bank */
|
||||
if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
|
||||
{
|
||||
section++; /* and skip it */
|
||||
section_offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* collect consecutive sections which fall into the same bank */
|
||||
section_first = section;
|
||||
section_last = section;
|
||||
padding[section] = 0;
|
||||
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
||||
&& (section_last + 1 < image->num_sections))
|
||||
{
|
||||
if (image->sections[section_last + 1].base_address < (run_address + run_size))
|
||||
{
|
||||
LOG_DEBUG("section %d out of order "
|
||||
"(surprising, but supported)",
|
||||
section_last + 1);
|
||||
/* REVISIT this can break with autoerase ...
|
||||
* clobbering data after it's written.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME This needlessly touches sectors BETWEEN the
|
||||
* sections it's writing. Without auto erase, it just
|
||||
* writes ones. That WILL INVALIDATE data in cases
|
||||
* like Stellaris Tempest chips, corrupting internal
|
||||
* ECC codes; and at least FreeScale suggests issues
|
||||
* with that approach (in HC11 documentation).
|
||||
*
|
||||
* With auto erase enabled, data in those sectors will
|
||||
* be needlessly destroyed; and some of the limited
|
||||
* number of flash erase cycles will be wasted...
|
||||
*
|
||||
* In both cases, the extra writes slow things down.
|
||||
*/
|
||||
|
||||
/* if we have multiple sections within our image,
|
||||
* flash programming could fail due to alignment issues
|
||||
* attempt to rebuild a consecutive buffer for the flash loader */
|
||||
pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size);
|
||||
if ((run_address + run_size + pad_bytes) > (c->base + c->size))
|
||||
break;
|
||||
padding[section_last] = pad_bytes;
|
||||
run_size += image->sections[++section_last].size;
|
||||
run_size += pad_bytes;
|
||||
|
||||
LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
|
||||
}
|
||||
|
||||
/* fit the run into bank constraints */
|
||||
if (run_address + run_size - 1 > c->base + c->size - 1)
|
||||
{
|
||||
/* REVISIT isn't this superfluous, given the while()
|
||||
* loop conditions above??
|
||||
*/
|
||||
LOG_WARNING("writing %d bytes only - as image section is %d bytes and bank is only %d bytes", \
|
||||
(int)(c->base + c->size - run_address), (int)(run_size), (int)(c->size));
|
||||
run_size = c->base + c->size - run_address;
|
||||
}
|
||||
|
||||
/* If we're applying any sector automagic, then pad this
|
||||
* (maybe-combined) segment to the end of its last sector.
|
||||
*/
|
||||
if (unlock || erase) {
|
||||
int sector;
|
||||
uint32_t offset_start = run_address - c->base;
|
||||
uint32_t offset_end = offset_start + run_size;
|
||||
uint32_t end = offset_end, delta;
|
||||
|
||||
for (sector = 0; sector < c->num_sectors; sector++) {
|
||||
end = c->sectors[sector].offset
|
||||
+ c->sectors[sector].size;
|
||||
if (offset_end <= end)
|
||||
break;
|
||||
}
|
||||
|
||||
delta = end - offset_end;
|
||||
padding[section_last] += delta;
|
||||
run_size += delta;
|
||||
}
|
||||
|
||||
/* allocate buffer */
|
||||
buffer = malloc(run_size);
|
||||
buffer_size = 0;
|
||||
|
||||
/* read sections to the buffer */
|
||||
while (buffer_size < run_size)
|
||||
{
|
||||
size_t size_read;
|
||||
|
||||
size_read = run_size - buffer_size;
|
||||
if (size_read > image->sections[section].size - section_offset)
|
||||
size_read = image->sections[section].size - section_offset;
|
||||
|
||||
if ((retval = image_read_section(image, section, section_offset,
|
||||
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
|
||||
{
|
||||
free(buffer);
|
||||
free(padding);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* see if we need to pad the section */
|
||||
while (padding[section]--)
|
||||
(buffer + buffer_size)[size_read++] = 0xff;
|
||||
|
||||
buffer_size += size_read;
|
||||
section_offset += size_read;
|
||||
|
||||
if (section_offset >= image->sections[section].size)
|
||||
{
|
||||
section++;
|
||||
section_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ERROR_OK;
|
||||
|
||||
if (unlock)
|
||||
{
|
||||
retval = flash_unlock_address_range(target, run_address, run_size);
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if (erase)
|
||||
{
|
||||
/* calculate and erase sectors */
|
||||
retval = flash_erase_address_range(target,
|
||||
do_pad, run_address, run_size);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
free(padding);
|
||||
return retval; /* abort operation */
|
||||
}
|
||||
|
||||
if (written != NULL)
|
||||
*written += run_size; /* add run size to total written counter */
|
||||
}
|
||||
|
||||
free(padding);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_write(struct target *target, struct image *image,
|
||||
uint32_t *written, int erase)
|
||||
{
|
||||
return flash_write_unlock(target, image, written, erase, false);
|
||||
}
|
||||
187
src/flash/nor/core.h
Normal file
187
src/flash/nor/core.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_NOR_CORE_H
|
||||
#define FLASH_NOR_CORE_H
|
||||
|
||||
#include <flash/common.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Upper level NOR flash interfaces.
|
||||
*/
|
||||
|
||||
struct image;
|
||||
|
||||
#define FLASH_MAX_ERROR_STR (128)
|
||||
|
||||
/**
|
||||
* Describes the geometry and status of a single flash sector
|
||||
* 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).
|
||||
uint32_t offset;
|
||||
/// Number of bytes in this flash sector.
|
||||
uint32_t size;
|
||||
/**
|
||||
* Indication of erasure status: 0 = not erased, 1 = erased,
|
||||
* other = unknown. Set by @c flash_driver_s::erase_check.
|
||||
*/
|
||||
int is_erased;
|
||||
/**
|
||||
* Indication of protection status: 0 = unprotected/unlocked,
|
||||
* 1 = protected/locked, other = unknown. Set by
|
||||
* @c flash_driver_s::protect_check.
|
||||
*/
|
||||
int is_protected;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides details of a flash bank, available either on-chip or through
|
||||
* a major interface.
|
||||
*
|
||||
* This structure will be passed as a parameter to the callbacks in the
|
||||
* flash_driver_s structure, some of which may modify the contents of
|
||||
* this structure of the area of flash that it defines. Driver writers
|
||||
* may use the @c driver_priv member to store additional data on a
|
||||
* per-bank basis, if required.
|
||||
*/
|
||||
struct flash_bank
|
||||
{
|
||||
char *name;
|
||||
|
||||
struct target *target; /**< Target to which this bank belongs. */
|
||||
|
||||
struct flash_driver *driver; /**< Driver for this bank. */
|
||||
void *driver_priv; /**< Private driver storage pointer */
|
||||
|
||||
int bank_number; /**< The 'bank' (or chip number) of this instance. */
|
||||
uint32_t base; /**< The base address of this bank */
|
||||
uint32_t size; /**< The size of this chip bank, in bytes */
|
||||
|
||||
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
|
||||
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
|
||||
|
||||
/**
|
||||
* The number of sectors on this chip. This value will
|
||||
* be set intially to 0, and the flash driver must set this to
|
||||
* some non-zero value during "probe()" or "auto_probe()".
|
||||
*/
|
||||
int num_sectors;
|
||||
/// 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
|
||||
int flash_register_commands(struct command_context *cmd_ctx);
|
||||
/// Initializes the 'flash' subsystem drivers
|
||||
int flash_init_drivers(struct command_context *cmd_ctx);
|
||||
|
||||
/**
|
||||
* Erases @a length bytes in the @a target flash, starting at @a addr.
|
||||
* The range @a addr to @a addr + @a length - 1 must be strictly
|
||||
* sector aligned, unless @a pad is true. Setting @a pad true extends
|
||||
* the range, at beginning and/or end, if needed for sector alignment.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int flash_erase_address_range(struct target *target,
|
||||
bool pad, uint32_t addr, uint32_t length);
|
||||
|
||||
/**
|
||||
* Writes @a image into the @a target flash. The @a written parameter
|
||||
* will contain the
|
||||
* @param target The target with the flash to be programmed.
|
||||
* @param image The image that will be programmed to flash.
|
||||
* @param written On return, contains the number of bytes written.
|
||||
* @param erase If non-zero, indicates the flash driver should first
|
||||
* erase the corresponding banks or sectors before programming.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int flash_write(struct target *target,
|
||||
struct image *image, uint32_t *written, int erase);
|
||||
/**
|
||||
* Forces targets to re-examine their erase/protection state.
|
||||
* 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.
|
||||
int flash_get_bank_count(void);
|
||||
/**
|
||||
* Provides default erased-bank check handling. Checks to see if
|
||||
* the flash driver knows they are erased; if things look uncertain,
|
||||
* this routine will call default_flash_mem_blank_check() to confirm.
|
||||
* @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
|
||||
* driver name and a suffix (option) specify the driver-specific
|
||||
* bank number. The suffix consists of the '.' and the driver-specific
|
||||
* bank number: when two str9x banks are defined, then 'str9x.1' refers
|
||||
* to the second.
|
||||
*/
|
||||
struct flash_bank *get_flash_bank_by_name(const char *name);
|
||||
/**
|
||||
* Returns a flash bank by the specified flash_bank_s bank_number, @a num.
|
||||
* @param num The flash bank number.
|
||||
* @returns A struct flash_bank for flash bank @a num, or NULL
|
||||
*/
|
||||
struct flash_bank *get_flash_bank_by_num(int num);
|
||||
/**
|
||||
* Retreives @a bank from a command argument, reporting errors parsing
|
||||
* the bank identifier or retreiving the specified bank. The bank
|
||||
* may be identified by its bank number or by @c name.instance, where
|
||||
* @a instance is driver-specific.
|
||||
* @param name_index The index to the string in args containing the
|
||||
* bank identifier.
|
||||
* @param bank On output, contians a pointer to the bank or NULL.
|
||||
* @returns ERROR_OK on success, or an error indicating the problem.
|
||||
*/
|
||||
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
|
||||
struct flash_bank **bank);
|
||||
/**
|
||||
* Returns the flash bank like get_flash_bank_by_num(), without probing.
|
||||
* @param num The flash bank number.
|
||||
* @returns A struct flash_bank for flash bank @a num, or NULL.
|
||||
*/
|
||||
struct flash_bank *get_flash_bank_by_num_noprobe(int num);
|
||||
/**
|
||||
* Returns the flash bank located at a specified address.
|
||||
* @param target The target, presumed to contain one or more banks.
|
||||
* @param addr An address that is within the range of the bank.
|
||||
* @returns The struct flash_bank located at @a addr, or NULL.
|
||||
*/
|
||||
struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr);
|
||||
|
||||
#endif // FLASH_NOR_CORE_H
|
||||
201
src/flash/nor/driver.h
Normal file
201
src/flash/nor/driver.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_NOR_DRIVER_H
|
||||
#define FLASH_NOR_DRIVER_H
|
||||
|
||||
struct flash_bank;
|
||||
|
||||
#define __FLASH_BANK_COMMAND(name) \
|
||||
COMMAND_HELPER(name, struct flash_bank *bank)
|
||||
|
||||
/**
|
||||
* @brief Provides the implementation-independent structure that defines
|
||||
* all of the callbacks required by OpenOCD flash drivers.
|
||||
*
|
||||
* Driver authors must implement the routines defined here, providing an
|
||||
* instance with the fields filled out. After that, the instance must
|
||||
* be registered in flash.c, so it can be used by the driver lookup system.
|
||||
*
|
||||
* Specifically, the user can issue the command: @par
|
||||
* @code
|
||||
* flash bank DRIVERNAME ...parameters...
|
||||
* @endcode
|
||||
*
|
||||
* OpenOCD will search for the driver with a @c flash_driver_s::name
|
||||
* that matches @c DRIVERNAME.
|
||||
*
|
||||
* The flash subsystem calls some of the other drivers routines a using
|
||||
* corresponding static <code>flash_driver_<i>callback</i>()</code>
|
||||
* routine in flash.c.
|
||||
*/
|
||||
struct flash_driver
|
||||
{
|
||||
/**
|
||||
* Gives a human-readable name of this flash driver,
|
||||
* This field is used to select and initialize the driver.
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* An array of driver-specific commands to register. When called
|
||||
* during the "flash bank" command, the driver can register addition
|
||||
* commands to support new flash chip functions.
|
||||
*/
|
||||
const struct command_registration *commands;
|
||||
|
||||
/**
|
||||
* Finish the "flash bank" command for @a bank. The
|
||||
* @a bank parameter will have been filled in by the core flash
|
||||
* layer when this routine is called, and the driver can store
|
||||
* additional information in its struct flash_bank::driver_priv field.
|
||||
*
|
||||
* The CMD_ARGV are: @par
|
||||
* @code
|
||||
* CMD_ARGV[0] = bank
|
||||
* CMD_ARGV[1] = drivername {name above}
|
||||
* CMD_ARGV[2] = baseaddress
|
||||
* CMD_ARGV[3] = lengthbytes
|
||||
* CMD_ARGV[4] = chip_width_in bytes
|
||||
* CMD_ARGV[5] = bus_width_bytes
|
||||
* CMD_ARGV[6] = driver-specific parameters
|
||||
* @endcode
|
||||
*
|
||||
* For example, CMD_ARGV[4] = 16 bit flash, CMD_ARGV[5] = 32bit bus.
|
||||
*
|
||||
* If extra arguments are provided (@a CMD_ARGC > 6), they will
|
||||
* start in @a CMD_ARGV[6]. These can be used to implement
|
||||
* driver-specific extensions.
|
||||
*
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
__FLASH_BANK_COMMAND((*flash_bank_command));
|
||||
|
||||
/**
|
||||
* Bank/sector erase routine (target-specific). When
|
||||
* called, the flash driver should erase the specified sectors
|
||||
* using whatever means are at its disposal.
|
||||
*
|
||||
* @param bank The bank of flash to be erased.
|
||||
* @param first The number of the first sector to erase, typically 0.
|
||||
* @param last The number of the last sector to erase, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase)(struct flash_bank *bank, int first, int last);
|
||||
|
||||
/**
|
||||
* Bank/sector protection routine (target-specific).
|
||||
* When called, the driver should disable 'flash write' bits (or
|
||||
* enable 'erase protection' bits) for the given @a bank and @a
|
||||
* sectors.
|
||||
*
|
||||
* @param bank The bank to protect or unprotect.
|
||||
* @param set If non-zero, enable protection; if 0, disable it.
|
||||
* @param first The first sector to (un)protect, typicaly 0.
|
||||
* @param last The last sector to (un)project, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect)(struct flash_bank *bank, int set, int first, int last);
|
||||
|
||||
/**
|
||||
* Program data into the flash. Note CPU address will be
|
||||
* "bank->base + offset", while the physical address is
|
||||
* dependent upon current target MMU mappings.
|
||||
*
|
||||
* @param bank The bank to program
|
||||
* @param buffer The data bytes to write.
|
||||
* @param offset The offset into the chip to program.
|
||||
* @param count The number of bytes to write.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*write)(struct flash_bank *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
|
||||
/**
|
||||
* Probe to determine what kind of flash is present.
|
||||
* This is invoked by the "probe" script command.
|
||||
*
|
||||
* @param bank The bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*probe)(struct flash_bank *bank);
|
||||
|
||||
/**
|
||||
* Check the erasure status of a flash bank.
|
||||
* When called, the driver routine must perform the required
|
||||
* checks and then set the @c flash_sector_s::is_erased field
|
||||
* for each of the flash banks's sectors.
|
||||
*
|
||||
* @param bank The bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase_check)(struct flash_bank *bank);
|
||||
|
||||
/**
|
||||
* Determine if the specific bank is "protected" or not.
|
||||
* When called, the driver routine must must perform the
|
||||
* required protection check(s) and then set the @c
|
||||
* flash_sector_s::is_protected field for each of the flash
|
||||
* bank's sectors.
|
||||
*
|
||||
* @param bank - the bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect_check)(struct flash_bank *bank);
|
||||
|
||||
/**
|
||||
* Display human-readable information about the flash
|
||||
* bank into the given buffer. Drivers must be careful to avoid
|
||||
* overflowing the buffer.
|
||||
*
|
||||
* @param bank - the bank to get info about
|
||||
* @param char - where to put the text for the human to read
|
||||
* @param buf_size - the size of the human buffer.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*info)(struct flash_bank *bank, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* driver probably should not perform its probe a second time.
|
||||
*
|
||||
* This callback is often called from the inside of other
|
||||
* routines (e.g. GDB flash downloads) to autoprobe the flash as
|
||||
* it is programing the flash.
|
||||
*
|
||||
* @param bank - the bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*auto_probe)(struct flash_bank *bank);
|
||||
};
|
||||
|
||||
#define FLASH_BANK_COMMAND_HANDLER(name) static __FLASH_BANK_COMMAND(name)
|
||||
|
||||
/**
|
||||
* Find a NOR flash driver by its name.
|
||||
* @param name The name of the requested driver.
|
||||
* @returns The flash_driver called @c name, or NULL if not found.
|
||||
*/
|
||||
struct flash_driver *flash_driver_find_by_name(const char *name);
|
||||
|
||||
#endif // FLASH_NOR_DRIVER_H
|
||||
77
src/flash/nor/drivers.c
Normal file
77
src/flash/nor/drivers.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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"
|
||||
|
||||
extern struct flash_driver lpc2000_flash;
|
||||
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 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 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;
|
||||
extern struct flash_driver faux_flash;
|
||||
|
||||
/**
|
||||
* The list of built-in flash drivers.
|
||||
* @todo Make this dynamically extendable with loadable modules.
|
||||
*/
|
||||
struct flash_driver *flash_drivers[] = {
|
||||
&lpc2000_flash,
|
||||
&lpc288x_flash,
|
||||
&lpc2900_flash,
|
||||
&cfi_flash,
|
||||
&at91sam7_flash,
|
||||
&at91sam3_flash,
|
||||
&str7x_flash,
|
||||
&str9x_flash,
|
||||
&aduc702x_flash,
|
||||
&stellaris_flash,
|
||||
&str9xpec_flash,
|
||||
&stm32x_flash,
|
||||
&tms470_flash,
|
||||
&ecosflash_flash,
|
||||
&ocl_flash,
|
||||
&pic32mx_flash,
|
||||
&avr_flash,
|
||||
&faux_flash,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct flash_driver *flash_driver_find_by_name(const char *name)
|
||||
{
|
||||
for (unsigned i = 0; flash_drivers[i]; i++)
|
||||
{
|
||||
if (strcmp(name, flash_drivers[i]->name) == 0)
|
||||
return flash_drivers[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -21,50 +21,27 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "flash.h"
|
||||
#include "embeddedice.h"
|
||||
#include "image.h"
|
||||
#include "imp.h"
|
||||
#include <target/embeddedice.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/image.h>
|
||||
|
||||
|
||||
static int ecosflash_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int ecosflash_probe(struct flash_bank_s *bank);
|
||||
static int ecosflash_protect_check(struct flash_bank_s *bank);
|
||||
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
#if 0
|
||||
static uint32_t ecosflash_get_flash_status(flash_bank_t *bank);
|
||||
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);
|
||||
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
|
||||
static int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
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
|
||||
|
||||
flash_driver_t ecosflash_flash =
|
||||
struct ecosflash_flash_bank
|
||||
{
|
||||
.name = "ecosflash",
|
||||
.register_commands = ecosflash_register_commands,
|
||||
.flash_bank_command = ecosflash_flash_bank_command,
|
||||
.erase = ecosflash_erase,
|
||||
.protect = ecosflash_protect,
|
||||
.write = ecosflash_write,
|
||||
.probe = ecosflash_probe,
|
||||
.auto_probe = ecosflash_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = ecosflash_protect_check,
|
||||
.info = ecosflash_info
|
||||
};
|
||||
|
||||
typedef struct ecosflash_flash_bank_s
|
||||
{
|
||||
struct target_s *target;
|
||||
working_area_t *write_algorithm;
|
||||
working_area_t *erase_check_algorithm;
|
||||
struct target *target;
|
||||
struct working_area *write_algorithm;
|
||||
struct working_area *erase_check_algorithm;
|
||||
char *driverPath;
|
||||
uint32_t start_address;
|
||||
} ecosflash_flash_bank_t;
|
||||
};
|
||||
|
||||
static const int sectorSize = 0x10000;
|
||||
|
||||
@@ -128,24 +105,24 @@ flash_errmsg(int err)
|
||||
|
||||
/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
|
||||
*/
|
||||
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
|
||||
{
|
||||
ecosflash_flash_bank_t *info;
|
||||
struct ecosflash_flash_bank *info;
|
||||
|
||||
if (argc < 7)
|
||||
if (CMD_ARGC < 7)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank ecosflash configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
info = malloc(sizeof(ecosflash_flash_bank_t));
|
||||
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(args[6]);
|
||||
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
|
||||
@@ -154,7 +131,7 @@ static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char
|
||||
int i = 0;
|
||||
uint32_t offset = 0;
|
||||
bank->num_sectors = bank->size/sectorSize;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
@@ -164,24 +141,24 @@ static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
info->target = get_target(args[5]);
|
||||
info->target = get_target(CMD_ARGV[5]);
|
||||
if (info->target == NULL)
|
||||
{
|
||||
LOG_ERROR("target '%s' not defined", args[5]);
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int loadDriver(ecosflash_flash_bank_t *info)
|
||||
static int loadDriver(struct ecosflash_flash_bank *info)
|
||||
{
|
||||
uint32_t buf_cnt;
|
||||
uint32_t image_size;
|
||||
image_t image;
|
||||
size_t buf_cnt;
|
||||
size_t image_size;
|
||||
struct image image;
|
||||
|
||||
image.base_address_set = 0;
|
||||
image.start_address_set = 0;
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
int retval;
|
||||
|
||||
if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
|
||||
@@ -205,7 +182,8 @@ static int loadDriver(ecosflash_flash_bank_t *info)
|
||||
}
|
||||
target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
|
||||
image_size += buf_cnt;
|
||||
LOG_DEBUG("%" PRIu32 " byte written at address 0x%8.8" PRIx32 "", buf_cnt, image.sections[i].base_address);
|
||||
LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "",
|
||||
buf_cnt, image.sections[i].base_address);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
@@ -222,19 +200,19 @@ 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(ecosflash_flash_bank_t *info,
|
||||
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)
|
||||
{
|
||||
target_t *target = info->target;
|
||||
struct target *target = info->target;
|
||||
|
||||
reg_param_t reg_params[3];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
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);
|
||||
@@ -263,7 +241,7 @@ static int runCode(ecosflash_flash_bank_t *info,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int eCosBoard_erase(ecosflash_flash_bank_t *info, uint32_t address, uint32_t len)
|
||||
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*/
|
||||
@@ -294,9 +272,9 @@ static int eCosBoard_erase(ecosflash_flash_bank_t *info, uint32_t address, uint3
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, uint32_t address, uint32_t len)
|
||||
static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32_t address, uint32_t len)
|
||||
{
|
||||
target_t *target = info->target;
|
||||
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*/
|
||||
@@ -353,22 +331,15 @@ static int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, uint32_t ad
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ecosflash_probe(struct flash_bank_s *bank)
|
||||
static int ecosflash_probe(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ecosflash_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
struct ecosflash_flash_bank *info = bank->driver_priv;
|
||||
int i;
|
||||
|
||||
if (info->target->endianness == TARGET_LITTLE_ENDIAN)
|
||||
@@ -389,7 +360,7 @@ static void command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static uint32_t ecosflash_address(struct flash_bank_s *bank, uint32_t address)
|
||||
static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
|
||||
{
|
||||
uint32_t retval = 0;
|
||||
switch (bank->bus_width)
|
||||
@@ -406,55 +377,68 @@ static uint32_t ecosflash_address(struct flash_bank_s *bank, uint32_t address)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int ecosflash_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct flash_bank_s *c = bank;
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
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_s *bank, int set, int first, int last)
|
||||
static int ecosflash_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int ecosflash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
struct flash_bank_s *c = bank;
|
||||
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_s *bank)
|
||||
static int ecosflash_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int ecosflash_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
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(flash_bank_t *bank)
|
||||
static uint32_t ecosflash_get_flash_status(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)
|
||||
static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
|
||||
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_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
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,
|
||||
.probe = ecosflash_probe,
|
||||
.auto_probe = ecosflash_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = ecosflash_protect_check,
|
||||
.info = ecosflash_info
|
||||
};
|
||||
@@ -21,57 +21,34 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "flash.h"
|
||||
#include "image.h"
|
||||
#include "imp.h"
|
||||
#include <target/image.h>
|
||||
#include "hello.h"
|
||||
|
||||
|
||||
static int faux_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int faux_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int faux_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int faux_probe(struct flash_bank_s *bank);
|
||||
static int faux_protect_check(struct flash_bank_s *bank);
|
||||
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
flash_driver_t faux_flash =
|
||||
struct faux_flash_bank
|
||||
{
|
||||
.name = "faux",
|
||||
.register_commands = faux_register_commands,
|
||||
.flash_bank_command = faux_flash_bank_command,
|
||||
.erase = faux_erase,
|
||||
.protect = faux_protect,
|
||||
.write = faux_write,
|
||||
.probe = faux_probe,
|
||||
.auto_probe = faux_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = faux_protect_check,
|
||||
.info = faux_info
|
||||
};
|
||||
|
||||
typedef struct faux_flash_bank_s
|
||||
{
|
||||
struct target_s *target;
|
||||
struct target *target;
|
||||
uint8_t *memory;
|
||||
uint32_t start_address;
|
||||
} faux_flash_bank_t;
|
||||
};
|
||||
|
||||
static const int sectorSize = 0x10000;
|
||||
|
||||
|
||||
/* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath>
|
||||
*/
|
||||
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
|
||||
{
|
||||
faux_flash_bank_t *info;
|
||||
struct faux_flash_bank *info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank faux configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
info = malloc(sizeof(faux_flash_bank_t));
|
||||
info = malloc(sizeof(struct faux_flash_bank));
|
||||
if (info == NULL)
|
||||
{
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
@@ -90,7 +67,7 @@ static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
int i = 0;
|
||||
uint32_t offset = 0;
|
||||
bank->num_sectors = bank->size/sectorSize;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
@@ -100,10 +77,10 @@ static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
info->target = get_target(args[5]);
|
||||
info->target = get_target(CMD_ARGV[5]);
|
||||
if (info->target == NULL)
|
||||
{
|
||||
LOG_ERROR("target '%s' not defined", args[5]);
|
||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
|
||||
free(info->memory);
|
||||
free(info);
|
||||
return ERROR_FAIL;
|
||||
@@ -111,43 +88,62 @@ static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int faux_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
faux_flash_bank_t *info = bank->driver_priv;
|
||||
struct faux_flash_bank *info = bank->driver_priv;
|
||||
memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1));
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_protect(struct flash_bank_s *bank, int set, 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");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int faux_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
faux_flash_bank_t *info = bank->driver_priv;
|
||||
struct faux_flash_bank *info = bank->driver_priv;
|
||||
memcpy(info->memory + offset, buffer, count);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_protect_check(struct flash_bank_s *bank)
|
||||
static int faux_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "faux flash driver");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_probe(struct flash_bank_s *bank)
|
||||
static int faux_probe(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration faux_command_handlers[] = {
|
||||
{
|
||||
.name = "faux",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "faux flash command group",
|
||||
.chain = hello_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver faux_flash = {
|
||||
.name = "faux",
|
||||
.commands = faux_command_handlers,
|
||||
.flash_bank_command = faux_flash_bank_command,
|
||||
.erase = faux_erase,
|
||||
.protect = faux_protect,
|
||||
.write = faux_write,
|
||||
.probe = faux_probe,
|
||||
.auto_probe = faux_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = faux_protect_check,
|
||||
.info = faux_info
|
||||
};
|
||||
48
src/flash/nor/imp.h
Normal file
48
src/flash/nor/imp.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
#ifndef FLASH_NOR_IMP_H
|
||||
#define FLASH_NOR_IMP_H
|
||||
|
||||
// this is an internal header
|
||||
#include "core.h"
|
||||
#include "driver.h"
|
||||
// almost all drivers will need this file
|
||||
#include <target/target.h>
|
||||
|
||||
/**
|
||||
* Adds a new NOR bank to the global list of banks.
|
||||
* @param bank The bank that should be added.
|
||||
*/
|
||||
void flash_bank_add(struct flash_bank *bank);
|
||||
|
||||
/**
|
||||
* @return The first bank in the global list.
|
||||
*/
|
||||
struct flash_bank *flash_bank_list(void);
|
||||
|
||||
int flash_driver_erase(struct flash_bank *bank, int first, int last);
|
||||
int flash_driver_protect(struct flash_bank *bank, int set, int first, int last);
|
||||
int flash_driver_write(struct flash_bank *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
|
||||
/* write (optional verify) an image to flash memory of the given target */
|
||||
int flash_write_unlock(struct target *target, struct image *image,
|
||||
uint32_t *written, int erase, bool unlock);
|
||||
|
||||
#endif // FLASH_NOR_IMP_H
|
||||
@@ -25,10 +25,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "lpc2000.h"
|
||||
#include "armv4_5.h"
|
||||
#include "armv7m.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/arm_opcodes.h>
|
||||
#include <target/armv7m.h>
|
||||
|
||||
|
||||
/* flash programming support for NXP LPC17xx and LPC2xxx devices
|
||||
@@ -53,46 +55,9 @@
|
||||
* - 176x (tested with LPC1768)
|
||||
*/
|
||||
|
||||
static int lpc2000_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int lpc2000_probe(struct flash_bank_s *bank);
|
||||
static int lpc2000_erase_check(struct flash_bank_s *bank);
|
||||
static int lpc2000_protect_check(struct flash_bank_s *bank);
|
||||
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t lpc2000_flash =
|
||||
static int lpc2000_build_sector_list(struct flash_bank *bank)
|
||||
{
|
||||
.name = "lpc2000",
|
||||
.register_commands = lpc2000_register_commands,
|
||||
.flash_bank_command = lpc2000_flash_bank_command,
|
||||
.erase = lpc2000_erase,
|
||||
.protect = lpc2000_protect,
|
||||
.write = lpc2000_write,
|
||||
.probe = lpc2000_probe,
|
||||
.auto_probe = lpc2000_probe,
|
||||
.erase_check = lpc2000_erase_check,
|
||||
.protect_check = lpc2000_protect_check,
|
||||
.info = lpc2000_info
|
||||
};
|
||||
|
||||
static int lpc2000_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,
|
||||
"print part id of lpc2000 flash bank <num>");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||
int i;
|
||||
uint32_t offset = 0;
|
||||
|
||||
@@ -105,7 +70,7 @@ static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
if (bank->size == 128 * 1024)
|
||||
{
|
||||
bank->num_sectors = 16;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * 16);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * 16);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
@@ -118,7 +83,7 @@ static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
else if (bank->size == 256 * 1024)
|
||||
{
|
||||
bank->num_sectors = 18;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * 18);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * 18);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
@@ -189,7 +154,7 @@ static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
break;
|
||||
}
|
||||
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
@@ -243,7 +208,7 @@ static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
|
||||
for(i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
@@ -271,15 +236,15 @@ static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
* 0x20 to 0x33: command result table (1+4 words)
|
||||
* 0x34 to 0xb3: stack (only 128b needed)
|
||||
*/
|
||||
static int lpc2000_iap_call(flash_bank_t *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;
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
mem_param_t mem_params[2];
|
||||
reg_param_t reg_params[5];
|
||||
armv4_5_algorithm_t armv4_5_info; /* for LPC2000 */
|
||||
armv7m_algorithm_t armv7m_info; /* for LPC1700 */
|
||||
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 */
|
||||
|
||||
@@ -299,8 +264,10 @@ static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
case lpc1700:
|
||||
target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
|
||||
target_buffer_set_u32(target, jump_gate,
|
||||
ARMV4_5_T_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4,
|
||||
ARMV4_5_T_B(0xfffffe));
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
@@ -328,9 +295,9 @@ static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
iap_entry_point = 0x7ffffff1;
|
||||
break;
|
||||
default:
|
||||
@@ -376,7 +343,7 @@ static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
/* IAP stack */
|
||||
init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
|
||||
|
||||
/* return address */
|
||||
@@ -412,7 +379,7 @@ static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5
|
||||
return status_code;
|
||||
}
|
||||
|
||||
static int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
@@ -456,20 +423,20 @@ static int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int las
|
||||
/*
|
||||
* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
|
||||
*/
|
||||
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info;
|
||||
struct lpc2000_flash_bank *lpc2000_info;
|
||||
|
||||
if (argc < 8)
|
||||
if (CMD_ARGC < 8)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank lpc2000 configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
|
||||
lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
|
||||
bank->driver_priv = lpc2000_info;
|
||||
|
||||
if (strcmp(args[6], "lpc2000_v1") == 0)
|
||||
if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0)
|
||||
{
|
||||
lpc2000_info->variant = lpc2000_v1;
|
||||
lpc2000_info->cmd51_dst_boundary = 512;
|
||||
@@ -477,7 +444,7 @@ static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *c
|
||||
lpc2000_info->cmd51_can_8192b = 1;
|
||||
lpc2000_info->checksum_vector = 5;
|
||||
}
|
||||
else if (strcmp(args[6], "lpc2000_v2") == 0)
|
||||
else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0)
|
||||
{
|
||||
lpc2000_info->variant = lpc2000_v2;
|
||||
lpc2000_info->cmd51_dst_boundary = 256;
|
||||
@@ -485,7 +452,7 @@ static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *c
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
lpc2000_info->checksum_vector = 5;
|
||||
}
|
||||
else if (strcmp(args[6], "lpc1700") == 0)
|
||||
else if (strcmp(CMD_ARGV[6], "lpc1700") == 0)
|
||||
{
|
||||
lpc2000_info->variant = lpc1700;
|
||||
lpc2000_info->cmd51_dst_boundary = 256;
|
||||
@@ -495,28 +462,28 @@ static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *c
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unknown LPC2000 variant: %s", args[6]);
|
||||
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
|
||||
free(lpc2000_info);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc2000_info->iap_working_area = NULL;
|
||||
lpc2000_info->cclk = strtoul(args[7], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk);
|
||||
lpc2000_info->calc_checksum = 0;
|
||||
lpc2000_build_sector_list(bank);
|
||||
|
||||
if (argc >= 9)
|
||||
if (CMD_ARGC >= 9)
|
||||
{
|
||||
if (strcmp(args[8], "calc_checksum") == 0)
|
||||
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
|
||||
lpc2000_info->calc_checksum = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc2000_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
@@ -566,16 +533,16 @@ static int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
/* can't protect/unprotect on the lpc2000 */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t dst_min_alignment;
|
||||
uint32_t bytes_remaining = count;
|
||||
uint32_t bytes_written = 0;
|
||||
@@ -585,7 +552,7 @@ static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t of
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
int i;
|
||||
working_area_t *download_area;
|
||||
struct working_area *download_area;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -609,7 +576,7 @@ static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t of
|
||||
{
|
||||
if (offset >= bank->sectors[i].offset)
|
||||
first_sector = i;
|
||||
if (offset + CEIL(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;
|
||||
}
|
||||
|
||||
@@ -740,7 +707,7 @@ static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t of
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int lpc2000_probe(struct flash_bank_s *bank)
|
||||
static int lpc2000_probe(struct flash_bank *bank)
|
||||
{
|
||||
/* we can't probe on an lpc2000
|
||||
* if this is an lpc2xxx, it has the configured flash
|
||||
@@ -748,7 +715,7 @@ static int lpc2000_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
static int lpc2000_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -759,39 +726,36 @@ static int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
|
||||
}
|
||||
|
||||
static int lpc2000_protect_check(struct flash_bank_s *bank)
|
||||
static int lpc2000_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
/* sectors are always protected */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||
|
||||
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(lpc2000_handle_part_id_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -803,15 +767,48 @@ static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, cha
|
||||
{
|
||||
if (status_code == ERROR_FLASH_OPERATION_FAILED)
|
||||
{
|
||||
command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||
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);
|
||||
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]);
|
||||
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration lpc2000_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "part_id",
|
||||
.handler = lpc2000_handle_part_id_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "print part id of lpc2000 flash bank <num>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration lpc2000_command_handlers[] = {
|
||||
{
|
||||
.name = "lpc2000",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "lpc2000 flash command group",
|
||||
.chain = lpc2000_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver lpc2000_flash = {
|
||||
.name = "lpc2000",
|
||||
.commands = lpc2000_command_handlers,
|
||||
.flash_bank_command = lpc2000_flash_bank_command,
|
||||
.erase = lpc2000_erase,
|
||||
.protect = lpc2000_protect,
|
||||
.write = lpc2000_write,
|
||||
.probe = lpc2000_probe,
|
||||
.auto_probe = lpc2000_probe,
|
||||
.erase_check = lpc2000_erase_check,
|
||||
.protect_check = lpc2000_protect_check,
|
||||
.info = lpc2000_info,
|
||||
};
|
||||
@@ -23,8 +23,6 @@
|
||||
#ifndef LPC2000_H
|
||||
#define LPC2000_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
lpc2000_v1,
|
||||
@@ -32,10 +30,10 @@ typedef enum
|
||||
lpc1700
|
||||
} lpc2000_variant;
|
||||
|
||||
typedef struct lpc2000_flash_bank_s
|
||||
struct lpc2000_flash_bank
|
||||
{
|
||||
lpc2000_variant variant;
|
||||
struct working_area_s *iap_working_area;
|
||||
struct working_area *iap_working_area;
|
||||
uint32_t cclk;
|
||||
int cmd51_dst_boundary;
|
||||
int cmd51_can_256b;
|
||||
@@ -43,7 +41,7 @@ typedef struct lpc2000_flash_bank_s
|
||||
int calc_checksum;
|
||||
uint32_t cmd51_max_buffer;
|
||||
int checksum_vector;
|
||||
} lpc2000_flash_bank_t;
|
||||
};
|
||||
|
||||
enum lpc2000_status_codes
|
||||
{
|
||||
@@ -31,8 +31,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "lpc288x.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
|
||||
|
||||
#define LOAD_TIMER_ERASE 0
|
||||
@@ -84,44 +85,15 @@
|
||||
/* F_CLK_TIME */
|
||||
#define FCT_CLK_DIV_MASK 0x0FFF
|
||||
|
||||
static int lpc288x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int lpc288x_probe(struct flash_bank_s *bank);
|
||||
static int lpc288x_erase_check(struct flash_bank_s *bank);
|
||||
static int lpc288x_protect_check(struct flash_bank_s *bank);
|
||||
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout);
|
||||
static void lpc288x_load_timer(int erase, struct target_s *target);
|
||||
static void lpc288x_set_flash_clk(struct flash_bank_s *bank);
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank);
|
||||
static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
|
||||
static void lpc288x_load_timer(int erase, struct target *target);
|
||||
static void lpc288x_set_flash_clk(struct flash_bank *bank);
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank *bank);
|
||||
|
||||
flash_driver_t lpc288x_flash =
|
||||
{
|
||||
.name = "lpc288x",
|
||||
.register_commands = lpc288x_register_commands,
|
||||
.flash_bank_command = lpc288x_flash_bank_command,
|
||||
.erase = lpc288x_erase,
|
||||
.protect = lpc288x_protect,
|
||||
.write = lpc288x_write,
|
||||
.probe = lpc288x_probe,
|
||||
.auto_probe = lpc288x_probe,
|
||||
.erase_check = lpc288x_erase_check,
|
||||
.protect_check = lpc288x_protect_check,
|
||||
.info = lpc288x_info
|
||||
};
|
||||
|
||||
static int lpc288x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
uint32_t status;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
do
|
||||
{
|
||||
alive_sleep(1);
|
||||
@@ -138,10 +110,10 @@ static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
}
|
||||
|
||||
/* Read device id register and fill in driver info structure */
|
||||
static int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
static int lpc288x_read_part_info(struct flash_bank *bank)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t cidr;
|
||||
|
||||
int i = 0;
|
||||
@@ -166,7 +138,7 @@ static int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
/* setup the sector info... */
|
||||
offset = bank->base;
|
||||
bank->num_sectors = 23;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * 23);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * 23);
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
@@ -188,28 +160,28 @@ static int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_protect_check(struct flash_bank_s *bank)
|
||||
static int lpc288x_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
|
||||
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info;
|
||||
struct lpc288x_flash_bank *lpc288x_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank LPC288x configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc288x_info = malloc(sizeof(lpc288x_flash_bank_t));
|
||||
lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
|
||||
bank->driver_priv = lpc288x_info;
|
||||
|
||||
/* part wasn't probed for info yet */
|
||||
lpc288x_info->cidr = 0;
|
||||
lpc288x_info->cclk = strtoul(args[6], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -219,10 +191,10 @@ static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *c
|
||||
* AHB = 12 MHz ?
|
||||
* 12000000/66000 = 182
|
||||
* CLK_DIV = 60 ? */
|
||||
static void lpc288x_set_flash_clk(struct flash_bank_s *bank)
|
||||
static void lpc288x_set_flash_clk(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t clk_time;
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
||||
clk_time = (lpc288x_info->cclk / 66000) / 3;
|
||||
target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
|
||||
target_write_u32(bank->target, F_CLK_TIME, clk_time);
|
||||
@@ -234,7 +206,7 @@ static void lpc288x_set_flash_clk(struct flash_bank_s *bank)
|
||||
* LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
|
||||
* = 23 (75) (AN10548 72 - is this wrong?)
|
||||
* TODO: Sort out timing calcs ;) */
|
||||
static void lpc288x_load_timer(int erase, struct target_s *target)
|
||||
static void lpc288x_load_timer(int erase, struct target *target)
|
||||
{
|
||||
if (erase == LOAD_TIMER_ERASE)
|
||||
{
|
||||
@@ -246,9 +218,9 @@ static void lpc288x_load_timer(int erase, struct target_s *target)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank)
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank *bank)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
||||
if (lpc288x_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
@@ -262,7 +234,7 @@ static uint32_t lpc288x_system_ready(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_erase_check(struct flash_bank_s *bank)
|
||||
static int lpc288x_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||
if (status != ERROR_OK)
|
||||
@@ -274,11 +246,11 @@ static int lpc288x_erase_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc288x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint32_t status;
|
||||
int sector;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||
if (status != ERROR_OK)
|
||||
@@ -315,11 +287,11 @@ static int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
uint8_t page_buffer[FLASH_PAGE_SIZE];
|
||||
uint32_t status, source_offset,dest_offset;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t bytes_remaining = count;
|
||||
uint32_t first_sector, last_sector, sector, page;
|
||||
int i;
|
||||
@@ -431,10 +403,10 @@ static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t of
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_probe(struct flash_bank_s *bank)
|
||||
static int lpc288x_probe(struct flash_bank *bank)
|
||||
{
|
||||
/* we only deal with LPC2888 so flash config is fixed */
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
|
||||
int retval;
|
||||
|
||||
if (lpc288x_info->cidr != 0)
|
||||
@@ -454,17 +426,17 @@ static int lpc288x_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int lpc288x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "lpc288x flash driver");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
int lockregion, status;
|
||||
uint32_t value;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
/* probed? halted? */
|
||||
status = lpc288x_system_ready(bank);
|
||||
@@ -499,3 +471,16 @@ static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int la
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct flash_driver lpc288x_flash = {
|
||||
.name = "lpc288x",
|
||||
.flash_bank_command = lpc288x_flash_bank_command,
|
||||
.erase = lpc288x_erase,
|
||||
.protect = lpc288x_protect,
|
||||
.write = lpc288x_write,
|
||||
.probe = lpc288x_probe,
|
||||
.auto_probe = lpc288x_probe,
|
||||
.erase_check = lpc288x_erase_check,
|
||||
.protect_check = lpc288x_protect_check,
|
||||
.info = lpc288x_info,
|
||||
};
|
||||
@@ -21,9 +21,7 @@
|
||||
#ifndef lpc288x_H
|
||||
#define lpc288x_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct lpc288x_flash_bank_s
|
||||
struct lpc288x_flash_bank
|
||||
{
|
||||
uint32_t working_area;
|
||||
uint32_t working_area_size;
|
||||
@@ -34,6 +32,6 @@ typedef struct lpc288x_flash_bank_s
|
||||
uint32_t cclk;
|
||||
|
||||
uint32_t sector_size_break;
|
||||
} lpc288x_flash_bank_t;
|
||||
};
|
||||
|
||||
#endif /* lpc288x_H */
|
||||
@@ -23,11 +23,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "image.h"
|
||||
|
||||
#include "lpc2900.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "armv4_5.h"
|
||||
#include "imp.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/arm.h>
|
||||
#include <target/image.h>
|
||||
|
||||
|
||||
/* 1024 bytes */
|
||||
@@ -129,7 +129,7 @@
|
||||
/**
|
||||
* Private data for \c lpc2900 flash driver.
|
||||
*/
|
||||
typedef struct lpc2900_flash_bank_s
|
||||
struct lpc2900_flash_bank
|
||||
{
|
||||
/**
|
||||
* Holds the value read from CHIPID register.
|
||||
@@ -168,32 +168,17 @@ typedef struct lpc2900_flash_bank_s
|
||||
*/
|
||||
uint32_t max_ram_block;
|
||||
|
||||
} lpc2900_flash_bank_t;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static int lpc2900_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc2900_flash_bank_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct flash_bank_s *bank);
|
||||
static int lpc2900_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int lpc2900_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int lpc2900_write(struct flash_bank_s *bank,
|
||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int lpc2900_probe(struct flash_bank_s *bank);
|
||||
static int lpc2900_erase_check(struct flash_bank_s *bank);
|
||||
static int lpc2900_protect_check(struct flash_bank_s *bank);
|
||||
static int lpc2900_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static uint32_t lpc2900_wait_status(flash_bank_t *bank, uint32_t mask, int timeout);
|
||||
static void lpc2900_setup(struct flash_bank_s *bank);
|
||||
static uint32_t lpc2900_is_ready(struct flash_bank_s *bank);
|
||||
static uint32_t lpc2900_read_security_status(struct flash_bank_s *bank);
|
||||
static uint32_t lpc2900_run_bist128(struct flash_bank_s *bank,
|
||||
static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout);
|
||||
static void lpc2900_setup(struct flash_bank *bank);
|
||||
static uint32_t lpc2900_is_ready(struct flash_bank *bank);
|
||||
static uint32_t lpc2900_read_security_status(struct flash_bank *bank);
|
||||
static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
|
||||
uint32_t addr_from, uint32_t addr_to,
|
||||
uint32_t (*signature)[4] );
|
||||
static uint32_t lpc2900_address2sector(struct flash_bank_s *bank, uint32_t offset);
|
||||
static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset);
|
||||
static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time );
|
||||
|
||||
|
||||
@@ -209,12 +194,12 @@ static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time );
|
||||
* @param[in] mask Mask to be used for INT_STATUS
|
||||
* @param[in] timeout Timeout in ms
|
||||
*/
|
||||
static uint32_t lpc2900_wait_status( flash_bank_t *bank,
|
||||
static uint32_t lpc2900_wait_status( struct flash_bank *bank,
|
||||
uint32_t mask,
|
||||
int timeout )
|
||||
{
|
||||
uint32_t int_status;
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
|
||||
do
|
||||
@@ -243,10 +228,10 @@ static uint32_t lpc2900_wait_status( flash_bank_t *bank,
|
||||
*
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static void lpc2900_setup( struct flash_bank_s *bank )
|
||||
static void lpc2900_setup( struct flash_bank *bank )
|
||||
{
|
||||
uint32_t fcra;
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
|
||||
/* Power up the flash block */
|
||||
@@ -266,9 +251,9 @@ static void lpc2900_setup( struct flash_bank_s *bank )
|
||||
* Must have been successfully probed.
|
||||
* Must be halted.
|
||||
*/
|
||||
static uint32_t lpc2900_is_ready( struct flash_bank_s *bank )
|
||||
static uint32_t lpc2900_is_ready( struct flash_bank *bank )
|
||||
{
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
if( lpc2900_info->chipid != EXPECTED_CHIPID )
|
||||
{
|
||||
@@ -290,7 +275,7 @@ static uint32_t lpc2900_is_ready( struct flash_bank_s *bank )
|
||||
*
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static uint32_t lpc2900_read_security_status( struct flash_bank_s *bank )
|
||||
static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
|
||||
{
|
||||
uint32_t status;
|
||||
if( (status = lpc2900_is_ready( bank )) != ERROR_OK )
|
||||
@@ -298,7 +283,7 @@ static uint32_t lpc2900_read_security_status( struct flash_bank_s *bank )
|
||||
return status;
|
||||
}
|
||||
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
/* Enable ISS access */
|
||||
target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS);
|
||||
@@ -371,12 +356,12 @@ static uint32_t lpc2900_read_security_status( struct flash_bank_s *bank )
|
||||
* @param addr_to
|
||||
* @param signature
|
||||
*/
|
||||
static uint32_t lpc2900_run_bist128(struct flash_bank_s *bank,
|
||||
static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
|
||||
uint32_t addr_from,
|
||||
uint32_t addr_to,
|
||||
uint32_t (*signature)[4] )
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
/* Clear END_OF_MISR interrupt status */
|
||||
target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_MISR );
|
||||
@@ -408,7 +393,7 @@ static uint32_t lpc2900_run_bist128(struct flash_bank_s *bank,
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
* @param offset Offset address relative to bank start
|
||||
*/
|
||||
static uint32_t lpc2900_address2sector( struct flash_bank_s *bank,
|
||||
static uint32_t lpc2900_address2sector( struct flash_bank *bank,
|
||||
uint32_t offset )
|
||||
{
|
||||
uint32_t address = bank->base + offset;
|
||||
@@ -439,7 +424,7 @@ static uint32_t lpc2900_address2sector( struct flash_bank_s *bank,
|
||||
* @param pagenum Page number (0...7)
|
||||
* @param page Page array (FLASH_PAGE_SIZE bytes)
|
||||
*/
|
||||
static int lpc2900_write_index_page( struct flash_bank_s *bank,
|
||||
static int lpc2900_write_index_page( struct flash_bank *bank,
|
||||
int pagenum,
|
||||
uint8_t (*page)[FLASH_PAGE_SIZE] )
|
||||
{
|
||||
@@ -451,7 +436,7 @@ static int lpc2900_write_index_page( struct flash_bank_s *bank,
|
||||
}
|
||||
|
||||
/* Get target, and check if it's halted */
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
if( target->state != TARGET_HALTED )
|
||||
{
|
||||
LOG_ERROR( "Target not halted" );
|
||||
@@ -459,7 +444,7 @@ static int lpc2900_write_index_page( struct flash_bank_s *bank,
|
||||
}
|
||||
|
||||
/* Private info */
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
/* Enable flash block and set the correct CRA clock of 66 kHz */
|
||||
lpc2900_setup( bank );
|
||||
@@ -545,33 +530,23 @@ static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time )
|
||||
*
|
||||
* Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value
|
||||
* of the flash content.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_signature_command( struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc )
|
||||
COMMAND_HANDLER(lpc2900_handle_signature_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
uint32_t status;
|
||||
uint32_t signature[4];
|
||||
|
||||
|
||||
if( argc < 1 )
|
||||
if( CMD_ARGC < 1 )
|
||||
{
|
||||
LOG_WARNING( "Too few arguments. Call: lpc2900 signature <bank#>" );
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
bank = get_flash_bank_by_num( strtoul(args[0], NULL, 0) );
|
||||
if( !bank )
|
||||
{
|
||||
command_print( cmd_ctx, "flash bank '#%s' is out of bounds", args[0] );
|
||||
return ERROR_OK;
|
||||
}
|
||||
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 )
|
||||
{
|
||||
@@ -589,7 +564,7 @@ static int lpc2900_handle_signature_command( struct command_context_s *cmd_ctx,
|
||||
return status;
|
||||
}
|
||||
|
||||
command_print( cmd_ctx, "signature: 0x%8.8" PRIx32
|
||||
command_print( CMD_CTX, "signature: 0x%8.8" PRIx32
|
||||
":0x%8.8" PRIx32
|
||||
":0x%8.8" PRIx32
|
||||
":0x%8.8" PRIx32,
|
||||
@@ -605,35 +580,24 @@ static int lpc2900_handle_signature_command( struct command_context_s *cmd_ctx,
|
||||
*
|
||||
* Read customer info from index sector, and store that block of data into
|
||||
* a disk file. The format is binary.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_read_custom_command( struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc )
|
||||
COMMAND_HANDLER(lpc2900_handle_read_custom_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
|
||||
|
||||
if( argc < 2 )
|
||||
if( CMD_ARGC < 2 )
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
bank = get_flash_bank_by_num( strtoul(args[0], NULL, 0) );
|
||||
if( !bank )
|
||||
{
|
||||
command_print( cmd_ctx, "flash bank '#%s' is out of bounds", args[0] );
|
||||
return ERROR_OK;
|
||||
}
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
lpc2900_info->risky = 0;
|
||||
|
||||
/* Get target, and check if it's halted */
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
if( target->state != TARGET_HALTED )
|
||||
{
|
||||
LOG_ERROR( "Target not halted" );
|
||||
@@ -658,8 +622,8 @@ static int lpc2900_handle_read_custom_command( struct command_context_s *cmd_ctx
|
||||
target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
|
||||
|
||||
/* Try and open the file */
|
||||
fileio_t fileio;
|
||||
char *filename = args[1];
|
||||
struct fileio fileio;
|
||||
const char *filename = CMD_ARGV[1];
|
||||
int ret = fileio_open( &fileio, filename, FILEIO_WRITE, FILEIO_BINARY );
|
||||
if( ret != ERROR_OK )
|
||||
{
|
||||
@@ -667,7 +631,7 @@ static int lpc2900_handle_read_custom_command( struct command_context_s *cmd_ctx
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t nwritten;
|
||||
size_t nwritten;
|
||||
ret = fileio_write( &fileio, sizeof(customer),
|
||||
(const uint8_t *)customer, &nwritten );
|
||||
if( ret != ERROR_OK )
|
||||
@@ -687,43 +651,32 @@ static int lpc2900_handle_read_custom_command( struct command_context_s *cmd_ctx
|
||||
|
||||
/**
|
||||
* Enter password to enable potentially dangerous options.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_password_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(lpc2900_handle_password_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
|
||||
|
||||
if (argc < 2)
|
||||
if (CMD_ARGC < 2)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
#define ISS_PASSWORD "I_know_what_I_am_doing"
|
||||
|
||||
lpc2900_info->risky = !strcmp( args[1], ISS_PASSWORD );
|
||||
lpc2900_info->risky = !strcmp( CMD_ARGV[1], ISS_PASSWORD );
|
||||
|
||||
if( !lpc2900_info->risky )
|
||||
{
|
||||
command_print(cmd_ctx, "Wrong password (use '%s')", ISS_PASSWORD);
|
||||
command_print(CMD_CTX, "Wrong password (use '%s')", ISS_PASSWORD);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx,
|
||||
command_print(CMD_CTX,
|
||||
"Potentially dangerous operation allowed in next command!");
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -733,39 +686,31 @@ static int lpc2900_handle_password_command(struct command_context_s *cmd_ctx,
|
||||
|
||||
/**
|
||||
* Write customer info from file to the index sector.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_write_custom_command( struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc )
|
||||
COMMAND_HANDLER(lpc2900_handle_write_custom_command)
|
||||
{
|
||||
if (argc < 2)
|
||||
if (CMD_ARGC < 2)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
flash_bank_t *bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
/* Check if command execution is allowed. */
|
||||
if( !lpc2900_info->risky )
|
||||
{
|
||||
command_print( cmd_ctx, "Command execution not allowed!" );
|
||||
command_print( CMD_CTX, "Command execution not allowed!" );
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
lpc2900_info->risky = 0;
|
||||
|
||||
/* Get target, and check if it's halted */
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
@@ -773,14 +718,14 @@ static int lpc2900_handle_write_custom_command( struct command_context_s *cmd_ct
|
||||
}
|
||||
|
||||
/* The image will always start at offset 0 */
|
||||
image_t image;
|
||||
struct image image;
|
||||
image.base_address_set = 1;
|
||||
image.base_address = 0;
|
||||
image.start_address_set = 0;
|
||||
|
||||
char *filename = args[1];
|
||||
char *type = (argc >= 3) ? args[2] : NULL;
|
||||
int retval = image_open(&image, filename, type);
|
||||
const char *filename = CMD_ARGV[1];
|
||||
const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL;
|
||||
retval = image_open(&image, filename, type);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
@@ -810,7 +755,7 @@ static int lpc2900_handle_write_custom_command( struct command_context_s *cmd_ct
|
||||
/* Page 4 */
|
||||
uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE;
|
||||
memset( page, 0xff, FLASH_PAGE_SIZE );
|
||||
uint32_t size_read;
|
||||
size_t size_read;
|
||||
retval = image_read_section( &image, 0, 0,
|
||||
ISS_CUSTOMER_SIZE1, &page[offset], &size_read);
|
||||
if( retval != ERROR_OK )
|
||||
@@ -851,52 +796,45 @@ static int lpc2900_handle_write_custom_command( struct command_context_s *cmd_ct
|
||||
|
||||
/**
|
||||
* Activate 'sector security' for a range of sectors.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_secure_sector_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
|
||||
{
|
||||
if (argc < 3)
|
||||
if (CMD_ARGC < 3)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
flash_bank_t *bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
/* Check if command execution is allowed. */
|
||||
if( !lpc2900_info->risky )
|
||||
{
|
||||
command_print( cmd_ctx, "Command execution not allowed! "
|
||||
command_print( CMD_CTX, "Command execution not allowed! "
|
||||
"(use 'password' command first)");
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
lpc2900_info->risky = 0;
|
||||
|
||||
/* Read sector range, and do a sanity check. */
|
||||
int first = strtoul(args[1], NULL, 0);
|
||||
int last = strtoul(args[2], NULL, 0);
|
||||
int first, last;
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
|
||||
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
|
||||
if( (first >= bank->num_sectors) ||
|
||||
(last >= bank->num_sectors) ||
|
||||
(first > last) )
|
||||
{
|
||||
command_print( cmd_ctx, "Illegal sector range" );
|
||||
command_print( CMD_CTX, "Illegal sector range" );
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
uint8_t page[FLASH_PAGE_SIZE];
|
||||
int sector;
|
||||
int retval;
|
||||
|
||||
/* Sectors in page 6 */
|
||||
if( (first <= 4) || (last >= 8) )
|
||||
@@ -940,7 +878,7 @@ static int lpc2900_handle_secure_sector_command(struct command_context_s *cmd_ct
|
||||
}
|
||||
}
|
||||
|
||||
command_print( cmd_ctx,
|
||||
command_print( CMD_CTX,
|
||||
"Sectors security will become effective after next power cycle");
|
||||
|
||||
/* Update the sector security status */
|
||||
@@ -957,33 +895,26 @@ static int lpc2900_handle_secure_sector_command(struct command_context_s *cmd_ct
|
||||
|
||||
/**
|
||||
* Activate JTAG protection.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
*/
|
||||
static int lpc2900_handle_secure_jtag_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
|
||||
{
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* Get the bank descriptor */
|
||||
flash_bank_t *bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
/* Check if command execution is allowed. */
|
||||
if( !lpc2900_info->risky )
|
||||
{
|
||||
command_print( cmd_ctx, "Command execution not allowed! "
|
||||
command_print( CMD_CTX, "Command execution not allowed! "
|
||||
"(use 'password' command first)");
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
@@ -1001,7 +932,6 @@ static int lpc2900_handle_secure_jtag_command(struct command_context_s *cmd_ctx,
|
||||
page[0x30 + 3] = 0x7F;
|
||||
|
||||
/* Write to page 5 */
|
||||
int retval;
|
||||
if( (retval = lpc2900_write_index_page( bank, 5, &page ))
|
||||
!= ERROR_OK )
|
||||
{
|
||||
@@ -1018,106 +948,86 @@ static int lpc2900_handle_secure_jtag_command(struct command_context_s *cmd_ctx,
|
||||
|
||||
/*********************** Flash interface functions **************************/
|
||||
|
||||
static const struct command_registration lpc2900_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "signature",
|
||||
.handler = lpc2900_handle_signature_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Calculate and display signature of flash bank.",
|
||||
},
|
||||
{
|
||||
.name = "read_custom",
|
||||
.handler = lpc2900_handle_read_custom_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id filename",
|
||||
.help = "Copies 912 bytes of customer information "
|
||||
"from index sector into file.",
|
||||
},
|
||||
{
|
||||
.name = "password",
|
||||
.handler = lpc2900_handle_password_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id password",
|
||||
.help = "Enter fixed password to enable 'dangerous' options.",
|
||||
},
|
||||
{
|
||||
.name = "write_custom",
|
||||
.handler = lpc2900_handle_write_custom_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id filename ('bin'|'ihex'|'elf'|'s19')",
|
||||
.help = "Copies 912 bytes of customer info from file "
|
||||
"to index sector.",
|
||||
},
|
||||
{
|
||||
.name = "secure_sector",
|
||||
.handler = lpc2900_handle_secure_sector_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id first_sector last_sector",
|
||||
.help = "Activate sector security for a range of sectors. "
|
||||
"It will be effective after a power cycle.",
|
||||
},
|
||||
{
|
||||
.name = "secure_jtag",
|
||||
.handler = lpc2900_handle_secure_jtag_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Disable the JTAG port. "
|
||||
"It will be effective after a power cycle.",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration lpc2900_command_handlers[] = {
|
||||
{
|
||||
.name = "lpc2900",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "LPC2900 flash command group",
|
||||
.chain = lpc2900_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/**
|
||||
* Register private command handlers.
|
||||
*
|
||||
* @param cmd_ctx
|
||||
*/
|
||||
static int lpc2900_register_commands(struct command_context_s *cmd_ctx)
|
||||
/// Evaluate flash bank command.
|
||||
FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
|
||||
{
|
||||
command_t *lpc2900_cmd = register_command(cmd_ctx, NULL, "lpc2900",
|
||||
NULL, COMMAND_ANY, NULL);
|
||||
struct lpc2900_flash_bank *lpc2900_info;
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"signature",
|
||||
lpc2900_handle_signature_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> | "
|
||||
"print device signature of flash bank");
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"read_custom",
|
||||
lpc2900_handle_read_custom_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> <filename> | "
|
||||
"read customer information from index sector to file");
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"password",
|
||||
lpc2900_handle_password_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> <password> | "
|
||||
"enter password to enable 'dangerous' options");
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"write_custom",
|
||||
lpc2900_handle_write_custom_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> <filename> [<type>] | "
|
||||
"write customer info from file to index sector");
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"secure_sector",
|
||||
lpc2900_handle_secure_sector_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> <first> <last> | "
|
||||
"activate sector security for a range of sectors");
|
||||
|
||||
register_command(
|
||||
cmd_ctx,
|
||||
lpc2900_cmd,
|
||||
"secure_jtag",
|
||||
lpc2900_handle_secure_jtag_command,
|
||||
COMMAND_EXEC,
|
||||
"<bank> <level> | "
|
||||
"activate JTAG security");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate flash bank command.
|
||||
*
|
||||
* Syntax: flash bank lpc2900 0 0 0 0 target# system_base_clock
|
||||
*
|
||||
* @param cmd_ctx
|
||||
* @param cmd
|
||||
* @param args
|
||||
* @param argc
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static int lpc2900_flash_bank_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2900_flash_bank_t *lpc2900_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank LPC2900 configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc2900_info = malloc(sizeof(lpc2900_flash_bank_t));
|
||||
lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank));
|
||||
bank->driver_priv = lpc2900_info;
|
||||
|
||||
/* Get flash clock.
|
||||
* Reject it if we can't meet the requirements for program time
|
||||
* (if clock too slow), or for erase time (clock too fast).
|
||||
*/
|
||||
lpc2900_info->clk_sys_fmc = strtoul(args[6], NULL, 0) * 1000;
|
||||
uint32_t clk_sys_fmc;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc);
|
||||
lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000;
|
||||
|
||||
uint32_t clock_limit;
|
||||
/* Check program time limit */
|
||||
@@ -1152,13 +1062,13 @@ static int lpc2900_flash_bank_command(struct command_context_s *cmd_ctx,
|
||||
* @param first First sector to be erased
|
||||
* @param last Last sector (including) to be erased
|
||||
*/
|
||||
static int lpc2900_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc2900_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint32_t status;
|
||||
int sector;
|
||||
int last_unsecured_sector;
|
||||
target_t *target = bank->target;
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
|
||||
|
||||
status = lpc2900_is_ready(bank);
|
||||
@@ -1259,7 +1169,7 @@ static int lpc2900_erase(struct flash_bank_s *bank, int first, int last)
|
||||
|
||||
|
||||
|
||||
static int lpc2900_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
/* This command is not supported.
|
||||
* "Protection" in LPC2900 terms is handled transparently. Sectors will
|
||||
@@ -1281,14 +1191,14 @@ static int lpc2900_protect(struct flash_bank_s *bank, int set, int first, int la
|
||||
* @param offset Start address (relative to bank start)
|
||||
* @param count Number of bytes to be programmed
|
||||
*/
|
||||
static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
uint8_t page[FLASH_PAGE_SIZE];
|
||||
uint32_t status;
|
||||
uint32_t num_bytes;
|
||||
target_t *target = bank->target;
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
int sector;
|
||||
int retval;
|
||||
|
||||
@@ -1376,7 +1286,7 @@ static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
|
||||
/* Try working area allocation. Start with a large buffer, and try with
|
||||
reduced size if that fails. */
|
||||
working_area_t *warea;
|
||||
struct working_area *warea;
|
||||
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
|
||||
while( (retval = target_alloc_working_area(target,
|
||||
buffer_size + target_code_size,
|
||||
@@ -1395,8 +1305,8 @@ static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
|
||||
if( warea )
|
||||
{
|
||||
reg_param_t reg_params[5];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
struct reg_param reg_params[5];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
|
||||
/* We can use target mode. Download the algorithm. */
|
||||
retval = target_write_buffer( target,
|
||||
@@ -1517,9 +1427,9 @@ static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time);
|
||||
|
||||
/* Execute algorithm, assume breakpoint for last instruction */
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARM_MODE_SVC;
|
||||
armv4_5_info.core_state = ARM_STATE_ARM;
|
||||
|
||||
retval = target_run_algorithm(target, 0, NULL, 5, reg_params,
|
||||
(warea->address) + buffer_size,
|
||||
@@ -1630,10 +1540,10 @@ static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
|
||||
*
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static int lpc2900_probe(struct flash_bank_s *bank)
|
||||
static int lpc2900_probe(struct flash_bank *bank)
|
||||
{
|
||||
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
int i = 0;
|
||||
uint32_t offset;
|
||||
|
||||
@@ -1784,7 +1694,7 @@ static int lpc2900_probe(struct flash_bank_s *bank)
|
||||
* the logical flash number are translated into the physical flash numbers
|
||||
* of the device.
|
||||
*/
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
@@ -1833,7 +1743,7 @@ static int lpc2900_probe(struct flash_bank_s *bank)
|
||||
*
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static int lpc2900_erase_check(struct flash_bank_s *bank)
|
||||
static int lpc2900_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t status = lpc2900_is_ready(bank);
|
||||
if (status != ERROR_OK)
|
||||
@@ -1891,7 +1801,7 @@ static int lpc2900_erase_check(struct flash_bank_s *bank)
|
||||
*
|
||||
* @param bank Pointer to the flash bank descriptor
|
||||
*/
|
||||
static int lpc2900_protect_check(struct flash_bank_s *bank)
|
||||
static int lpc2900_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return lpc2900_read_security_status(bank);
|
||||
}
|
||||
@@ -1904,7 +1814,7 @@ static int lpc2900_protect_check(struct flash_bank_s *bank)
|
||||
* @param buf Buffer to take the string
|
||||
* @param buf_size Maximum number of characters that the buffer can take
|
||||
*/
|
||||
static int lpc2900_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "lpc2900 flash driver");
|
||||
|
||||
@@ -1912,10 +1822,10 @@ static int lpc2900_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
}
|
||||
|
||||
|
||||
flash_driver_t lpc2900_flash =
|
||||
struct flash_driver lpc2900_flash =
|
||||
{
|
||||
.name = "lpc2900",
|
||||
.register_commands = lpc2900_register_commands,
|
||||
.commands = lpc2900_command_handlers,
|
||||
.flash_bank_command = lpc2900_flash_bank_command,
|
||||
.erase = lpc2900_erase,
|
||||
.protect = lpc2900_protect,
|
||||
@@ -23,8 +23,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "non_cfi.h"
|
||||
#include "imp.h"
|
||||
#include "cfi.h"
|
||||
#include "non_cfi.h"
|
||||
|
||||
|
||||
#define KB 1024
|
||||
@@ -32,7 +33,7 @@
|
||||
#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
|
||||
|
||||
/* non-CFI compatible flashes */
|
||||
static non_cfi_t non_cfi_flashes[] = {
|
||||
static struct non_cfi non_cfi_flashes[] = {
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0xd4,
|
||||
@@ -279,6 +280,23 @@ static non_cfi_t non_cfi_flashes[] = {
|
||||
ERASE_REGION(15, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_FUJITSU,
|
||||
.id = 0xba, /* 29LV400BC */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 512*KB,
|
||||
.interface_desc = 0x1, /* x8 or x16 device w/ nBYTE */
|
||||
.max_buf_write_size = 0x00,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 4,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(7, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_AMIC,
|
||||
.id = 0xb31a, /* A29L800A */
|
||||
@@ -403,10 +421,10 @@ static non_cfi_t non_cfi_flashes[] = {
|
||||
}
|
||||
};
|
||||
|
||||
void cfi_fixup_non_cfi(flash_bank_t *bank)
|
||||
void cfi_fixup_non_cfi(struct flash_bank *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
non_cfi_t *non_cfi = non_cfi_flashes;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct non_cfi *non_cfi = non_cfi_flashes;
|
||||
|
||||
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
|
||||
{
|
||||
@@ -456,7 +474,7 @@ void cfi_fixup_non_cfi(flash_bank_t *bank)
|
||||
|
||||
if (cfi_info->pri_id == 0x2)
|
||||
{
|
||||
cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
|
||||
struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
|
||||
|
||||
pri_ext->pri[0] = 'P';
|
||||
pri_ext->pri[1] = 'R';
|
||||
@@ -20,9 +20,7 @@
|
||||
#ifndef NON_CFI_H
|
||||
#define NON_CFI_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct non_cfi_s
|
||||
struct non_cfi
|
||||
{
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
@@ -33,8 +31,8 @@ typedef struct non_cfi_s
|
||||
uint8_t num_erase_regions;
|
||||
uint32_t erase_region_info[6];
|
||||
uint8_t status_poll_mask;
|
||||
} non_cfi_t;
|
||||
};
|
||||
|
||||
extern void cfi_fixup_non_cfi(flash_bank_t *bank);
|
||||
void cfi_fixup_non_cfi(struct flash_bank *bank);
|
||||
|
||||
#endif /* NON_CFI_H */
|
||||
@@ -21,77 +21,45 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "ocl.h"
|
||||
#include "flash.h"
|
||||
#include "embeddedice.h"
|
||||
#include <target/embeddedice.h>
|
||||
|
||||
|
||||
static int ocl_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int ocl_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int ocl_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int ocl_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int ocl_probe(struct flash_bank_s *bank);
|
||||
static int ocl_erase_check(struct flash_bank_s *bank);
|
||||
static int ocl_protect_check(struct flash_bank_s *bank);
|
||||
static int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int ocl_auto_probe(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t ocl_flash =
|
||||
struct ocl_priv
|
||||
{
|
||||
.name = "ocl",
|
||||
.register_commands = ocl_register_commands,
|
||||
.flash_bank_command = ocl_flash_bank_command,
|
||||
.erase = ocl_erase,
|
||||
.protect = ocl_protect,
|
||||
.write = ocl_write,
|
||||
.probe = ocl_probe,
|
||||
.erase_check = ocl_erase_check,
|
||||
.protect_check = ocl_protect_check,
|
||||
.info = ocl_info,
|
||||
.auto_probe = ocl_auto_probe
|
||||
};
|
||||
|
||||
typedef struct ocl_priv_s
|
||||
{
|
||||
arm_jtag_t *jtag_info;
|
||||
struct arm_jtag *jtag_info;
|
||||
unsigned int buflen;
|
||||
unsigned int bufalign;
|
||||
} ocl_priv_t;
|
||||
};
|
||||
|
||||
static int ocl_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int ocl_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_protect_check(struct flash_bank_s *bank)
|
||||
static int ocl_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank ocl 0 0 0 0 <target#> */
|
||||
static int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
|
||||
{
|
||||
int retval;
|
||||
armv4_5_common_t *armv4_5;
|
||||
arm7_9_common_t *arm7_9;
|
||||
ocl_priv_t *ocl;
|
||||
struct arm7_9_common *arm7_9;
|
||||
struct ocl_priv *ocl;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank ocl configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if ((retval = arm7_9_get_arch_pointers(bank->target, &armv4_5, &arm7_9)) != ERROR_OK)
|
||||
return retval;
|
||||
arm7_9 = target_to_arm7_9(bank->target);
|
||||
if (!is_arm7_9(arm7_9))
|
||||
return ERROR_TARGET_INVALID;
|
||||
|
||||
ocl = bank->driver_priv = malloc(sizeof(ocl_priv_t));
|
||||
ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv));
|
||||
ocl->jtag_info = &arm7_9->jtag_info;
|
||||
ocl->buflen = 0;
|
||||
ocl->bufalign = 1;
|
||||
@@ -99,9 +67,9 @@ static int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int ocl_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
struct ocl_priv *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
uint32_t dcc_buffer[3];
|
||||
|
||||
@@ -154,14 +122,14 @@ static int ocl_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
struct ocl_priv *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
uint32_t *dcc_buffer;
|
||||
uint32_t *dcc_bufptr;
|
||||
@@ -266,9 +234,9 @@ static int ocl_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_probe(struct flash_bank_s *bank)
|
||||
static int ocl_probe(struct flash_bank *bank)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
struct ocl_priv *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
uint32_t dcc_buffer[1];
|
||||
int sectsize;
|
||||
@@ -321,7 +289,7 @@ static int ocl_probe(struct flash_bank_s *bank)
|
||||
ocl->buflen = dcc_buffer[0] & 0xffff;
|
||||
ocl->bufalign = dcc_buffer[0] >> 16;
|
||||
|
||||
bank->sectors = realloc(bank->sectors, sizeof(flash_sector_t)*bank->num_sectors);
|
||||
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors);
|
||||
if (bank->num_sectors == 0)
|
||||
{
|
||||
LOG_ERROR("number of sectors shall be non zero value");
|
||||
@@ -364,17 +332,30 @@ static int ocl_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int ocl_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ocl_auto_probe(struct flash_bank_s *bank)
|
||||
static int ocl_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
struct ocl_priv *ocl = bank->driver_priv;
|
||||
|
||||
if (ocl->buflen == 0 || ocl->bufalign == 0)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct flash_driver ocl_flash = {
|
||||
.name = "ocl",
|
||||
.flash_bank_command = ocl_flash_bank_command,
|
||||
.erase = ocl_erase,
|
||||
.protect = ocl_protect,
|
||||
.write = ocl_write,
|
||||
.probe = ocl_probe,
|
||||
.erase_check = ocl_erase_check,
|
||||
.protect_check = ocl_protect_check,
|
||||
.info = ocl_info,
|
||||
.auto_probe = ocl_auto_probe,
|
||||
};
|
||||
@@ -27,8 +27,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "pic32mx.h"
|
||||
#include "mips32.h"
|
||||
#include <target/mips32.h>
|
||||
|
||||
|
||||
static
|
||||
@@ -57,72 +58,22 @@ struct pic32mx_devs_s {
|
||||
{ 0x00, NULL, 0 }
|
||||
};
|
||||
|
||||
static int pic32mx_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int pic32mx_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int pic32mx_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int pic32mx_write_row(struct flash_bank_s *bank, uint32_t address, uint32_t srcaddr);
|
||||
static int pic32mx_write_word(struct flash_bank_s *bank, uint32_t address, uint32_t word);
|
||||
static int pic32mx_probe(struct flash_bank_s *bank);
|
||||
static int pic32mx_auto_probe(struct flash_bank_s *bank);
|
||||
//static int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int pic32mx_protect_check(struct flash_bank_s *bank);
|
||||
static int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
#if 0
|
||||
int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
#endif
|
||||
static int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
//static int pic32mx_chip_erase(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t pic32mx_flash =
|
||||
{
|
||||
.name = "pic32mx",
|
||||
.register_commands = pic32mx_register_commands,
|
||||
.flash_bank_command = pic32mx_flash_bank_command,
|
||||
.erase = pic32mx_erase,
|
||||
.protect = pic32mx_protect,
|
||||
.write = pic32mx_write,
|
||||
.probe = pic32mx_probe,
|
||||
.auto_probe = pic32mx_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = pic32mx_protect_check,
|
||||
.info = pic32mx_info
|
||||
};
|
||||
|
||||
static int pic32mx_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *pic32mx_cmd = register_command(cmd_ctx, NULL, "pic32mx", NULL, COMMAND_ANY, "pic32mx flash specific commands");
|
||||
|
||||
#if 0
|
||||
register_command(cmd_ctx, pic32mx_cmd, "lock", pic32mx_handle_lock_command, COMMAND_EXEC,
|
||||
"lock device");
|
||||
register_command(cmd_ctx, pic32mx_cmd, "unlock", pic32mx_handle_unlock_command, COMMAND_EXEC,
|
||||
"unlock protected device");
|
||||
#endif
|
||||
register_command(cmd_ctx, pic32mx_cmd, "chip_erase", pic32mx_handle_chip_erase_command, COMMAND_EXEC,
|
||||
"erase device");
|
||||
register_command(cmd_ctx, pic32mx_cmd, "pgm_word", pic32mx_handle_pgm_word_command, COMMAND_EXEC,
|
||||
"program a word");
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr);
|
||||
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word);
|
||||
|
||||
/* flash bank pic32mx <base> <size> 0 0 <target#>
|
||||
*/
|
||||
static int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info;
|
||||
struct pic32mx_flash_bank *pic32mx_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank pic32mx configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
pic32mx_info = malloc(sizeof(pic32mx_flash_bank_t));
|
||||
pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank));
|
||||
bank->driver_priv = pic32mx_info;
|
||||
|
||||
pic32mx_info->write_algorithm = NULL;
|
||||
@@ -131,9 +82,9 @@ static int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *c
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t pic32mx_get_flash_status(flash_bank_t *bank)
|
||||
static uint32_t pic32mx_get_flash_status(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
target_read_u32(target, PIC32MX_NVMCON, &status);
|
||||
@@ -141,7 +92,7 @@ static uint32_t pic32mx_get_flash_status(flash_bank_t *bank)
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint32_t pic32mx_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
@@ -157,9 +108,9 @@ static uint32_t pic32mx_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int pic32mx_nvm_exec(struct flash_bank_s *bank, uint32_t op, uint32_t timeout)
|
||||
static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
|
||||
@@ -179,9 +130,9 @@ static int pic32mx_nvm_exec(struct flash_bank_s *bank, uint32_t op, uint32_t tim
|
||||
return status;
|
||||
}
|
||||
|
||||
static int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
static int pic32mx_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
uint32_t devcfg0;
|
||||
int s;
|
||||
@@ -213,9 +164,9 @@ static int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int pic32mx_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
uint32_t status;
|
||||
|
||||
@@ -255,10 +206,10 @@ static int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
struct pic32mx_flash_bank *pic32mx_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
#if 0
|
||||
uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
int i, reg, bit;
|
||||
@@ -348,16 +299,16 @@ static int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int la
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pic32mx_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t buffer_size = 512;
|
||||
working_area_t *source;
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
int retval = ERROR_OK;
|
||||
#if 0
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
armv7m_algorithm_t armv7m_info;
|
||||
struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
|
||||
uint8_t pic32mx_flash_write_code[] = {
|
||||
/* write: */
|
||||
@@ -477,9 +428,9 @@ static int pic32mx_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint3
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int pic32mx_write_word(struct flash_bank_s *bank, uint32_t address, uint32_t word)
|
||||
static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
|
||||
@@ -493,9 +444,9 @@ static int pic32mx_write_word(struct flash_bank_s *bank, uint32_t address, uint3
|
||||
/*
|
||||
* Write a 128 word (512 byte) row to flash address from RAM srcaddr.
|
||||
*/
|
||||
static int pic32mx_write_row(struct flash_bank_s *bank, uint32_t address, uint32_t srcaddr)
|
||||
static int pic32mx_write_row(struct flash_bank *bank, uint32_t address, uint32_t srcaddr)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
|
||||
LOG_DEBUG("addr: 0x%08" PRIx32 " srcaddr: 0x%08" PRIx32 "", address, srcaddr);
|
||||
|
||||
@@ -511,7 +462,7 @@ static int pic32mx_write_row(struct flash_bank_s *bank, uint32_t address, uint32
|
||||
return pic32mx_nvm_exec(bank, NVMCON_OP_ROW_PROG, 100);
|
||||
}
|
||||
|
||||
static int pic32mx_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
uint32_t words_remaining = (count / 4);
|
||||
uint32_t bytes_remaining = (count & 0x00000003);
|
||||
@@ -589,12 +540,12 @@ static int pic32mx_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t of
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int pic32mx_probe(struct flash_bank_s *bank)
|
||||
static int pic32mx_probe(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
mips32_common_t *mips32 = target->arch_info;
|
||||
mips_ejtag_t *ejtag_info = &mips32->ejtag_info;
|
||||
struct target *target = bank->target;
|
||||
struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
|
||||
struct mips32_common *mips32 = target->arch_info;
|
||||
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
|
||||
int i;
|
||||
uint16_t num_pages = 0;
|
||||
uint32_t device_id;
|
||||
@@ -657,7 +608,7 @@ static int pic32mx_probe(struct flash_bank_s *bank)
|
||||
bank->num_sectors = num_pages;
|
||||
bank->chip_width = 4;
|
||||
bank->bus_width = 4;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_pages);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||
|
||||
for (i = 0; i < num_pages; i++)
|
||||
{
|
||||
@@ -672,26 +623,26 @@ static int pic32mx_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int pic32mx_auto_probe(struct flash_bank_s *bank)
|
||||
static int pic32mx_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv;
|
||||
if (pic32mx_info->probed)
|
||||
return ERROR_OK;
|
||||
return pic32mx_probe(bank);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(pic32mx_handle_part_id_command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
mips32_common_t *mips32 = target->arch_info;
|
||||
mips_ejtag_t *ejtag_info = &mips32->ejtag_info;
|
||||
struct target *target = bank->target;
|
||||
struct mips32_common *mips32 = target->arch_info;
|
||||
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
|
||||
uint32_t device_id;
|
||||
int printed = 0, i;
|
||||
|
||||
@@ -722,24 +673,21 @@ static int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
}
|
||||
|
||||
#if 0
|
||||
int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(pic32mx_handle_lock_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
pic32mx_flash_bank_t *pic32mx_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct pic32mx_flash_bank *pic32mx_info = NULL;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx lock <bank>");
|
||||
command_print(CMD_CTX, "pic32mx lock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
pic32mx_info = bank->driver_priv;
|
||||
|
||||
@@ -753,7 +701,7 @@ int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
|
||||
if (pic32mx_erase_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx failed to erase options");
|
||||
command_print(CMD_CTX, "pic32mx failed to erase options");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -762,33 +710,30 @@ int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
|
||||
if (pic32mx_write_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx failed to lock device");
|
||||
command_print(CMD_CTX, "pic32mx failed to lock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "pic32mx locked");
|
||||
command_print(CMD_CTX, "pic32mx locked");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(pic32mx_handle_unlock_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
pic32mx_flash_bank_t *pic32mx_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct pic32mx_flash_bank *pic32mx_info = NULL;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx unlock <bank>");
|
||||
command_print(CMD_CTX, "pic32mx unlock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
pic32mx_info = bank->driver_priv;
|
||||
|
||||
@@ -802,26 +747,26 @@ int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
|
||||
if (pic32mx_erase_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx failed to unlock device");
|
||||
command_print(CMD_CTX, "pic32mx failed to unlock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (pic32mx_write_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx failed to lock device");
|
||||
command_print(CMD_CTX, "pic32mx failed to lock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "pic32mx unlocked");
|
||||
command_print(CMD_CTX, "pic32mx unlocked");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
static int pic32mx_chip_erase(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
#if 0
|
||||
uint32_t status;
|
||||
#endif
|
||||
@@ -864,24 +809,21 @@ static int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(pic32mx_handle_chip_erase_command)
|
||||
{
|
||||
#if 0
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
if (argc != 0)
|
||||
if (CMD_ARGC != 0)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx chip_erase");
|
||||
command_print(CMD_CTX, "pic32mx chip_erase");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (pic32mx_chip_erase(bank) == ERROR_OK)
|
||||
{
|
||||
@@ -891,41 +833,39 @@ static int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx,
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "pic32mx chip erase complete");
|
||||
command_print(CMD_CTX, "pic32mx chip erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx chip erase failed");
|
||||
command_print(CMD_CTX, "pic32mx chip erase failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(pic32mx_handle_pgm_word_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
uint32_t address, value;
|
||||
int status, res;
|
||||
|
||||
if (argc != 3)
|
||||
if (CMD_ARGC != 3)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx pgm_word <addr> <value> <bank>");
|
||||
command_print(CMD_CTX, "pic32mx pgm_word <addr> <value> <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
address = strtoul(args[0], NULL, 0);
|
||||
value = strtoul(args[1], NULL, 0);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
||||
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[2], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[2]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (address < bank->base || address >= (bank->base + bank->size))
|
||||
{
|
||||
command_print(cmd_ctx, "flash address '%s' is out of bounds", args[0]);
|
||||
command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -937,9 +877,47 @@ static int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, ch
|
||||
res = ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
if (res == ERROR_OK)
|
||||
command_print(cmd_ctx, "pic32mx pgm word complete");
|
||||
command_print(CMD_CTX, "pic32mx pgm word complete");
|
||||
else
|
||||
command_print(cmd_ctx, "pic32mx pgm word failed (status = 0x%x)", status);
|
||||
command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
static const struct command_registration pic32mx_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "chip_erase",
|
||||
.handler = pic32mx_handle_chip_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "erase device",
|
||||
},
|
||||
{
|
||||
.name = "pgm_word",
|
||||
.handler = pic32mx_handle_pgm_word_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "program a word",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration pic32mx_command_handlers[] = {
|
||||
{
|
||||
.name = "pic32mx",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "pic32mx flash command group",
|
||||
.chain = pic32mx_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver pic32mx_flash = {
|
||||
.name = "pic32mx",
|
||||
.commands = pic32mx_command_handlers,
|
||||
.flash_bank_command = pic32mx_flash_bank_command,
|
||||
.erase = pic32mx_erase,
|
||||
.protect = pic32mx_protect,
|
||||
.write = pic32mx_write,
|
||||
.probe = pic32mx_probe,
|
||||
.auto_probe = pic32mx_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = pic32mx_protect_check,
|
||||
.info = pic32mx_info,
|
||||
};
|
||||
@@ -26,15 +26,13 @@
|
||||
#ifndef PIC32MX_H
|
||||
#define PIC32MX_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct pic32mx_flash_bank_s
|
||||
struct pic32mx_flash_bank
|
||||
{
|
||||
working_area_t *write_algorithm;
|
||||
struct working_area *write_algorithm;
|
||||
int devid;
|
||||
int ppage_size;
|
||||
int probed;
|
||||
} pic32mx_flash_bank_t;
|
||||
};
|
||||
|
||||
#define PIC32MX_MANUF_ID 0x029
|
||||
|
||||
@@ -104,10 +102,10 @@ typedef struct pic32mx_flash_bank_s
|
||||
#define NVMKEY1 0xAA996655
|
||||
#define NVMKEY2 0x556699AA
|
||||
|
||||
typedef struct pic32mx_mem_layout_s {
|
||||
struct pic32mx_mem_layout {
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
} pic32mx_mem_layout_t;
|
||||
};
|
||||
|
||||
#endif /* PIC32MX_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,9 +20,7 @@
|
||||
#ifndef STELLARIS_FLASH_H
|
||||
#define STELLARIS_FLASH_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct stellaris_flash_bank_s
|
||||
struct stellaris_flash_bank
|
||||
{
|
||||
/* chip id register */
|
||||
uint32_t did0;
|
||||
@@ -41,7 +39,6 @@ typedef struct stellaris_flash_bank_s
|
||||
|
||||
/* nv memory bits */
|
||||
uint16_t num_lockbits;
|
||||
uint32_t lockbits;
|
||||
|
||||
/* main clock status */
|
||||
uint32_t rcc;
|
||||
@@ -52,25 +49,32 @@ typedef struct stellaris_flash_bank_s
|
||||
uint32_t mck_freq;
|
||||
const char *iosc_desc;
|
||||
const char *mck_desc;
|
||||
} stellaris_flash_bank_t;
|
||||
};
|
||||
|
||||
/* STELLARIS control registers */
|
||||
#define SCB_BASE 0x400FE000
|
||||
#define DID0 0x000
|
||||
#define DID1 0x004
|
||||
#define DC0 0x008
|
||||
#define DC1 0x010
|
||||
#define DC2 0x014
|
||||
#define DC3 0x018
|
||||
#define DC4 0x01C
|
||||
#define DID0 0x000
|
||||
#define DID1 0x004
|
||||
#define DC0 0x008
|
||||
#define DC1 0x010
|
||||
#define DC2 0x014
|
||||
#define DC3 0x018
|
||||
#define DC4 0x01C
|
||||
|
||||
#define RIS 0x050
|
||||
#define RCC 0x060
|
||||
#define PLLCFG 0x064
|
||||
#define RCC2 0x070
|
||||
#define RIS 0x050
|
||||
#define RCC 0x060
|
||||
#define PLLCFG 0x064
|
||||
#define RCC2 0x070
|
||||
#define NVMSTAT 0x1a0
|
||||
|
||||
/* "legacy" flash memory protection registers (64KB max) */
|
||||
#define FMPRE 0x130
|
||||
#define FMPPE 0x134
|
||||
|
||||
/* new flash memory protection registers (for more than 64KB) */
|
||||
#define FMPRE0 0x200 /* PRE1 = PRE0 + 4, etc */
|
||||
#define FMPPE0 0x400 /* PPE1 = PPE0 + 4, etc */
|
||||
|
||||
#define USECRL 0x140
|
||||
|
||||
#define FLASH_CONTROL_BASE 0x400FD000
|
||||
@@ -96,4 +100,8 @@ typedef struct stellaris_flash_bank_s
|
||||
|
||||
/* STELLARIS constants */
|
||||
|
||||
/* values to write in FMA to commit write-"once" values */
|
||||
#define FLASH_FMA_PRE(x) (2 * (x)) /* for FMPPREx */
|
||||
#define FLASH_FMA_PPE(x) (2 * (x) + 1) /* for FMPPPEx */
|
||||
|
||||
#endif /* STELLARIS_H */
|
||||
@@ -24,74 +24,28 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "stm32x.h"
|
||||
#include "armv7m.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/armv7m.h>
|
||||
|
||||
|
||||
static int stm32x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int stm32x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int stm32x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int stm32x_probe(struct flash_bank_s *bank);
|
||||
static int stm32x_auto_probe(struct flash_bank_s *bank);
|
||||
//static int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_protect_check(struct flash_bank_s *bank);
|
||||
static int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_mass_erase(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t stm32x_flash =
|
||||
{
|
||||
.name = "stm32x",
|
||||
.register_commands = stm32x_register_commands,
|
||||
.flash_bank_command = stm32x_flash_bank_command,
|
||||
.erase = stm32x_erase,
|
||||
.protect = stm32x_protect,
|
||||
.write = stm32x_write,
|
||||
.probe = stm32x_probe,
|
||||
.auto_probe = stm32x_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = stm32x_protect_check,
|
||||
.info = stm32x_info
|
||||
};
|
||||
|
||||
static int stm32x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *stm32x_cmd = register_command(cmd_ctx, NULL, "stm32x", NULL, COMMAND_ANY, "stm32x flash specific commands");
|
||||
|
||||
register_command(cmd_ctx, stm32x_cmd, "lock", stm32x_handle_lock_command, COMMAND_EXEC,
|
||||
"lock device");
|
||||
register_command(cmd_ctx, stm32x_cmd, "unlock", stm32x_handle_unlock_command, COMMAND_EXEC,
|
||||
"unlock protected device");
|
||||
register_command(cmd_ctx, stm32x_cmd, "mass_erase", stm32x_handle_mass_erase_command, COMMAND_EXEC,
|
||||
"mass erase device");
|
||||
register_command(cmd_ctx, stm32x_cmd, "options_read", stm32x_handle_options_read_command, COMMAND_EXEC,
|
||||
"read device option bytes");
|
||||
register_command(cmd_ctx, stm32x_cmd, "options_write", stm32x_handle_options_write_command, COMMAND_EXEC,
|
||||
"write device option bytes");
|
||||
return ERROR_OK;
|
||||
}
|
||||
static int stm32x_mass_erase(struct flash_bank *bank);
|
||||
|
||||
/* flash bank stm32x <base> <size> 0 0 <target#>
|
||||
*/
|
||||
static int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info;
|
||||
struct stm32x_flash_bank *stm32x_info;
|
||||
|
||||
if (argc < 6)
|
||||
if (CMD_ARGC < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank stm32x configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
stm32x_info = malloc(sizeof(stm32x_flash_bank_t));
|
||||
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
|
||||
bank->driver_priv = stm32x_info;
|
||||
|
||||
stm32x_info->write_algorithm = NULL;
|
||||
@@ -100,9 +54,9 @@ static int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cm
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t stm32x_get_flash_status(flash_bank_t *bank)
|
||||
static uint32_t stm32x_get_flash_status(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
target_read_u32(target, STM32_FLASH_SR, &status);
|
||||
@@ -110,9 +64,9 @@ static uint32_t stm32x_get_flash_status(flash_bank_t *bank)
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint32_t stm32x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
/* wait for busy to clear */
|
||||
@@ -129,11 +83,11 @@ static uint32_t stm32x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int stm32x_read_options(struct flash_bank_s *bank)
|
||||
static int stm32x_read_options(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t optiondata;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -157,10 +111,10 @@ static int stm32x_read_options(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
static int stm32x_erase_options(struct flash_bank *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
@@ -194,10 +148,10 @@ static int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_write_options(struct flash_bank_s *bank)
|
||||
static int stm32x_write_options(struct flash_bank *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
@@ -278,10 +232,10 @@ static int stm32x_write_options(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
static int stm32x_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
|
||||
uint32_t protection;
|
||||
int i, s;
|
||||
@@ -350,9 +304,9 @@ static int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int stm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
uint32_t status;
|
||||
|
||||
@@ -391,10 +345,10 @@ static int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
struct target *target = bank->target;
|
||||
uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
int i, reg, bit;
|
||||
int status;
|
||||
@@ -478,15 +432,15 @@ static int stm32x_protect(struct flash_bank_s *bank, int set, int first, int las
|
||||
return stm32x_write_options(bank);
|
||||
}
|
||||
|
||||
static int stm32x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t buffer_size = 16384;
|
||||
working_area_t *source;
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[4];
|
||||
armv7m_algorithm_t armv7m_info;
|
||||
struct reg_param reg_params[4];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
uint8_t stm32x_flash_write_code[] = {
|
||||
@@ -597,9 +551,9 @@ static int stm32x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int stm32x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t words_remaining = (count / 2);
|
||||
uint32_t bytes_remaining = (count & 0x00000001);
|
||||
uint32_t address = bank->base + offset;
|
||||
@@ -702,10 +656,10 @@ static int stm32x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t off
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_probe(struct flash_bank_s *bank)
|
||||
static int stm32x_probe(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
int i;
|
||||
uint16_t num_pages;
|
||||
uint32_t device_id;
|
||||
@@ -804,7 +758,7 @@ static int stm32x_probe(struct flash_bank_s *bank)
|
||||
bank->base = 0x08000000;
|
||||
bank->size = (num_pages * page_size);
|
||||
bank->num_sectors = num_pages;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_pages);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||
|
||||
for (i = 0; i < num_pages; i++)
|
||||
{
|
||||
@@ -819,24 +773,24 @@ static int stm32x_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_auto_probe(struct flash_bank_s *bank)
|
||||
static int stm32x_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
if (stm32x_info->probed)
|
||||
return ERROR_OK;
|
||||
return stm32x_probe(bank);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_part_id_command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t device_id;
|
||||
int printed;
|
||||
|
||||
@@ -940,24 +894,21 @@ static int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_lock_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x lock <bank>");
|
||||
command_print(CMD_CTX, "stm32x lock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -971,7 +922,7 @@ static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *c
|
||||
|
||||
if (stm32x_erase_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to erase options");
|
||||
command_print(CMD_CTX, "stm32x failed to erase options");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -980,33 +931,30 @@ static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *c
|
||||
|
||||
if (stm32x_write_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to lock device");
|
||||
command_print(CMD_CTX, "stm32x failed to lock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "stm32x locked");
|
||||
command_print(CMD_CTX, "stm32x locked");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_unlock_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x unlock <bank>");
|
||||
command_print(CMD_CTX, "stm32x unlock <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -1020,40 +968,39 @@ static int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char
|
||||
|
||||
if (stm32x_erase_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to unlock device");
|
||||
command_print(CMD_CTX, "stm32x failed to unlock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (stm32x_write_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to lock device");
|
||||
command_print(CMD_CTX, "stm32x failed to lock device");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "stm32x unlocked");
|
||||
command_print(CMD_CTX, "stm32x unlocked.\n"
|
||||
"INFO: a reset or power cycle is required "
|
||||
"for the new settings to take effect.");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_options_read_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
uint32_t optionbyte;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x options_read <bank>");
|
||||
command_print(CMD_CTX, "stm32x options_read <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -1066,53 +1013,50 @@ static int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx,
|
||||
}
|
||||
|
||||
target_read_u32(target, STM32_FLASH_OBR, &optionbyte);
|
||||
command_print(cmd_ctx, "Option Byte: 0x%" PRIx32 "", optionbyte);
|
||||
command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);
|
||||
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_ERROR, 1))
|
||||
command_print(cmd_ctx, "Option Byte Complement Error");
|
||||
command_print(CMD_CTX, "Option Byte Complement Error");
|
||||
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_READOUT, 1))
|
||||
command_print(cmd_ctx, "Readout Protection On");
|
||||
command_print(CMD_CTX, "Readout Protection On");
|
||||
else
|
||||
command_print(cmd_ctx, "Readout Protection Off");
|
||||
command_print(CMD_CTX, "Readout Protection Off");
|
||||
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDWDGSW, 1))
|
||||
command_print(cmd_ctx, "Software Watchdog");
|
||||
command_print(CMD_CTX, "Software Watchdog");
|
||||
else
|
||||
command_print(cmd_ctx, "Hardware Watchdog");
|
||||
command_print(CMD_CTX, "Hardware Watchdog");
|
||||
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTOP, 1))
|
||||
command_print(cmd_ctx, "Stop: No reset generated");
|
||||
command_print(CMD_CTX, "Stop: No reset generated");
|
||||
else
|
||||
command_print(cmd_ctx, "Stop: Reset generated");
|
||||
command_print(CMD_CTX, "Stop: Reset generated");
|
||||
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTDBY, 1))
|
||||
command_print(cmd_ctx, "Standby: No reset generated");
|
||||
command_print(CMD_CTX, "Standby: No reset generated");
|
||||
else
|
||||
command_print(cmd_ctx, "Standby: Reset generated");
|
||||
command_print(CMD_CTX, "Standby: Reset generated");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_options_write_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct stm32x_flash_bank *stm32x_info = NULL;
|
||||
uint16_t optionbyte = 0xF8;
|
||||
|
||||
if (argc < 4)
|
||||
if (CMD_ARGC < 4)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>");
|
||||
command_print(CMD_CTX, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -1124,36 +1068,43 @@ static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (strcmp(args[1], "SWWDG") == 0)
|
||||
/* REVISIT: ignores some options which we will display...
|
||||
* and doesn't insist on the specified syntax.
|
||||
*/
|
||||
|
||||
/* OPT_RDWDGSW */
|
||||
if (strcmp(CMD_ARGV[1], "SWWDG") == 0)
|
||||
{
|
||||
optionbyte |= (1 << 0);
|
||||
}
|
||||
else
|
||||
else /* REVISIT must be "HWWDG" then ... */
|
||||
{
|
||||
optionbyte &= ~(1 << 0);
|
||||
}
|
||||
|
||||
if (strcmp(args[2], "NORSTSTNDBY") == 0)
|
||||
/* OPT_RDRSTSTDBY */
|
||||
if (strcmp(CMD_ARGV[2], "NORSTSTNDBY") == 0)
|
||||
{
|
||||
optionbyte |= (1 << 1);
|
||||
}
|
||||
else
|
||||
else /* REVISIT must be "RSTSTNDBY" then ... */
|
||||
{
|
||||
optionbyte &= ~(1 << 1);
|
||||
}
|
||||
|
||||
if (strcmp(args[3], "NORSTSTOP") == 0)
|
||||
/* OPT_RDRSTSTOP */
|
||||
if (strcmp(CMD_ARGV[3], "NORSTSTOP") == 0)
|
||||
{
|
||||
optionbyte |= (1 << 2);
|
||||
}
|
||||
else
|
||||
else /* REVISIT must be "RSTSTOP" then ... */
|
||||
{
|
||||
optionbyte &= ~(1 << 2);
|
||||
}
|
||||
|
||||
if (stm32x_erase_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to erase options");
|
||||
command_print(CMD_CTX, "stm32x failed to erase options");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1161,18 +1112,20 @@ static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx
|
||||
|
||||
if (stm32x_write_options(bank) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x failed to write options");
|
||||
command_print(CMD_CTX, "stm32x failed to write options");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "stm32x write options complete");
|
||||
command_print(CMD_CTX, "stm32x write options complete.\n"
|
||||
"INFO: a reset or power cycle is required "
|
||||
"for the new settings to take effect.");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
static int stm32x_mass_erase(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
@@ -1208,23 +1161,20 @@ static int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x mass_erase <bank>");
|
||||
command_print(CMD_CTX, "stm32x mass_erase <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (stm32x_mass_erase(bank) == ERROR_OK)
|
||||
{
|
||||
@@ -1234,12 +1184,76 @@ static int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, c
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "stm32x mass erase complete");
|
||||
command_print(CMD_CTX, "stm32x mass erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x mass erase failed");
|
||||
command_print(CMD_CTX, "stm32x mass erase failed");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration stm32x_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "lock",
|
||||
.handler = stm32x_handle_lock_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Lock entire flash device.",
|
||||
},
|
||||
{
|
||||
.name = "unlock",
|
||||
.handler = stm32x_handle_unlock_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Unlock entire protected flash device.",
|
||||
},
|
||||
{
|
||||
.name = "mass_erase",
|
||||
.handler = stm32x_handle_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Erase entire flash device.",
|
||||
},
|
||||
{
|
||||
.name = "options_read",
|
||||
.handler = stm32x_handle_options_read_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Read and display device option byte.",
|
||||
},
|
||||
{
|
||||
.name = "options_write",
|
||||
.handler = stm32x_handle_options_write_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id ('SWWDG'|'HWWDG') "
|
||||
"('RSTSTNDBY'|'NORSTSTNDBY') "
|
||||
"('RSTSTOP'|'NORSTSTOP')",
|
||||
.help = "Replace bits in device option byte.",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration stm32x_command_handlers[] = {
|
||||
{
|
||||
.name = "stm32x",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "stm32x flash command group",
|
||||
.chain = stm32x_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver stm32x_flash = {
|
||||
.name = "stm32x",
|
||||
.commands = stm32x_command_handlers,
|
||||
.flash_bank_command = stm32x_flash_bank_command,
|
||||
.erase = stm32x_erase,
|
||||
.protect = stm32x_protect,
|
||||
.write = stm32x_write,
|
||||
.probe = stm32x_probe,
|
||||
.auto_probe = stm32x_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = stm32x_protect_check,
|
||||
.info = stm32x_info,
|
||||
};
|
||||
@@ -23,22 +23,20 @@
|
||||
#ifndef STM32X_H
|
||||
#define STM32X_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct stm32x_options_s
|
||||
struct stm32x_options
|
||||
{
|
||||
uint16_t RDP;
|
||||
uint16_t user_options;
|
||||
uint16_t protection[4];
|
||||
} stm32x_options_t;
|
||||
};
|
||||
|
||||
typedef struct stm32x_flash_bank_s
|
||||
struct stm32x_flash_bank
|
||||
{
|
||||
stm32x_options_t option_bytes;
|
||||
working_area_t *write_algorithm;
|
||||
struct stm32x_options option_bytes;
|
||||
struct working_area *write_algorithm;
|
||||
int ppage_size;
|
||||
int probed;
|
||||
} stm32x_flash_bank_t;
|
||||
};
|
||||
|
||||
/* stm32x register locations */
|
||||
|
||||
@@ -93,9 +91,9 @@ typedef struct stm32x_flash_bank_s
|
||||
#define KEY1 0x45670123
|
||||
#define KEY2 0xCDEF89AB
|
||||
|
||||
typedef struct stm32x_mem_layout_s {
|
||||
struct stm32x_mem_layout {
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
} stm32x_mem_layout_t;
|
||||
};
|
||||
|
||||
#endif /* STM32X_H */
|
||||
@@ -24,12 +24,14 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "str7x.h"
|
||||
#include "armv4_5.h"
|
||||
#include "binarybuffer.h"
|
||||
#include <target/arm.h>
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
|
||||
|
||||
str7x_mem_layout_t mem_layout_str7bank0[] = {
|
||||
struct str7x_mem_layout mem_layout_str7bank0[] = {
|
||||
{0x00000000, 0x02000, 0x01},
|
||||
{0x00002000, 0x02000, 0x02},
|
||||
{0x00004000, 0x02000, 0x04},
|
||||
@@ -40,57 +42,20 @@ str7x_mem_layout_t mem_layout_str7bank0[] = {
|
||||
{0x00030000, 0x10000, 0x80}
|
||||
};
|
||||
|
||||
str7x_mem_layout_t mem_layout_str7bank1[] = {
|
||||
struct str7x_mem_layout mem_layout_str7bank1[] = {
|
||||
{0x00000000, 0x02000, 0x10000},
|
||||
{0x00002000, 0x02000, 0x20000}
|
||||
};
|
||||
|
||||
static int str7x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int str7x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int str7x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int str7x_probe(struct flash_bank_s *bank);
|
||||
//static int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int str7x_protect_check(struct flash_bank_s *bank);
|
||||
static int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t str7x_flash =
|
||||
static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg)
|
||||
{
|
||||
.name = "str7x",
|
||||
.register_commands = str7x_register_commands,
|
||||
.flash_bank_command = str7x_flash_bank_command,
|
||||
.erase = str7x_erase,
|
||||
.protect = str7x_protect,
|
||||
.write = str7x_write,
|
||||
.probe = str7x_probe,
|
||||
.auto_probe = str7x_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = str7x_protect_check,
|
||||
.info = str7x_info
|
||||
};
|
||||
|
||||
static int str7x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *str7x_cmd = register_command(cmd_ctx, NULL, "str7x", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
register_command(cmd_ctx, str7x_cmd, "disable_jtag", str7x_handle_disable_jtag_command, COMMAND_EXEC,
|
||||
"disable jtag access");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_get_flash_adr(struct flash_bank_s *bank, uint32_t reg)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
return (str7x_info->register_base | reg);
|
||||
}
|
||||
|
||||
static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
static int str7x_build_block_list(struct flash_bank *bank)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
|
||||
int i;
|
||||
int num_sectors;
|
||||
@@ -118,7 +83,7 @@ static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
num_sectors = b0_sectors + b1_sectors;
|
||||
|
||||
bank->num_sectors = num_sectors;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
|
||||
str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
|
||||
|
||||
num_sectors = 0;
|
||||
@@ -128,7 +93,10 @@ static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start;
|
||||
bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size;
|
||||
bank->sectors[num_sectors].is_erased = -1;
|
||||
bank->sectors[num_sectors].is_protected = 1;
|
||||
/* the reset_init handler marks all the sectors unprotected,
|
||||
* matching hardware after reset; keep the driver in sync
|
||||
*/
|
||||
bank->sectors[num_sectors].is_protected = 0;
|
||||
str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit;
|
||||
}
|
||||
|
||||
@@ -137,7 +105,10 @@ static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start;
|
||||
bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size;
|
||||
bank->sectors[num_sectors].is_erased = -1;
|
||||
bank->sectors[num_sectors].is_protected = 1;
|
||||
/* the reset_init handler marks all the sectors unprotected,
|
||||
* matching hardware after reset; keep the driver in sync
|
||||
*/
|
||||
bank->sectors[num_sectors].is_protected = 0;
|
||||
str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit;
|
||||
}
|
||||
|
||||
@@ -146,40 +117,40 @@ static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
|
||||
/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
|
||||
*/
|
||||
static int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info;
|
||||
struct str7x_flash_bank *str7x_info;
|
||||
|
||||
if (argc < 7)
|
||||
if (CMD_ARGC < 7)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank str7x configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
str7x_info = malloc(sizeof(str7x_flash_bank_t));
|
||||
str7x_info = malloc(sizeof(struct str7x_flash_bank));
|
||||
bank->driver_priv = str7x_info;
|
||||
|
||||
/* set default bits for str71x flash */
|
||||
str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
|
||||
str7x_info->disable_bit = (1 << 1);
|
||||
|
||||
if (strcmp(args[6], "STR71x") == 0)
|
||||
if (strcmp(CMD_ARGV[6], "STR71x") == 0)
|
||||
{
|
||||
str7x_info->register_base = 0x40100000;
|
||||
}
|
||||
else if (strcmp(args[6], "STR73x") == 0)
|
||||
else if (strcmp(CMD_ARGV[6], "STR73x") == 0)
|
||||
{
|
||||
str7x_info->register_base = 0x80100000;
|
||||
str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
|
||||
}
|
||||
else if (strcmp(args[6], "STR75x") == 0)
|
||||
else if (strcmp(CMD_ARGV[6], "STR75x") == 0)
|
||||
{
|
||||
str7x_info->register_base = 0x20100000;
|
||||
str7x_info->disable_bit = (1 << 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unknown STR7x variant: '%s'", args[6]);
|
||||
LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]);
|
||||
free(str7x_info);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
@@ -191,9 +162,9 @@ static int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t str7x_status(struct flash_bank_s *bank)
|
||||
static uint32_t str7x_status(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t retval;
|
||||
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
|
||||
@@ -201,9 +172,9 @@ static uint32_t str7x_status(struct flash_bank_s *bank)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static uint32_t str7x_result(struct flash_bank_s *bank)
|
||||
static uint32_t str7x_result(struct flash_bank *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
struct target *target = bank->target;
|
||||
uint32_t retval;
|
||||
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
|
||||
@@ -211,10 +182,10 @@ static uint32_t str7x_result(struct flash_bank_s *bank)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int str7x_protect_check(struct flash_bank_s *bank)
|
||||
static int str7x_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
|
||||
int i;
|
||||
uint32_t retval;
|
||||
@@ -238,10 +209,10 @@ static int str7x_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int str7x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
|
||||
int i;
|
||||
uint32_t cmd;
|
||||
@@ -291,10 +262,10 @@ static int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int str7x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
uint32_t cmd;
|
||||
uint32_t retval;
|
||||
@@ -345,15 +316,15 @@ static int str7x_protect(struct flash_bank_s *bank, int set, int first, int last
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t buffer_size = 8192;
|
||||
working_area_t *source;
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[6];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
struct reg_param reg_params[6];
|
||||
struct arm_algorithm armv4_5_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
uint32_t str7x_flash_write_code[] = {
|
||||
@@ -406,9 +377,9 @@ static int str7x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_
|
||||
}
|
||||
}
|
||||
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
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_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
@@ -460,10 +431,10 @@ static int str7x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int str7x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
static int str7x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
struct str7x_flash_bank *str7x_info = bank->driver_priv;
|
||||
uint32_t dwords_remaining = (count / 8);
|
||||
uint32_t bytes_remaining = (count & 0x00000007);
|
||||
uint32_t address = bank->base + offset;
|
||||
@@ -620,47 +591,49 @@ static int str7x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offs
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_probe(struct flash_bank_s *bank)
|
||||
static int str7x_probe(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(str7x_handle_part_id_command)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int str7x_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "str7x flash driver info");
|
||||
/* STR7x flash doesn't support sector protection interrogation.
|
||||
* FLASH_NVWPAR acts as a write only register; its read value
|
||||
* doesn't reflect the actual protection state of the sectors.
|
||||
*/
|
||||
LOG_WARNING("STR7x flash lock information might not be correct "
|
||||
"due to hardware limitations.");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
COMMAND_HANDLER(str7x_handle_disable_jtag_command)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
str7x_flash_bank_t *str7x_info = NULL;
|
||||
struct target *target = NULL;
|
||||
struct str7x_flash_bank *str7x_info = NULL;
|
||||
|
||||
uint32_t flash_cmd;
|
||||
uint32_t retval;
|
||||
uint16_t ProtectionLevel = 0;
|
||||
uint16_t ProtectionRegs;
|
||||
|
||||
if (argc < 1)
|
||||
if (CMD_ARGC < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "str7x disable_jtag <bank>");
|
||||
command_print(CMD_CTX, "str7x disable_jtag <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "str7x disable_jtag <bank> ok");
|
||||
return ERROR_OK;
|
||||
}
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
str7x_info = bank->driver_priv;
|
||||
|
||||
@@ -673,15 +646,16 @@ static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx,
|
||||
}
|
||||
|
||||
/* first we get protection status */
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), &retval);
|
||||
uint32_t reg;
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), ®);
|
||||
|
||||
if (!(retval & str7x_info->disable_bit))
|
||||
if (!(reg & str7x_info->disable_bit))
|
||||
{
|
||||
ProtectionLevel = 1;
|
||||
}
|
||||
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), &retval);
|
||||
ProtectionRegs = ~(retval >> 16);
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®);
|
||||
ProtectionRegs = ~(reg >> 16);
|
||||
|
||||
while (((ProtectionRegs) != 0) && (ProtectionLevel < 16))
|
||||
{
|
||||
@@ -710,3 +684,36 @@ static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx,
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration str7x_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "disable_jtag",
|
||||
.handler = str7x_handle_disable_jtag_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "disable jtag access",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
static const struct command_registration str7x_command_handlers[] = {
|
||||
{
|
||||
.name = "str7x",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "str7x flash command group",
|
||||
.chain = str7x_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver str7x_flash = {
|
||||
.name = "str7x",
|
||||
.commands = str7x_command_handlers,
|
||||
.flash_bank_command = str7x_flash_bank_command,
|
||||
.erase = str7x_erase,
|
||||
.protect = str7x_protect,
|
||||
.write = str7x_write,
|
||||
.probe = str7x_probe,
|
||||
.auto_probe = str7x_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = str7x_protect_check,
|
||||
.info = str7x_info,
|
||||
};
|
||||
@@ -23,16 +23,14 @@
|
||||
#ifndef STR7X_H
|
||||
#define STR7X_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct str7x_flash_bank_s
|
||||
struct str7x_flash_bank
|
||||
{
|
||||
uint32_t *sector_bits;
|
||||
uint32_t disable_bit;
|
||||
uint32_t busy_bits;
|
||||
uint32_t register_base;
|
||||
working_area_t *write_algorithm;
|
||||
} str7x_flash_bank_t;
|
||||
struct working_area *write_algorithm;
|
||||
};
|
||||
|
||||
enum str7x_status_codes
|
||||
{
|
||||
@@ -101,10 +99,10 @@ enum str7x_status_codes
|
||||
#define FLASH_ERER 0x00000002
|
||||
#define FLASH_ERR 0x00000001
|
||||
|
||||
typedef struct str7x_mem_layout_s {
|
||||
struct str7x_mem_layout {
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
uint32_t sector_bit;
|
||||
} str7x_mem_layout_t;
|
||||
};
|
||||
|
||||
#endif /* STR7X_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user