Compare commits
941 Commits
v0.4.0
...
v0.5.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff640f197a | ||
|
|
e53f7e5fc0 | ||
|
|
45287bda76 | ||
|
|
5e2637a4e0 | ||
|
|
b851a4949b | ||
|
|
1aba820519 | ||
|
|
5141ab3e69 | ||
|
|
29f6f6ae5f | ||
|
|
379abb9167 | ||
|
|
b4bbe33d17 | ||
|
|
f279e54347 | ||
|
|
3c3f3c4247 | ||
|
|
03e4ae8481 | ||
|
|
37aaa28292 | ||
|
|
e7c611deea | ||
|
|
16cbe1216a | ||
|
|
9cac49caee | ||
|
|
3428035a7e | ||
|
|
37d5ac6378 | ||
|
|
9f40d41f68 | ||
|
|
523c172280 | ||
|
|
c8b5719802 | ||
|
|
1b0862c189 | ||
|
|
5227ae7162 | ||
|
|
47aa65b3e8 | ||
|
|
d343941386 | ||
|
|
cbe201fe6b | ||
|
|
7b0ead520d | ||
|
|
f4b9a2fc8b | ||
|
|
ca76e4a423 | ||
|
|
c4bcb0b95a | ||
|
|
d539fc856f | ||
|
|
f42353d821 | ||
|
|
f4a3db0d4a | ||
|
|
56d3927abf | ||
|
|
e899fcaca0 | ||
|
|
01c0ffe98f | ||
|
|
33f9bec9ec | ||
|
|
1cfb2287a6 | ||
|
|
5d9b7cdd2b | ||
|
|
c989de0cea | ||
|
|
d09bef2622 | ||
|
|
f499bab698 | ||
|
|
f6315d5e5b | ||
|
|
ae02a0e517 | ||
|
|
fa1f2682d4 | ||
|
|
796086cd49 | ||
|
|
524d79ebe7 | ||
|
|
4da551732e | ||
|
|
096fd6bcc0 | ||
|
|
875298bc53 | ||
|
|
ba576920cf | ||
|
|
9b4628ddab | ||
|
|
db91a36fdd | ||
|
|
acdf14eb43 | ||
|
|
73988aea1f | ||
|
|
212db44fcf | ||
|
|
a57daf23db | ||
|
|
6d6837f988 | ||
|
|
5d7d08a1f0 | ||
|
|
d16b0ea6d4 | ||
|
|
ef599aebfd | ||
|
|
ee124401a2 | ||
|
|
6d9f61fb65 | ||
|
|
129f099ef1 | ||
|
|
9d4aec6bda | ||
|
|
6349a47ebc | ||
|
|
53c0fb6ef5 | ||
|
|
289cecebf0 | ||
|
|
2889471b58 | ||
|
|
522d5b84e2 | ||
|
|
743fada06a | ||
|
|
7d8053e93f | ||
|
|
e3f3f60a02 | ||
|
|
5c739b148e | ||
|
|
d2911627d2 | ||
|
|
1e7e594452 | ||
|
|
5578935eff | ||
|
|
b778b36f29 | ||
|
|
36d60ee6c8 | ||
|
|
5bd1f0bad4 | ||
|
|
2e88162b00 | ||
|
|
5d987bca9c | ||
|
|
3c6af518b3 | ||
|
|
32ede8fa21 | ||
|
|
e105915a4a | ||
|
|
2ed19d3b9b | ||
|
|
e984dc1f16 | ||
|
|
b69119668e | ||
|
|
f9feeacb7f | ||
|
|
ecd5e5de7f | ||
|
|
81f238f522 | ||
|
|
041953f3b1 | ||
|
|
5cc83a880a | ||
|
|
08303f10aa | ||
|
|
28ddd16ddc | ||
|
|
a7844aa4e8 | ||
|
|
d6027ca6a8 | ||
|
|
ba71e8c521 | ||
|
|
28e6dcee85 | ||
|
|
22437fac28 | ||
|
|
5d538084be | ||
|
|
13cf987bb8 | ||
|
|
c7a17b8466 | ||
|
|
24943498e6 | ||
|
|
becfbeaacd | ||
|
|
5e86c5173c | ||
|
|
719f9ecde3 | ||
|
|
bc9afcd4d1 | ||
|
|
b125689459 | ||
|
|
3fea99097e | ||
|
|
a1d9f16320 | ||
|
|
930d70f1a3 | ||
|
|
3b7c9585db | ||
|
|
a0b83e82f7 | ||
|
|
977df18f50 | ||
|
|
364cfaac1d | ||
|
|
378567da4e | ||
|
|
2615bf4398 | ||
|
|
d76fd2aac7 | ||
|
|
1b9e80f7e6 | ||
|
|
0c1ebf2673 | ||
|
|
83ab5ad240 | ||
|
|
667c65552e | ||
|
|
e1f5055bb0 | ||
|
|
f169f86bd1 | ||
|
|
8d338f3296 | ||
|
|
b75bdb7b04 | ||
|
|
ac6f8f9616 | ||
|
|
3e83991560 | ||
|
|
56f705525c | ||
|
|
54ec0c4a8a | ||
|
|
be14e8cbb0 | ||
|
|
68bd107c6d | ||
|
|
dec80e1cff | ||
|
|
a843789ede | ||
|
|
fc574c64bb | ||
|
|
6c5e1781a1 | ||
|
|
ec2b8d71ac | ||
|
|
a343570195 | ||
|
|
17201b5847 | ||
|
|
558f760ff0 | ||
|
|
4332bc32e4 | ||
|
|
9f17b30f88 | ||
|
|
33a17fd359 | ||
|
|
582b4195a9 | ||
|
|
9b1d38707c | ||
|
|
9eeb02c165 | ||
|
|
2321bb3c42 | ||
|
|
4da640563b | ||
|
|
bb0d11cba9 | ||
|
|
689c244389 | ||
|
|
59a6380a17 | ||
|
|
cc9939879c | ||
|
|
8e85bb4eea | ||
|
|
2c4f7f1dd4 | ||
|
|
bce76b80cc | ||
|
|
952de89bfe | ||
|
|
0123985abc | ||
|
|
df500c5a04 | ||
|
|
a4bf71386b | ||
|
|
aebc0d5556 | ||
|
|
f6783d4465 | ||
|
|
26db0a6bef | ||
|
|
e941805713 | ||
|
|
0eed61b7c4 | ||
|
|
b992dd58f1 | ||
|
|
99cd373019 | ||
|
|
2ed3f55547 | ||
|
|
e5677ce9e5 | ||
|
|
95de667e24 | ||
|
|
c3c6a6e1d4 | ||
|
|
6ddcee7d20 | ||
|
|
47b5829db4 | ||
|
|
f26cd96740 | ||
|
|
05abfbadf1 | ||
|
|
403e239960 | ||
|
|
6ebac1b829 | ||
|
|
2bd6a4795a | ||
|
|
578294dbdd | ||
|
|
fa93174a56 | ||
|
|
01edbc2c3f | ||
|
|
b7163f534a | ||
|
|
0f863ecb01 | ||
|
|
3f4b9e334b | ||
|
|
fe0894015f | ||
|
|
aa9baf11a8 | ||
|
|
17a6ffa0c7 | ||
|
|
422e9f9b41 | ||
|
|
779005f43d | ||
|
|
bc404041c0 | ||
|
|
dcc9624b98 | ||
|
|
aaa52e16ce | ||
|
|
f609d03f1f | ||
|
|
28b953d0bd | ||
|
|
177fe9d762 | ||
|
|
05ab8bdb81 | ||
|
|
94e90cbf16 | ||
|
|
405b7a458d | ||
|
|
b21be6054a | ||
|
|
6684b35346 | ||
|
|
08bf273def | ||
|
|
d51b561b10 | ||
|
|
706284a8fd | ||
|
|
5ca7cbe2d2 | ||
|
|
75cdbff5aa | ||
|
|
b0bdc4e2f2 | ||
|
|
aaf145c422 | ||
|
|
efcea8306a | ||
|
|
859ccccd80 | ||
|
|
a0858bfed0 | ||
|
|
4592506b8e | ||
|
|
c34e69cb10 | ||
|
|
8e60d4955f | ||
|
|
aea22bdbd1 | ||
|
|
3fa99ed2bf | ||
|
|
827053c79d | ||
|
|
e26bda10bc | ||
|
|
6df10184f6 | ||
|
|
4df93cb95f | ||
|
|
9629adcbde | ||
|
|
5b34018ccd | ||
|
|
a727418184 | ||
|
|
4749a40821 | ||
|
|
5b1efd0176 | ||
|
|
11193c040c | ||
|
|
8eb92c7e99 | ||
|
|
8684bd1342 | ||
|
|
0535531d27 | ||
|
|
61e1e525c1 | ||
|
|
7ec55eb863 | ||
|
|
94fa8fd30a | ||
|
|
aa61a3b3d8 | ||
|
|
7351eecf6a | ||
|
|
6a1750e961 | ||
|
|
9f408db29d | ||
|
|
a665ef716a | ||
|
|
0cd84000da | ||
|
|
dc1c5a7500 | ||
|
|
e8eb5bbc04 | ||
|
|
c69553cbc5 | ||
|
|
1795239cfd | ||
|
|
09a0a69c09 | ||
|
|
d8ece229f9 | ||
|
|
d356034f03 | ||
|
|
18a5a46bd9 | ||
|
|
093ec6656a | ||
|
|
f49283a062 | ||
|
|
5e27647e22 | ||
|
|
457556b146 | ||
|
|
b7b9ad755e | ||
|
|
35c30e9ee7 | ||
|
|
3db34f8447 | ||
|
|
2e1f2b50fd | ||
|
|
5f3603b8ef | ||
|
|
21a1c6ec33 | ||
|
|
7bb79f0f51 | ||
|
|
52044a17ce | ||
|
|
b0759dfc53 | ||
|
|
0136977c40 | ||
|
|
50e79d60ce | ||
|
|
eea91f71f9 | ||
|
|
4f9a9b8eba | ||
|
|
8f93c0a3fe | ||
|
|
7cd2617384 | ||
|
|
4994c60083 | ||
|
|
56d9ee779d | ||
|
|
319555cd35 | ||
|
|
690e054a3d | ||
|
|
3d834bdab7 | ||
|
|
83e5aaf577 | ||
|
|
921f40f62a | ||
|
|
8b41812da3 | ||
|
|
e03f45f699 | ||
|
|
37f4978f95 | ||
|
|
07dcb5af12 | ||
|
|
29d2d15f3f | ||
|
|
d33f4a2ad5 | ||
|
|
9f18afc39e | ||
|
|
23bf724e04 | ||
|
|
6839618062 | ||
|
|
c9544e411d | ||
|
|
30da7c67ce | ||
|
|
af3f77a177 | ||
|
|
2eebdcf93e | ||
|
|
5787853bc1 | ||
|
|
969b1e66dd | ||
|
|
39dbb516a4 | ||
|
|
cbf48bed6a | ||
|
|
9a76c68563 | ||
|
|
c6e07051e6 | ||
|
|
ae68ddc25e | ||
|
|
26ba6ea511 | ||
|
|
fe4fe623d5 | ||
|
|
b4ee2864e4 | ||
|
|
6165f14ee2 | ||
|
|
b3052b614c | ||
|
|
b8c42b985d | ||
|
|
4bd2b30d5b | ||
|
|
fa46805481 | ||
|
|
740b9e25b4 | ||
|
|
5cd931ed1c | ||
|
|
6ef4e97779 | ||
|
|
2e7d51c96a | ||
|
|
81790fb56a | ||
|
|
bd9d2468cb | ||
|
|
f2a1b7f3af | ||
|
|
0ac6c0d1a8 | ||
|
|
7b2687b45b | ||
|
|
f0fac8a2cd | ||
|
|
c24087d33e | ||
|
|
a1ce28b118 | ||
|
|
778b789c8e | ||
|
|
40a93104d5 | ||
|
|
71031bcf7f | ||
|
|
1bd87f5dba | ||
|
|
6356604382 | ||
|
|
94e1445a86 | ||
|
|
a9d0b3de44 | ||
|
|
9a04974131 | ||
|
|
c606d858a9 | ||
|
|
1892a2b510 | ||
|
|
42082f7c23 | ||
|
|
4bbdf966d4 | ||
|
|
e6fc371e2e | ||
|
|
06b4903e3e | ||
|
|
8902789f0d | ||
|
|
17634b3760 | ||
|
|
6dbe9b7124 | ||
|
|
64751942a3 | ||
|
|
fcee511f4e | ||
|
|
c40571e6b9 | ||
|
|
8c0c259ed6 | ||
|
|
d80fca527a | ||
|
|
838cd58e24 | ||
|
|
ab263fafbb | ||
|
|
29d7031fe3 | ||
|
|
7bbd6c7683 | ||
|
|
d16dbaa0fc | ||
|
|
5d09972931 | ||
|
|
f1f8d9a6c9 | ||
|
|
f5ae179519 | ||
|
|
4cc3597944 | ||
|
|
fb7c709804 | ||
|
|
28bbe4e983 | ||
|
|
2b546fdc45 | ||
|
|
52558354e6 | ||
|
|
d213e1a12c | ||
|
|
c5414f95b6 | ||
|
|
49f42ab51d | ||
|
|
09c798a144 | ||
|
|
e7a8de1762 | ||
|
|
fdae51287c | ||
|
|
015bf55944 | ||
|
|
6287c23b32 | ||
|
|
c62fb3fa81 | ||
|
|
aa4c140a12 | ||
|
|
6c04f1e440 | ||
|
|
e7b2958229 | ||
|
|
4747af362d | ||
|
|
d220e22e63 | ||
|
|
fc4e001de3 | ||
|
|
6ef3d4ccfe | ||
|
|
49a231f38d | ||
|
|
e774df7f69 | ||
|
|
fc4cbc0f98 | ||
|
|
074498f836 | ||
|
|
8f1f8e7b96 | ||
|
|
d5b9c7998c | ||
|
|
1fa91f336a | ||
|
|
887cac65b0 | ||
|
|
0649fb2f6c | ||
|
|
9e3d43cfe7 | ||
|
|
70b1538996 | ||
|
|
d8464623bd | ||
|
|
559d08c19e | ||
|
|
4617cd0f91 | ||
|
|
1fafb669c9 | ||
|
|
53228fbc2e | ||
|
|
2ff1adfa79 | ||
|
|
f176278e98 | ||
|
|
e7d26173fc | ||
|
|
1ceb2c7e7a | ||
|
|
d4de14dafe | ||
|
|
ed44447e3d | ||
|
|
2ee47b22c6 | ||
|
|
e3773e3e3d | ||
|
|
3864da1ab8 | ||
|
|
6229e438dd | ||
|
|
ebe431879d | ||
|
|
7e4cf8db58 | ||
|
|
45de3b1fbe | ||
|
|
d543aa0148 | ||
|
|
96a56ba086 | ||
|
|
50d5441e2a | ||
|
|
6c137a2fc0 | ||
|
|
cb2dba2c12 | ||
|
|
5a41435e45 | ||
|
|
a60a57d8ed | ||
|
|
d623832685 | ||
|
|
fb7235f12a | ||
|
|
3931b99d14 | ||
|
|
3a693ef526 | ||
|
|
ecad76061f | ||
|
|
45e5d1d90a | ||
|
|
19167a7af6 | ||
|
|
3bb4a6ba14 | ||
|
|
6468c593c7 | ||
|
|
9f26aff39c | ||
|
|
cb0de21d0c | ||
|
|
22911a3aed | ||
|
|
9aafd42853 | ||
|
|
edefee9880 | ||
|
|
ea48794210 | ||
|
|
1abc26d7a2 | ||
|
|
6000411ddd | ||
|
|
241fd0b5a8 | ||
|
|
61780558e1 | ||
|
|
549d974814 | ||
|
|
f6a3fc818b | ||
|
|
32ab98c9e9 | ||
|
|
1dbb7ba472 | ||
|
|
f613011aa0 | ||
|
|
103c1f9525 | ||
|
|
ebfb2f4f37 | ||
|
|
7e888741d1 | ||
|
|
60501bb0fb | ||
|
|
c14852385f | ||
|
|
4a47d87e47 | ||
|
|
1b0f194d90 | ||
|
|
35691065f7 | ||
|
|
81e0d4438e | ||
|
|
8afd2309a4 | ||
|
|
73e5dffdfd | ||
|
|
505d4633cd | ||
|
|
ac86f4ccba | ||
|
|
8c21659d2a | ||
|
|
ef92da3315 | ||
|
|
e1c6f6783d | ||
|
|
a40f12d626 | ||
|
|
98a66c4809 | ||
|
|
35af12d3e7 | ||
|
|
ae80c3564a | ||
|
|
3c69eee9ef | ||
|
|
1ca286557a | ||
|
|
31b47688ca | ||
|
|
6f84198841 | ||
|
|
5c98e063b9 | ||
|
|
2c4ef30b11 | ||
|
|
962946ea89 | ||
|
|
66fb176766 | ||
|
|
70794664f1 | ||
|
|
c54c323cf3 | ||
|
|
d23428a47f | ||
|
|
c3d51bf0da | ||
|
|
bb88f3f470 | ||
|
|
36333f9ca8 | ||
|
|
f60a2390cc | ||
|
|
dce422516a | ||
|
|
52ba344a09 | ||
|
|
c3ee26d272 | ||
|
|
a72faf6405 | ||
|
|
07e0bd4685 | ||
|
|
14a25cd6de | ||
|
|
4ed89e4e42 | ||
|
|
98d2579c61 | ||
|
|
a8c8c238f2 | ||
|
|
8f779cf66b | ||
|
|
f1bd1274ee | ||
|
|
676f48d77d | ||
|
|
f941192723 | ||
|
|
ba951aede3 | ||
|
|
91305bfa7f | ||
|
|
3e71449ade | ||
|
|
1399e5f753 | ||
|
|
28ddefd065 | ||
|
|
7682877c8c | ||
|
|
bfa34f88f8 | ||
|
|
c49d4c9f7f | ||
|
|
4e27305ed5 | ||
|
|
d1638abd6a | ||
|
|
6ed9ab5b58 | ||
|
|
ab818f6898 | ||
|
|
803351ec59 | ||
|
|
630fc86ee3 | ||
|
|
8e9b12dc8a | ||
|
|
8772355bbd | ||
|
|
a84112f471 | ||
|
|
f4c1f08f16 | ||
|
|
a463670c31 | ||
|
|
51d9b56861 | ||
|
|
450aaad1e9 | ||
|
|
260eb4548b | ||
|
|
ee17d5c48e | ||
|
|
7176ed9afe | ||
|
|
f0c0256b1f | ||
|
|
1143bbc0c8 | ||
|
|
e0525cd182 | ||
|
|
a9761c9093 | ||
|
|
441ea95f69 | ||
|
|
4333840ee3 | ||
|
|
5164fe5563 | ||
|
|
b62c8d6009 | ||
|
|
a7315891ef | ||
|
|
7dcde11b45 | ||
|
|
e7a1ec64bf | ||
|
|
44ef0327dd | ||
|
|
6c573df11d | ||
|
|
6a237c23c1 | ||
|
|
70fee9207b | ||
|
|
612184176f | ||
|
|
8dbe367c53 | ||
|
|
4611f87f0a | ||
|
|
0345667642 | ||
|
|
8f5e84bf8d | ||
|
|
d249057adf | ||
|
|
20c1d4cc9a | ||
|
|
221ce7c89b | ||
|
|
8249261b88 | ||
|
|
a2d5b0ef77 | ||
|
|
ad02493cf2 | ||
|
|
19fc52f008 | ||
|
|
d10f0def80 | ||
|
|
b85dcae447 | ||
|
|
495ef923ef | ||
|
|
2fdc1db304 | ||
|
|
a4dace3122 | ||
|
|
b05ae41331 | ||
|
|
d16f9259c2 | ||
|
|
9cbf0723d5 | ||
|
|
01b2a3091a | ||
|
|
bb588bdaec | ||
|
|
0672a6497e | ||
|
|
1619facb5e | ||
|
|
f129ef67dc | ||
|
|
e521f6415b | ||
|
|
dc4df8bb97 | ||
|
|
1c79432061 | ||
|
|
e8445c9c9f | ||
|
|
ac5ad4ad8d | ||
|
|
daa02f7d84 | ||
|
|
ccaa9edf29 | ||
|
|
3099858c68 | ||
|
|
1e0f898415 | ||
|
|
db8b99aed6 | ||
|
|
93f2afa45f | ||
|
|
deb176d335 | ||
|
|
f97b6b59ab | ||
|
|
dd88b461da | ||
|
|
cd7f443103 | ||
|
|
2986320cde | ||
|
|
fb96b8607a | ||
|
|
e5d1befe43 | ||
|
|
6cb2d6dd7a | ||
|
|
4fa3cc7746 | ||
|
|
d236a48e8f | ||
|
|
33e7696cfa | ||
|
|
8b82171f75 | ||
|
|
f44eeba16f | ||
|
|
bf8d954352 | ||
|
|
bef497aeb0 | ||
|
|
fe1f7f63b6 | ||
|
|
9a8fe44c83 | ||
|
|
b50bb632ad | ||
|
|
4d238c7f91 | ||
|
|
59bf45be1f | ||
|
|
37cfbe4917 | ||
|
|
19925e4d7f | ||
|
|
f747b16e4e | ||
|
|
9b5572857a | ||
|
|
bc7fa896e6 | ||
|
|
190986eb8c | ||
|
|
ff1c09fbea | ||
|
|
decd417064 | ||
|
|
d26b5236ba | ||
|
|
3f59fcf77e | ||
|
|
b978dcbbee | ||
|
|
3cfbf70559 | ||
|
|
ec073e8943 | ||
|
|
2fbb0b5972 | ||
|
|
dcba070958 | ||
|
|
7013b960fe | ||
|
|
8d1dcb9bcd | ||
|
|
acee9d1c65 | ||
|
|
2a25c968bf | ||
|
|
b8f8d756a2 | ||
|
|
2319caff7d | ||
|
|
3f9d377ce7 | ||
|
|
127f9da4fe | ||
|
|
c3ee63be77 | ||
|
|
cebd817cee | ||
|
|
ada8f5963d | ||
|
|
3eaab9b55b | ||
|
|
647fe050db | ||
|
|
b1cd202f9a | ||
|
|
f2f798fdd3 | ||
|
|
d4e4da0fa1 | ||
|
|
8a2808681e | ||
|
|
80eb7e2a78 | ||
|
|
b89462d7dc | ||
|
|
984bf15821 | ||
|
|
814c2a8f9a | ||
|
|
818120d409 | ||
|
|
5104d56e5c | ||
|
|
cd9c61cc06 | ||
|
|
9bbbbdc0bd | ||
|
|
f4958d61ef | ||
|
|
94f373b404 | ||
|
|
6de2b2d14b | ||
|
|
72d227cd5e | ||
|
|
42c84c59b1 | ||
|
|
f9acaa894f | ||
|
|
f1ce4fe288 | ||
|
|
8022940c5c | ||
|
|
72eb87673c | ||
|
|
e538367186 | ||
|
|
0a837fc36b | ||
|
|
0365225c48 | ||
|
|
953d96f1e2 | ||
|
|
88aa5e31d1 | ||
|
|
90454525b6 | ||
|
|
4d0d649ef9 | ||
|
|
26a77f71e1 | ||
|
|
e85fe0a637 | ||
|
|
43a9282203 | ||
|
|
78b7a571e9 | ||
|
|
4bd415d01b | ||
|
|
8cfd25d29e | ||
|
|
97197c98eb | ||
|
|
da5979c38d | ||
|
|
ab6e62ab76 | ||
|
|
66f42b6f74 | ||
|
|
a09d6020e0 | ||
|
|
748863c2e2 | ||
|
|
64cf05f0c4 | ||
|
|
83ebddd519 | ||
|
|
9161b5fc5c | ||
|
|
395d3bff8c | ||
|
|
00017c90ae | ||
|
|
3c8a0e72f3 | ||
|
|
2eba49b8b1 | ||
|
|
c9e2d13cf9 | ||
|
|
bf3410fcc7 | ||
|
|
3e51d893ed | ||
|
|
9132f7083d | ||
|
|
b6a8254065 | ||
|
|
f3ae52cace | ||
|
|
18918a0423 | ||
|
|
aa2de47d3c | ||
|
|
bac52fbac8 | ||
|
|
9e62f86f24 | ||
|
|
ce58ab9a4e | ||
|
|
dcc7de4f9b | ||
|
|
20724e3325 | ||
|
|
4532dc7831 | ||
|
|
0538081246 | ||
|
|
ecc8041c0f | ||
|
|
73aaaf4830 | ||
|
|
9ab7636ce6 | ||
|
|
49e6c61bcc | ||
|
|
c634680384 | ||
|
|
f6236ade0e | ||
|
|
14c112e992 | ||
|
|
31bbb3cf0c | ||
|
|
54f3f8e4c1 | ||
|
|
00635e28ba | ||
|
|
a1cf1b5244 | ||
|
|
631514724d | ||
|
|
d944a0bed7 | ||
|
|
86e851e1e2 | ||
|
|
215353ef67 | ||
|
|
ee4106ee99 | ||
|
|
94dc7c0a93 | ||
|
|
5319ccd7eb | ||
|
|
ef72484b78 | ||
|
|
f1c1bed39a | ||
|
|
e2c9518eda | ||
|
|
9c3b4cfc5d | ||
|
|
0e4f4bacdc | ||
|
|
06df4664a9 | ||
|
|
2e1eaaae35 | ||
|
|
82ef8472bf | ||
|
|
c0cdb7c631 | ||
|
|
72ba8ec90e | ||
|
|
f40faeb349 | ||
|
|
8465e99442 | ||
|
|
b80d0501b6 | ||
|
|
c86d7bdad4 | ||
|
|
e804a34a63 | ||
|
|
e92b203a76 | ||
|
|
dc464ad88e | ||
|
|
fafed75d98 | ||
|
|
3ecc191b36 | ||
|
|
5fd1c2db9a | ||
|
|
76b81682ee | ||
|
|
602685e66f | ||
|
|
bc8be110ff | ||
|
|
24ebfffff5 | ||
|
|
feb95fbb7b | ||
|
|
ebdd3a1670 | ||
|
|
34f70956ed | ||
|
|
a69cbf0f74 | ||
|
|
61bb0d3d23 | ||
|
|
89747f81f2 | ||
|
|
c7b269ace1 | ||
|
|
b8c54b362b | ||
|
|
9597dcefaa | ||
|
|
dcca0b7694 | ||
|
|
0eb7fb59a0 | ||
|
|
215a5f7442 | ||
|
|
a7fb60dc7b | ||
|
|
7b36d2a229 | ||
|
|
7b76da57f4 | ||
|
|
b05f8171c9 | ||
|
|
6f03e92959 | ||
|
|
4e022886d6 | ||
|
|
4cf13101e5 | ||
|
|
3650981de7 | ||
|
|
2ae192699f | ||
|
|
bbc8f4e6ce | ||
|
|
cf811d8e6b | ||
|
|
f32492c74f | ||
|
|
737c9b6258 | ||
|
|
f7e0f3c285 | ||
|
|
3077f5845f | ||
|
|
2fba796e27 | ||
|
|
82ea640830 | ||
|
|
812e21ac39 | ||
|
|
31b050108a | ||
|
|
91b9f3de0b | ||
|
|
7e33f87b3d | ||
|
|
0d8f60e28f | ||
|
|
ca0f6a5c58 | ||
|
|
80660288e0 | ||
|
|
909130e16e | ||
|
|
282e89c878 | ||
|
|
70226c221f | ||
|
|
8865209545 | ||
|
|
32e647acf4 | ||
|
|
fe60480b7a | ||
|
|
14f4606dcb | ||
|
|
da9f72ca0a | ||
|
|
5e79f999bc | ||
|
|
78248f1df6 | ||
|
|
49b7905cae | ||
|
|
56a21c9cb1 | ||
|
|
e0285dbe73 | ||
|
|
4f1296d151 | ||
|
|
c6cd253ae1 | ||
|
|
48e282aa00 | ||
|
|
cc5f3c85de | ||
|
|
e4056cca2d | ||
|
|
ddf7aabc67 | ||
|
|
620310bcc6 | ||
|
|
b886049c74 | ||
|
|
c9e58238c3 | ||
|
|
ee13916411 | ||
|
|
d31bbc33fa | ||
|
|
decad30865 | ||
|
|
a8a9eddca0 | ||
|
|
41cb911853 | ||
|
|
f549dadb85 | ||
|
|
689fa8ad8c | ||
|
|
da741a51f2 | ||
|
|
f1be0e6af2 | ||
|
|
2ea78551ab | ||
|
|
4809dbb2d7 | ||
|
|
11fd673f0c | ||
|
|
b2495c0101 | ||
|
|
787a5067fb | ||
|
|
fdb9199001 | ||
|
|
d7246f452f | ||
|
|
c936cb334b | ||
|
|
5926b5a94f | ||
|
|
a6307fed91 | ||
|
|
617811ac66 | ||
|
|
aaf848596c | ||
|
|
9acd453d9f | ||
|
|
069f88cfac | ||
|
|
300f0f53c5 | ||
|
|
402d3292bb | ||
|
|
61c0635991 | ||
|
|
0c82bea44a | ||
|
|
c0b5ca6d17 | ||
|
|
b2468e3c4f | ||
|
|
4678108034 | ||
|
|
ec1c90e3cd | ||
|
|
8ffdefcc59 | ||
|
|
de27d28df9 | ||
|
|
8a871560f9 | ||
|
|
4a1bd5b806 | ||
|
|
0f3bbcf096 | ||
|
|
263b4b9057 | ||
|
|
3f0b17e48a | ||
|
|
321aa6aa8f | ||
|
|
81fab96c0d | ||
|
|
2a17fd9f9b | ||
|
|
876bf9bf4c | ||
|
|
88fcb5a9ef | ||
|
|
d37a10da52 | ||
|
|
33e5dd1272 | ||
|
|
d60ebc0ab5 | ||
|
|
a092e8d237 | ||
|
|
27b98c2fa5 | ||
|
|
ed81249129 | ||
|
|
ed6756fb23 | ||
|
|
010492a1ed | ||
|
|
e736468b0e | ||
|
|
4af724df23 | ||
|
|
ec28c674af | ||
|
|
d7dba8d346 | ||
|
|
1cda3e64e4 | ||
|
|
9f1d9499ce | ||
|
|
721502f1d3 | ||
|
|
4be9eded7f | ||
|
|
ccfaed8bc7 | ||
|
|
c2f714bd44 | ||
|
|
b7811b7679 | ||
|
|
5dcad2d34f | ||
|
|
96949890ee | ||
|
|
3b310dbac5 | ||
|
|
7373d1c342 | ||
|
|
03359b1680 | ||
|
|
7f6bab0c4c | ||
|
|
15ff2aeca9 | ||
|
|
1911c8ec8d | ||
|
|
7298452382 | ||
|
|
8ce828dd38 | ||
|
|
8d411d0d24 | ||
|
|
fc9de56a25 | ||
|
|
c09035ea2c | ||
|
|
52a788e008 | ||
|
|
ec108ff59e | ||
|
|
46f92878da | ||
|
|
d37ed9094a | ||
|
|
ae1c64706a | ||
|
|
b48a94f05d | ||
|
|
36df240cea | ||
|
|
fccdfc1cd7 | ||
|
|
0529431fe7 | ||
|
|
cc197c8086 | ||
|
|
bf71e34cbf | ||
|
|
099ffc754a | ||
|
|
3ad171cd53 | ||
|
|
e7e9bfde47 | ||
|
|
79ca05b106 | ||
|
|
051e2c99ab | ||
|
|
7e447043cd | ||
|
|
1d9fba8c14 | ||
|
|
6f8b8593d6 | ||
|
|
030ee192dd | ||
|
|
679f6602fd | ||
|
|
82f44a4708 | ||
|
|
ab5f98edcd | ||
|
|
f85ad1e52a | ||
|
|
a540033a71 | ||
|
|
1bd3ae3986 | ||
|
|
b559b273b5 | ||
|
|
96f9790279 | ||
|
|
4b964a81ca | ||
|
|
de761e350b | ||
|
|
c25fda2c95 | ||
|
|
c23d4596d2 | ||
|
|
763013f15e | ||
|
|
03a26d31e9 | ||
|
|
db464f3cd4 | ||
|
|
24e1e3dd26 | ||
|
|
591e0bbab9 | ||
|
|
edf52a6cc5 | ||
|
|
6030a5cb2a | ||
|
|
257a764582 | ||
|
|
f10ed95a5c | ||
|
|
d0a57c0f0c | ||
|
|
6344f2ab98 | ||
|
|
2946c895a1 | ||
|
|
17d437a7a1 | ||
|
|
c986cc200c | ||
|
|
fc1063a1b9 | ||
|
|
7a5c9c2f4a | ||
|
|
50dc56a488 | ||
|
|
57d7743639 | ||
|
|
e018c7c1d2 | ||
|
|
f7d1be714b | ||
|
|
c6e323b983 | ||
|
|
74113cf725 | ||
|
|
d33a81c549 | ||
|
|
57ebf6d3de | ||
|
|
45a528ff3c | ||
|
|
5e78ddcea0 | ||
|
|
5fdf9535ce | ||
|
|
99939c3c75 | ||
|
|
2119c0a764 | ||
|
|
381ce4308c | ||
|
|
61ee632dbc | ||
|
|
24b1426a72 | ||
|
|
db6c994642 | ||
|
|
d72e90ae4b | ||
|
|
53b3d4dd53 | ||
|
|
5b31186578 | ||
|
|
cb72b7a270 | ||
|
|
b1c00e5a4e | ||
|
|
27401e4c80 | ||
|
|
afbf927663 | ||
|
|
761d4555b8 | ||
|
|
409e23e39b | ||
|
|
57fc63f9f1 | ||
|
|
c9560ba190 | ||
|
|
73c1cff7c2 | ||
|
|
8d13a46626 | ||
|
|
9d6ede25dd | ||
|
|
550abe7396 | ||
|
|
4c9f29bd9c | ||
|
|
b8d8953ae9 | ||
|
|
a851ce0d6f | ||
|
|
0324eb2496 | ||
|
|
63763345d9 | ||
|
|
e4a40d257d | ||
|
|
e70d42a727 | ||
|
|
3ef9beb52c | ||
|
|
8c9b52e8b6 | ||
|
|
a3245bd7cd | ||
|
|
4a64820f23 | ||
|
|
79010bf3df | ||
|
|
7abe9f38b2 | ||
|
|
75067c4042 | ||
|
|
faef631a4d | ||
|
|
1f5883ea56 | ||
|
|
90efc404f3 | ||
|
|
c21c740a89 | ||
|
|
dc342f45f6 | ||
|
|
c8ea748dc2 | ||
|
|
3b68a708c2 | ||
|
|
ecff73043c | ||
|
|
39cfe62796 | ||
|
|
a97bb67543 | ||
|
|
249263d29d | ||
|
|
1aac72d243 | ||
|
|
a299371a9e | ||
|
|
27c068c1f8 | ||
|
|
ce1feaa732 | ||
|
|
b853b9dbc0 |
17
.gitignore
vendored
17
.gitignore
vendored
@@ -14,6 +14,17 @@
|
|||||||
src/jtag/minidriver_imp.h
|
src/jtag/minidriver_imp.h
|
||||||
src/jtag/jtag_minidriver.h
|
src/jtag/jtag_minidriver.h
|
||||||
|
|
||||||
|
# OpenULINK driver files generated by SDCC
|
||||||
|
src/jtag/drivers/OpenULINK/*.rel
|
||||||
|
src/jtag/drivers/OpenULINK/*.asm
|
||||||
|
src/jtag/drivers/OpenULINK/*.lst
|
||||||
|
src/jtag/drivers/OpenULINK/*.sym
|
||||||
|
src/jtag/drivers/OpenULINK/*.map
|
||||||
|
src/jtag/drivers/OpenULINK/*.mem
|
||||||
|
src/jtag/drivers/OpenULINK/*.lnk
|
||||||
|
src/jtag/drivers/OpenULINK/*.ihx
|
||||||
|
src/jtag/drivers/OpenULINK/*.rst
|
||||||
|
|
||||||
# editor files
|
# editor files
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
@@ -73,3 +84,9 @@ patches
|
|||||||
.project
|
.project
|
||||||
.cproject
|
.cproject
|
||||||
.settings
|
.settings
|
||||||
|
|
||||||
|
# Emacs temp files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# CScope database files
|
||||||
|
*cscope.out
|
||||||
|
|||||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
|||||||
[submodule "tools/git2cl"]
|
[submodule "tools/git2cl"]
|
||||||
path = tools/git2cl
|
path = tools/git2cl
|
||||||
url = git://repo.or.cz/git2cl.git
|
url = http://repo.or.cz/r/git2cl.git
|
||||||
|
[submodule "jimtcl"]
|
||||||
|
path = jimtcl
|
||||||
|
url = http://repo.or.cz/r/jimtcl.git
|
||||||
|
|||||||
56
HACKING
Normal file
56
HACKING
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
Submitting patches to the OpenOCD mailing list:
|
||||||
|
|
||||||
|
By the time you have read this, one supposes that
|
||||||
|
you have figured out how to clone the OpenOCD git
|
||||||
|
repository.
|
||||||
|
|
||||||
|
Below is a basic workflow and specific instructions
|
||||||
|
to get you going with git and patches.
|
||||||
|
|
||||||
|
0. Clone the git repository, rather than just
|
||||||
|
download the source.
|
||||||
|
|
||||||
|
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
||||||
|
|
||||||
|
or if you have problems with the "git:" protocol, use
|
||||||
|
the slower http protocol:
|
||||||
|
|
||||||
|
git clone http://repo.or.cz/r/openocd.git
|
||||||
|
|
||||||
|
1. Set up git with your name and email:
|
||||||
|
|
||||||
|
git config --global user.name "John Smith"
|
||||||
|
git config --global user.email "john@smith.org"
|
||||||
|
|
||||||
|
2. Work on your patches. Split the work into
|
||||||
|
multiple small patches that can be reviewed and
|
||||||
|
applied seperately and safely to the OpenOCD
|
||||||
|
repository.
|
||||||
|
|
||||||
|
while(!done) {
|
||||||
|
work - edit files using your favorite editor.
|
||||||
|
run "git commit -a" to commit all changes.
|
||||||
|
}
|
||||||
|
|
||||||
|
TIP! use "git add ." before commit to add new files.
|
||||||
|
|
||||||
|
--- example comment, notice the short first line w/topic ---
|
||||||
|
topic: short comment
|
||||||
|
<blank line>
|
||||||
|
longer comments over several
|
||||||
|
lines...
|
||||||
|
-----
|
||||||
|
|
||||||
|
3. Next you need to make sure that your patches
|
||||||
|
are on top of the latest stuff on the server and
|
||||||
|
that there are no conflicts.
|
||||||
|
|
||||||
|
git pull --rebase
|
||||||
|
|
||||||
|
4. Generate the patch files. This will generate
|
||||||
|
patches for all commits that are on top of
|
||||||
|
the latest stuff on the server:
|
||||||
|
|
||||||
|
git format-patch origin/master
|
||||||
|
|
||||||
|
5. Email the patches to openocd-development@lists.berlios.de
|
||||||
21
Makefile.am
21
Makefile.am
@@ -2,6 +2,9 @@
|
|||||||
# have all needed files, that a GNU package needs
|
# have all needed files, that a GNU package needs
|
||||||
AUTOMAKE_OPTIONS = gnu 1.6
|
AUTOMAKE_OPTIONS = gnu 1.6
|
||||||
|
|
||||||
|
# make sure we pass the correct jimtcl flags to distcheck
|
||||||
|
DISTCHECK_CONFIGURE_FLAGS = --with-jim-ext=nvp --disable-lineedit
|
||||||
|
|
||||||
nobase_dist_pkgdata_DATA = \
|
nobase_dist_pkgdata_DATA = \
|
||||||
contrib/libdcc/dcc_stdio.c \
|
contrib/libdcc/dcc_stdio.c \
|
||||||
contrib/libdcc/dcc_stdio.h \
|
contrib/libdcc/dcc_stdio.h \
|
||||||
@@ -9,11 +12,23 @@ nobase_dist_pkgdata_DATA = \
|
|||||||
contrib/libdcc/README \
|
contrib/libdcc/README \
|
||||||
contrib/openocd.udev
|
contrib/openocd.udev
|
||||||
|
|
||||||
SUBDIRS = src doc
|
if INTERNAL_JIMTCL
|
||||||
|
SUBDIRS = jimtcl
|
||||||
|
else
|
||||||
|
SUBDIRS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += src doc
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
BUGS \
|
||||||
|
HACKING \
|
||||||
|
NEWTAPS \
|
||||||
|
PATCHES.txt \
|
||||||
|
README.Win32 \
|
||||||
Doxyfile.in \
|
Doxyfile.in \
|
||||||
tools/logger.pl
|
tools/logger.pl \
|
||||||
|
contrib/loaders
|
||||||
|
|
||||||
libtool: $(LIBTOOL_DEPS)
|
libtool: $(LIBTOOL_DEPS)
|
||||||
$(SHELL) ./config.status --recheck
|
$(SHELL) ./config.status --recheck
|
||||||
@@ -69,9 +84,9 @@ install-data-hook:
|
|||||||
uninstall-hook:
|
uninstall-hook:
|
||||||
rm -rf $(DESTDIR)$(pkgdatadir)/scripts
|
rm -rf $(DESTDIR)$(pkgdatadir)/scripts
|
||||||
|
|
||||||
|
|
||||||
distclean-local:
|
distclean-local:
|
||||||
rm -rf Doxyfile doxygen
|
rm -rf Doxyfile doxygen
|
||||||
|
rm -f $(srcdir)/jimtcl/configure.gnu
|
||||||
|
|
||||||
DISTCLEANFILES = doxygen.log
|
DISTCLEANFILES = doxygen.log
|
||||||
|
|
||||||
|
|||||||
112
NEWS
112
NEWS
@@ -1,90 +1,65 @@
|
|||||||
This file includes highlights of the changes made in the
|
This file includes highlights of the changes made in the
|
||||||
OpenOCD 0.4.0 source archive release. See the repository
|
OpenOCD 0.5.0 source archive release. See the repository
|
||||||
history for details about what changed, including bugfixes
|
history for details about what changed, including bugfixes
|
||||||
and other issues not mentioned here.
|
and other issues not mentioned here.
|
||||||
|
|
||||||
JTAG Layer:
|
JTAG Layer:
|
||||||
Support KT-Link JTAG adapter.
|
New driver for "Bus Pirate"
|
||||||
Support USB-JTAG, Altera USB-Blaster and compatibles.
|
Rename various commands so they're not JTAG-specific
|
||||||
|
There are migration procedures for most of these, but you should
|
||||||
|
convert your scripts to the new names, since those procedures
|
||||||
|
will not be around forever.
|
||||||
|
jtag jinterface ... is now adapter_name
|
||||||
|
jtag_khz ... is now adapter_khz
|
||||||
|
jtag_nsrst_delay ... is now adapter_nsrst_delay
|
||||||
|
jtag_nsrst_assert_width ... is now adapter_nsrst_assert_width
|
||||||
|
Support Voipac VPACLink JTAG Adapter.
|
||||||
|
|
||||||
Boundary Scan:
|
Boundary Scan:
|
||||||
|
|
||||||
|
Transport framework core ... supporting future work for SWD, SPI, and other
|
||||||
|
non-JTAG ways to debug targets or program flash.
|
||||||
|
|
||||||
Target Layer:
|
Target Layer:
|
||||||
General
|
ARM:
|
||||||
- Removed commands which have been obsolete for at least
|
- basic semihosting support for ARMv7M.
|
||||||
a year (from both documentation and, sometimes, code).
|
- renamed "armv7m" command prefix as "arm"
|
||||||
- new "reset-assert" event, for systems without SRST
|
MIPS:
|
||||||
ARM
|
- "ejtag_srst" variant removed. The same functionality is
|
||||||
- supports "reset-assert" event (except on Cortex-M3)
|
obtained by using "reset_config none".
|
||||||
- renamed "armv4_5" command prefix as "arm"
|
- added PIC32MX software reset support, this means srst is not
|
||||||
- recognize TrustZone "Secure Monitor" mode
|
required to be connected anymore.
|
||||||
- "arm regs" command output changed
|
OTHER:
|
||||||
- register names use "sp" not "r13"
|
- preliminary AVR32 AP7000 support.
|
||||||
- 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:
|
Flash Layer:
|
||||||
'flash bank' and 'nand device' take <bank_name> as first argument.
|
New "stellaris recover" command, implements the procedure
|
||||||
With this, flash/NAND commands allow referencing banks by name:
|
to recover locked devices (restoring non-volatile
|
||||||
- <bank_name>: reference the bank with its defined name
|
state to the factory defaults, including erasing
|
||||||
- <driver_name>[.N]: reference the driver's Nth bank
|
the flash and its protection bits, and possibly
|
||||||
New 'nand verify' command to check bank against an image file.
|
re-enabling hardware debugging).
|
||||||
The "flash erase_address" command now rejects partial sectors;
|
PIC32MX now uses algorithm for flash programming, this
|
||||||
previously it would silently erase extra data. If you
|
has increased the performance by approx 96%.
|
||||||
want to erase the rest of the first and/or last sectors
|
New 'pic32mx unlock' cmd to remove readout protection.
|
||||||
instead of failing, you must pass an explicit "pad" flag.
|
New STM32 Value Line Support.
|
||||||
New at91sam9 NAND controller driver.
|
New 'virtual' flash driver, used to associate other addresses
|
||||||
New s3c64xx NAND controller driver.
|
with a flash bank. See pic32mx.cfg for usage.
|
||||||
|
New iMX27 NAND flash controller driver.
|
||||||
|
|
||||||
Board, Target, and Interface Configuration Scripts:
|
Board, Target, and Interface Configuration Scripts:
|
||||||
ARM9
|
Support IAR LPC1768 kickstart board (by Olimex)
|
||||||
- ETM and ETB hookup for iMX2* targets
|
Support Voipac PXA270/PXA270M module.
|
||||||
Add $HOME/.openocd to the search path.
|
New $PARPORTADDR tcl variable used to change default
|
||||||
Handle Rev C of LM3S811 eval boards.
|
parallel port address used.
|
||||||
- use "luminary-lm3s811.cfg" for older boards
|
Remove lm3s811.cfg; use "stellaris.cfg" instead
|
||||||
- use "luminary.cfg" for RevC and newer
|
|
||||||
|
|
||||||
Core Jim/TCL Scripting:
|
Core Jim/TCL Scripting:
|
||||||
New 'usage' command to provide terse command help.
|
New "add_script_search_dir" command, behaviour is the same
|
||||||
Improved command 'help' command output (sorted and indented).
|
as the "-s" cmd line option.
|
||||||
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:
|
Documentation:
|
||||||
New built-in command development documentation and primer.
|
|
||||||
|
|
||||||
Build and Release:
|
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,
|
For more details about what has changed since the last release,
|
||||||
see the git repository history. With gitweb, you can browse that
|
see the git repository history. With gitweb, you can browse that
|
||||||
@@ -96,3 +71,4 @@ For older NEWS, see the NEWS files associated with each release
|
|||||||
For more information about contributing test reports, bug fixes, or new
|
For more information about contributing test reports, bug fixes, or new
|
||||||
features and device support, please read the new Developer Manual (or
|
features and device support, please read the new Developer Manual (or
|
||||||
the BUGS and PATCHES.txt files in the source archive).
|
the BUGS and PATCHES.txt files in the source archive).
|
||||||
|
|
||||||
|
|||||||
98
NEWS-0.4.0
Normal file
98
NEWS-0.4.0
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
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:
|
||||||
|
Support KT-Link JTAG adapter.
|
||||||
|
Support USB-JTAG, Altera USB-Blaster and compatibles.
|
||||||
|
|
||||||
|
Boundary Scan:
|
||||||
|
|
||||||
|
Target Layer:
|
||||||
|
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:
|
||||||
|
'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:
|
||||||
|
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:
|
||||||
|
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 git repository history. With gitweb, you can browse that
|
||||||
|
in various levels of detail.
|
||||||
|
|
||||||
|
For older NEWS, see the NEWS files associated with each release
|
||||||
|
(i.e. NEWS-<version>).
|
||||||
|
|
||||||
|
For more information about contributing test reports, bug fixes, or new
|
||||||
|
features and device support, please read the new Developer Manual (or
|
||||||
|
the BUGS and PATCHES.txt files in the source archive).
|
||||||
6
README
6
README
@@ -236,6 +236,8 @@ options may be available there:
|
|||||||
Programmer
|
Programmer
|
||||||
--enable-rlink Enable building support for the Raisonance RLink
|
--enable-rlink Enable building support for the Raisonance RLink
|
||||||
JTAG Programmer
|
JTAG Programmer
|
||||||
|
--enable-ulink Enable building support for the Keil ULINK JTAG
|
||||||
|
Programmer
|
||||||
--enable-usbprog Enable building support for the usbprog JTAG
|
--enable-usbprog Enable building support for the usbprog JTAG
|
||||||
Programmer
|
Programmer
|
||||||
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
||||||
@@ -255,8 +257,6 @@ options may be available there:
|
|||||||
|
|
||||||
--enable-ioutil Enable ioutil functions - useful for standalone
|
--enable-ioutil Enable ioutil functions - useful for standalone
|
||||||
OpenOCD implementations
|
OpenOCD implementations
|
||||||
--enable-httpd Enable builtin httpd server - useful for standalone
|
|
||||||
OpenOCD implementations
|
|
||||||
|
|
||||||
--disable-doxygen-html Disable building Doxygen manual as HTML.
|
--disable-doxygen-html Disable building Doxygen manual as HTML.
|
||||||
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
|
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
|
||||||
@@ -317,7 +317,7 @@ The libftdi source code can be download from the following website:
|
|||||||
|
|
||||||
For both Linux and Windows, both libusb and libftdi must be built and
|
For both Linux and Windows, both libusb and libftdi must be built and
|
||||||
installed. To use the newer FT2232H chips, supporting RTCK and USB high
|
installed. To use the newer FT2232H chips, supporting RTCK and USB high
|
||||||
speed (480 Mbps), you need libftdi version 0.16 or newer. Many Linux
|
speed (480 Mbps), use libftdi version 0.17 or newer. Many Linux
|
||||||
distributions provide suitable packages for these libraries.
|
distributions provide suitable packages for these libraries.
|
||||||
|
|
||||||
For Windows, libftdi is supported with versions 0.14 and later.
|
For Windows, libftdi is supported with versions 0.14 and later.
|
||||||
|
|||||||
30
bootstrap
30
bootstrap
@@ -1,15 +1,23 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh
|
||||||
# Run the autotools bootstrap sequence to create the configure script
|
# Run the autotools bootstrap sequence to create the configure script
|
||||||
|
|
||||||
# Stop execution as soon as we have an unknown command
|
# Abort execution on error
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if libtoolize --version >/dev/null 2>&1; then
|
if which libtoolize > /dev/null; then
|
||||||
libtoolize="libtoolize"
|
libtoolize="libtoolize"
|
||||||
elif glibtoolize --version >/dev/null 2>&1; then
|
elif which glibtoolize >/dev/null; then
|
||||||
libtoolize="glibtoolize"
|
libtoolize="glibtoolize"
|
||||||
else
|
else
|
||||||
echo "libtool is required" >&2
|
echo "$0: Error: libtool is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = "nosubmodule" ]; then
|
||||||
|
SKIP_SUBMODULE=1
|
||||||
|
elif [ -n "$1" ]; then
|
||||||
|
echo "$0: Illegal argument $1"
|
||||||
|
echo "USAGE: $0 [nosubmodule]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -26,4 +34,14 @@ automake --gnu --add-missing --copy
|
|||||||
# AM_MAINTAINER_MODE requires --enable-maintainer-mode from everyone using
|
# AM_MAINTAINER_MODE requires --enable-maintainer-mode from everyone using
|
||||||
# current source snapshots (working from GIT, or some source snapshot, etc)
|
# current source snapshots (working from GIT, or some source snapshot, etc)
|
||||||
# otherwise the documentation will fail to build due to missing version.texi
|
# otherwise the documentation will fail to build due to missing version.texi
|
||||||
echo "Bootstrap complete; you can './configure --enable-maintainer-mode ....'"
|
|
||||||
|
if [ -n "$SKIP_SUBMODULE" ]; then
|
||||||
|
echo "Skipping submodule setup"
|
||||||
|
else
|
||||||
|
echo "Setting up submodules"
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Bootstrap complete. Quick build instructions:"
|
||||||
|
echo "./configure --enable-maintainer-mode ...."
|
||||||
|
|||||||
11
common.mk
Normal file
11
common.mk
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
# common flags used in openocd build
|
||||||
|
AM_CPPFLAGS = -I$(top_srcdir)/src \
|
||||||
|
-I$(top_builddir)/src \
|
||||||
|
-DPKGDATADIR=\"$(pkgdatadir)\" \
|
||||||
|
-DPKGLIBDIR=\"$(pkglibdir)\"
|
||||||
|
|
||||||
|
if INTERNAL_JIMTCL
|
||||||
|
AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \
|
||||||
|
-I$(top_builddir)/jimtcl
|
||||||
|
endif
|
||||||
27
config_subdir.m4
Normal file
27
config_subdir.m4
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
dnl
|
||||||
|
dnl If needed, define the m4_ifblank and m4_ifnblank macros from autoconf 2.64
|
||||||
|
dnl This allows us to run with earlier Autoconfs as well.
|
||||||
|
ifdef([m4_ifblank],[],[
|
||||||
|
m4_define([m4_ifblank],
|
||||||
|
[m4_if(m4_translit([[$1]], [ ][ ][
|
||||||
|
]), [], [$2], [$3])])])
|
||||||
|
dnl
|
||||||
|
ifdef([m4_ifnblank],[],[
|
||||||
|
m4_define([m4_ifnblank],
|
||||||
|
[m4_if(m4_translit([[$1]], [ ][ ][
|
||||||
|
]), [], [$3], [$2])])])
|
||||||
|
dnl
|
||||||
|
|
||||||
|
dnl AC_CONFIG_SUBDIRS does not allow configure options to be passed
|
||||||
|
dnl to subdirs, this function allows that by creating a configure.gnu
|
||||||
|
dnl script that prepends configure options and then calls the real
|
||||||
|
dnl configure script
|
||||||
|
AC_DEFUN([AX_CONFIG_SUBDIR_OPTION],
|
||||||
|
[
|
||||||
|
AC_CONFIG_SUBDIRS([$1])
|
||||||
|
|
||||||
|
m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu],
|
||||||
|
[printf "#!/bin/sh
|
||||||
|
"\$"SHELL "../$srcdir/$1/configure" $2 \""\$"@"\" > "$srcdir/$1/configure.gnu"
|
||||||
|
])
|
||||||
|
])
|
||||||
106
configure.in
106
configure.in
@@ -1,8 +1,10 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
AC_INIT([openocd], [0.4.0],
|
AC_INIT([openocd], [0.5.0-dev],
|
||||||
[OpenOCD Mailing List <openocd-development@lists.berlios.de>])
|
[OpenOCD Mailing List <openocd-development@lists.berlios.de>])
|
||||||
AC_CONFIG_SRCDIR([src/openocd.c])
|
AC_CONFIG_SRCDIR([src/openocd.c])
|
||||||
|
|
||||||
|
m4_include(config_subdir.m4)dnl
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip])
|
AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip])
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
|
|
||||||
@@ -408,6 +410,10 @@ AC_ARG_ENABLE(ecosboard,
|
|||||||
AS_HELP_STRING([--enable-ecosboard], [Enable building support for eCos based JTAG debugger]),
|
AS_HELP_STRING([--enable-ecosboard], [Enable building support for eCos based JTAG debugger]),
|
||||||
[build_ecosboard=$enableval], [build_ecosboard=no])
|
[build_ecosboard=$enableval], [build_ecosboard=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(zy1000_master,
|
||||||
|
AS_HELP_STRING([--enable-zy1000-master], [Use ZY1000 JTAG master registers]),
|
||||||
|
[build_zy1000_master=$enableval], [build_zy1000_master=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(zy1000,
|
AC_ARG_ENABLE(zy1000,
|
||||||
AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]),
|
AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]),
|
||||||
[build_zy1000=$enableval], [build_zy1000=no])
|
[build_zy1000=$enableval], [build_zy1000=no])
|
||||||
@@ -416,10 +422,6 @@ AC_ARG_ENABLE(ioutil,
|
|||||||
AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]),
|
AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]),
|
||||||
[build_ioutil=$enableval], [build_ioutil=no])
|
[build_ioutil=$enableval], [build_ioutil=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(httpd,
|
|
||||||
AS_HELP_STRING([--enable-httpd], [Enable builtin httpd server - useful for standalone OpenOCD implementations]),
|
|
||||||
[build_httpd=$enableval], [build_httpd=no])
|
|
||||||
|
|
||||||
case "${host_cpu}" in
|
case "${host_cpu}" in
|
||||||
arm*)
|
arm*)
|
||||||
AC_ARG_ENABLE(ep93xx,
|
AC_ARG_ENABLE(ep93xx,
|
||||||
@@ -470,14 +472,25 @@ AC_ARG_ENABLE(rlink,
|
|||||||
AS_HELP_STRING([--enable-rlink], [Enable building support for the Raisonance RLink JTAG Programmer]),
|
AS_HELP_STRING([--enable-rlink], [Enable building support for the Raisonance RLink JTAG Programmer]),
|
||||||
[build_rlink=$enableval], [build_rlink=no])
|
[build_rlink=$enableval], [build_rlink=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(ulink,
|
||||||
|
AS_HELP_STRING([--enable-ulink], [Enable building support for the Keil ULINK JTAG Programmer]),
|
||||||
|
[build_ulink=$enableval], [build_ulink=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(arm-jtag-ew,
|
AC_ARG_ENABLE(arm-jtag-ew,
|
||||||
AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]),
|
AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]),
|
||||||
[build_armjtagew=$enableval], [build_armjtagew=no])
|
[build_armjtagew=$enableval], [build_armjtagew=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(buspirate,
|
||||||
|
AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]),
|
||||||
|
[build_buspirate=$enableval], [build_buspirate=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(minidriver_dummy,
|
AC_ARG_ENABLE(minidriver_dummy,
|
||||||
AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]),
|
AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]),
|
||||||
[build_minidriver_dummy=$enableval], [build_minidriver_dummy=no])
|
[build_minidriver_dummy=$enableval], [build_minidriver_dummy=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(internal-jimtcl,
|
||||||
|
AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]),
|
||||||
|
[use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes])
|
||||||
|
|
||||||
build_minidriver=no
|
build_minidriver=no
|
||||||
AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
|
AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
|
||||||
@@ -529,7 +542,7 @@ case $host in
|
|||||||
is_win32=yes
|
is_win32=yes
|
||||||
parport_use_ppdev=no
|
parport_use_ppdev=no
|
||||||
|
|
||||||
AC_COMPILE_IFELSE(AC_LANG_PROGRAM([],[return __MINGW32__;]),
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[return __MINGW32__;]])],
|
||||||
[is_mingw=yes],[is_mingw=no])
|
[is_mingw=yes],[is_mingw=no])
|
||||||
if test $is_mingw = yes; then
|
if test $is_mingw = yes; then
|
||||||
AC_DEFINE(IS_MINGW, 1, [1 if building for MinGW.])
|
AC_DEFINE(IS_MINGW, 1, [1 if building for MinGW.])
|
||||||
@@ -622,6 +635,12 @@ else
|
|||||||
AC_DEFINE(BUILD_ZY1000, 0, [0 if you don't want ZY1000.])
|
AC_DEFINE(BUILD_ZY1000, 0, [0 if you don't want ZY1000.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test $build_zy1000_master = yes; then
|
||||||
|
AC_DEFINE(BUILD_ZY1000_MASTER, 1, [1 if you want ZY1000 JTAG master registers.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_ZY1000_MASTER, 0, [0 if you don't want ZY1000 JTAG master registers.])
|
||||||
|
fi
|
||||||
|
|
||||||
if test $build_at91rm9200 = yes; then
|
if test $build_at91rm9200 = yes; then
|
||||||
build_bitbang=yes
|
build_bitbang=yes
|
||||||
AC_DEFINE(BUILD_AT91RM9200, 1, [1 if you want at91rm9200.])
|
AC_DEFINE(BUILD_AT91RM9200, 1, [1 if you want at91rm9200.])
|
||||||
@@ -735,12 +754,32 @@ else
|
|||||||
AC_DEFINE(BUILD_RLINK, 0, [0 if you don't want the RLink JTAG driver.])
|
AC_DEFINE(BUILD_RLINK, 0, [0 if you don't want the RLink JTAG driver.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test $build_ulink = yes; then
|
||||||
|
AC_DEFINE(BUILD_ULINK, 1, [1 if you want the ULINK JTAG driver.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_ULINK, 0, [0 if you don't want the ULINK JTAG driver.])
|
||||||
|
fi
|
||||||
|
|
||||||
if test $build_armjtagew = yes; then
|
if test $build_armjtagew = yes; then
|
||||||
AC_DEFINE(BUILD_ARMJTAGEW, 1, [1 if you want the ARM-JTAG-EW JTAG driver.])
|
AC_DEFINE(BUILD_ARMJTAGEW, 1, [1 if you want the ARM-JTAG-EW JTAG driver.])
|
||||||
else
|
else
|
||||||
AC_DEFINE(BUILD_ARMJTAGEW, 0, [0 if you don't want the ARM-JTAG-EW JTAG driver.])
|
AC_DEFINE(BUILD_ARMJTAGEW, 0, [0 if you don't want the ARM-JTAG-EW JTAG driver.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test $build_buspirate = yes; then
|
||||||
|
AC_DEFINE(BUILD_BUSPIRATE, 1, [1 if you want the Buspirate JTAG driver.])
|
||||||
|
else
|
||||||
|
AC_DEFINE(BUILD_BUSPIRATE, 0, [0 if you don't want the Buspirate JTAG driver.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$use_internal_jimtcl" = yes; then
|
||||||
|
if test -f "$srcdir/jimtcl/configure.ac"; then
|
||||||
|
AX_CONFIG_SUBDIR_OPTION([jimtcl], [--with-jim-ext=nvp --disable-lineedit])
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
#-- Deal with MingW/Cygwin FTD2XX issues
|
#-- Deal with MingW/Cygwin FTD2XX issues
|
||||||
|
|
||||||
if test $is_win32 = yes; then
|
if test $is_win32 = yes; then
|
||||||
@@ -889,22 +928,17 @@ _CFLAGS=`eval echo $CFLAGS`
|
|||||||
LDFLAGS=$_LDFLAGS
|
LDFLAGS=$_LDFLAGS
|
||||||
CFLAGS=$_CFLAGS
|
CFLAGS=$_CFLAGS
|
||||||
|
|
||||||
AC_RUN_IFELSE([
|
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
#if IS_WIN32
|
#if IS_WIN32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ftd2xx.h>
|
#include <ftd2xx.h>
|
||||||
|
]], [[
|
||||||
int
|
|
||||||
main( int argc, char **argv )
|
|
||||||
{
|
|
||||||
DWORD x;
|
DWORD x;
|
||||||
FT_GetLibraryVersion( &x );
|
FT_GetLibraryVersion( &x );
|
||||||
return 0;
|
]])], [
|
||||||
}
|
|
||||||
], [
|
|
||||||
AC_MSG_RESULT([Success!])
|
AC_MSG_RESULT([Success!])
|
||||||
], [
|
], [
|
||||||
AC_MSG_ERROR([Cannot build & run test program using ftd2xx.lib])
|
AC_MSG_ERROR([Cannot build & run test program using ftd2xx.lib])
|
||||||
@@ -913,15 +947,16 @@ main( int argc, char **argv )
|
|||||||
])
|
])
|
||||||
|
|
||||||
AC_MSG_CHECKING([for ftd2xx highspeed device support])
|
AC_MSG_CHECKING([for ftd2xx highspeed device support])
|
||||||
AC_COMPILE_IFELSE([
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
#if IS_WIN32
|
#if IS_WIN32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ftd2xx.h>
|
#include <ftd2xx.h>
|
||||||
|
|
||||||
DWORD x = FT_DEVICE_4232H;
|
DWORD x = FT_DEVICE_4232H;
|
||||||
], [
|
]], [])], [
|
||||||
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
|
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
|
||||||
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
|
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
|
||||||
build_ft2232_highspeed=yes
|
build_ft2232_highspeed=yes
|
||||||
@@ -953,13 +988,10 @@ if test $build_ft2232_libftdi = yes ; then
|
|||||||
LDFLAGS=$_LDFLAGS
|
LDFLAGS=$_LDFLAGS
|
||||||
CFLAGS=$_CFLAGS
|
CFLAGS=$_CFLAGS
|
||||||
|
|
||||||
AC_RUN_IFELSE([
|
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
|
]], [[
|
||||||
int
|
|
||||||
main( int argc, char **argv )
|
|
||||||
{
|
|
||||||
struct ftdi_context *p;
|
struct ftdi_context *p;
|
||||||
p = ftdi_new();
|
p = ftdi_new();
|
||||||
if( p != NULL ){
|
if( p != NULL ){
|
||||||
@@ -968,8 +1000,7 @@ main( int argc, char **argv )
|
|||||||
fprintf( stderr, "calling ftdi_new() failed\n");
|
fprintf( stderr, "calling ftdi_new() failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
]])], [
|
||||||
], [
|
|
||||||
AC_MSG_RESULT([Success])
|
AC_MSG_RESULT([Success])
|
||||||
], [
|
], [
|
||||||
AC_MSG_ERROR([Cannot build & run test program using libftdi])
|
AC_MSG_ERROR([Cannot build & run test program using libftdi])
|
||||||
@@ -978,11 +1009,12 @@ main( int argc, char **argv )
|
|||||||
])
|
])
|
||||||
|
|
||||||
AC_MSG_CHECKING([for libftdi highspeed device support])
|
AC_MSG_CHECKING([for libftdi highspeed device support])
|
||||||
AC_COMPILE_IFELSE([
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
|
]], [[
|
||||||
enum ftdi_chip_type x = TYPE_2232H;
|
enum ftdi_chip_type x = TYPE_2232H;
|
||||||
], [
|
]])], [
|
||||||
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
|
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
|
||||||
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
|
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
|
||||||
build_ft2232_highspeed=yes
|
build_ft2232_highspeed=yes
|
||||||
@@ -1003,7 +1035,7 @@ fi
|
|||||||
# check for usb.h when a driver will require it
|
# check for usb.h when a driver will require it
|
||||||
build_usb=no
|
build_usb=no
|
||||||
if test $build_jlink = yes -o $build_vsllink = yes -o $build_usbprog = yes -o \
|
if test $build_jlink = yes -o $build_vsllink = yes -o $build_usbprog = yes -o \
|
||||||
$build_rlink = yes -o $build_armjtagew = yes
|
$build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes
|
||||||
then
|
then
|
||||||
AC_CHECK_HEADERS([usb.h],[],
|
AC_CHECK_HEADERS([usb.h],[],
|
||||||
[AC_MSG_ERROR([usb.h is required to build some OpenOCD driver(s)])])
|
[AC_MSG_ERROR([usb.h is required to build some OpenOCD driver(s)])])
|
||||||
@@ -1017,8 +1049,8 @@ AM_CONDITIONAL(GIVEIO, test x$parport_use_giveio = xyes)
|
|||||||
AM_CONDITIONAL(EP93XX, test $build_ep93xx = yes)
|
AM_CONDITIONAL(EP93XX, test $build_ep93xx = yes)
|
||||||
AM_CONDITIONAL(ECOSBOARD, test $build_ecosboard = yes)
|
AM_CONDITIONAL(ECOSBOARD, test $build_ecosboard = yes)
|
||||||
AM_CONDITIONAL(ZY1000, test $build_zy1000 = yes)
|
AM_CONDITIONAL(ZY1000, test $build_zy1000 = yes)
|
||||||
|
AM_CONDITIONAL(ZY1000_MASTER, test $build_zy1000_master = yes)
|
||||||
AM_CONDITIONAL(IOUTIL, test $build_ioutil = yes)
|
AM_CONDITIONAL(IOUTIL, test $build_ioutil = yes)
|
||||||
AM_CONDITIONAL(HTTPD, test $build_httpd = yes)
|
|
||||||
AM_CONDITIONAL(AT91RM9200, test $build_at91rm9200 = yes)
|
AM_CONDITIONAL(AT91RM9200, test $build_at91rm9200 = yes)
|
||||||
AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
|
AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
|
||||||
AM_CONDITIONAL(FT2232_LIBFTDI, test $build_ft2232_libftdi = yes)
|
AM_CONDITIONAL(FT2232_LIBFTDI, test $build_ft2232_libftdi = yes)
|
||||||
@@ -1034,7 +1066,9 @@ AM_CONDITIONAL(OOCD_TRACE, test $build_oocd_trace = yes)
|
|||||||
AM_CONDITIONAL(JLINK, test $build_jlink = yes)
|
AM_CONDITIONAL(JLINK, test $build_jlink = yes)
|
||||||
AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
|
AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
|
||||||
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
|
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
|
||||||
|
AM_CONDITIONAL(ULINK, test $build_ulink = yes)
|
||||||
AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
|
AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
|
||||||
|
AM_CONDITIONAL(BUSPIRATE, test $build_buspirate = yes)
|
||||||
AM_CONDITIONAL(USB, test $build_usb = yes)
|
AM_CONDITIONAL(USB, test $build_usb = yes)
|
||||||
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
|
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
|
||||||
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
|
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
|
||||||
@@ -1045,14 +1079,16 @@ AM_CONDITIONAL(BITQ, test $build_bitq = yes)
|
|||||||
AM_CONDITIONAL(MINIDRIVER, test $build_minidriver = yes)
|
AM_CONDITIONAL(MINIDRIVER, test $build_minidriver = yes)
|
||||||
AM_CONDITIONAL(MINIDRIVER_DUMMY, test $build_minidriver_dummy = yes)
|
AM_CONDITIONAL(MINIDRIVER_DUMMY, test $build_minidriver_dummy = yes)
|
||||||
|
|
||||||
|
AM_CONDITIONAL(INTERNAL_JIMTCL, test $use_internal_jimtcl = yes)
|
||||||
|
|
||||||
# Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h?
|
# Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h?
|
||||||
AC_MSG_CHECKING([for environ in unistd.h and stdlib.h])
|
AC_MSG_CHECKING([for environ in unistd.h and stdlib.h])
|
||||||
AC_COMPILE_IFELSE([
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
int main(int argc, char **argv) { char **ep = environ; }
|
]], [[char **ep = environ;]]
|
||||||
], [
|
)], [
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
has_environ=yes
|
has_environ=yes
|
||||||
], [
|
], [
|
||||||
@@ -1060,10 +1096,10 @@ int main(int argc, char **argv) { char **ep = environ; }
|
|||||||
|
|
||||||
# Possibility #2: can environ be found in an available library?
|
# Possibility #2: can environ be found in an available library?
|
||||||
AC_MSG_CHECKING([for extern environ])
|
AC_MSG_CHECKING([for extern environ])
|
||||||
AC_LINK_IFELSE([
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
int main(int argc, char **argv) { char **ep = environ; }
|
]], [[char **ep = environ;]]
|
||||||
], [
|
)], [
|
||||||
AC_DEFINE(NEED_ENVIRON_EXTERN, [1], [Must declare 'environ' to use it.])
|
AC_DEFINE(NEED_ENVIRON_EXTERN, [1], [Must declare 'environ' to use it.])
|
||||||
has_environ=yes
|
has_environ=yes
|
||||||
], [
|
], [
|
||||||
@@ -1079,7 +1115,7 @@ fi
|
|||||||
AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).])
|
AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).])
|
||||||
|
|
||||||
# set default gcc warnings
|
# set default gcc warnings
|
||||||
GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security"
|
GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow"
|
||||||
if test "${gcc_wextra}" = yes; then
|
if test "${gcc_wextra}" = yes; then
|
||||||
GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter"
|
GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter"
|
||||||
GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast"
|
GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast"
|
||||||
@@ -1142,9 +1178,11 @@ AC_OUTPUT(dnl
|
|||||||
src/helper/Makefile dnl
|
src/helper/Makefile dnl
|
||||||
src/jtag/Makefile dnl
|
src/jtag/Makefile dnl
|
||||||
src/jtag/drivers/Makefile dnl
|
src/jtag/drivers/Makefile dnl
|
||||||
|
src/transport/Makefile dnl
|
||||||
src/xsvf/Makefile dnl
|
src/xsvf/Makefile dnl
|
||||||
src/svf/Makefile dnl
|
src/svf/Makefile dnl
|
||||||
src/target/Makefile dnl
|
src/target/Makefile dnl
|
||||||
|
src/rtos/Makefile dnl
|
||||||
src/server/Makefile dnl
|
src/server/Makefile dnl
|
||||||
src/flash/Makefile dnl
|
src/flash/Makefile dnl
|
||||||
src/flash/nor/Makefile dnl
|
src/flash/nor/Makefile dnl
|
||||||
|
|||||||
68
contrib/coresight-trace.txt
Normal file
68
contrib/coresight-trace.txt
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
+OpenOCD and CoreSight Tracing
|
||||||
|
+
|
||||||
|
Many recent ARM chips (Using e..g. Cortex-M3 and
|
||||||
|
Cortex-M4 cores) support CoreSight debug/trace.
|
||||||
|
This note sketches an approach currently planned for those cores
|
||||||
|
with OpenOCD.
|
||||||
|
|
||||||
|
This tracing data can help debug and tune ARM software, but not
|
||||||
|
all cores support tracing. Some support more extensive tracing
|
||||||
|
other cores with trace support +should be able to use the same
|
||||||
|
approach and maybe some of the same analysis code.
|
||||||
|
|
||||||
|
+the Cortex-M3 is assumed here to be the
|
||||||
|
+core in use, for simplicity and to reflect current OpenOCD users.
|
||||||
|
|
||||||
|
|
||||||
|
This note summarizes a software model to generate, collect, and
|
||||||
|
analyze such trace data . That is not fully implemented as of early
|
||||||
|
January 2011, +and thus is not *yet* usable.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+Some microcontroller cores support a low pin-count Single-wire trace,
|
||||||
|
with a mode where +trace data is emitted (usually to a UART. To use
|
||||||
|
this mode, +SWD must be in use.
|
||||||
|
+At this writing, OpenOCD SWD support is not yet complete either.
|
||||||
|
|
||||||
|
(There are also multi-wire trace ports requiring more complex debug
|
||||||
|
adapters than OpenOCD currently supports, and offering richer data.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+* ENABLING involves activating SWD and (single wire) trace.
|
||||||
|
+
|
||||||
|
+current expectations are that OpenOCD itself will handle enabling;
|
||||||
|
activating single wire trace involves a debug adapter interaction, and
|
||||||
|
collecting that trace data requires particular (re)wiring.
|
||||||
|
+
|
||||||
|
+* CONFIGURATION involves setting up ITM and/or ETM modules to emit the
|
||||||
|
+desired data from the Cortex core. (This might include dumping
|
||||||
|
+event counters printf-style messages; code profiling; and more. Not all
|
||||||
|
+cores offer the same trace capabilities.
|
||||||
|
+
|
||||||
|
+current expectations are that Tcl scripts will be used to configure these
|
||||||
|
+modules for the desired tracing, by direct writes to registers. In some
|
||||||
|
+cases (as with RTOS event tracking and similar messaging, this might
|
||||||
|
+be augmented or replaced by user code running on the ARM core.
|
||||||
|
+
|
||||||
|
+COLLECTION involves reading that trace data, probably through UART, and
|
||||||
|
+saving it in a useful format to analyse For now, deferred analysis modes
|
||||||
|
are assumed, not than real-time or interactive ones.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+current expectations are to to dump data in text using contrib/itmdump.c
|
||||||
|
+or derived tools, and to post-process it into reports. Such reports might
|
||||||
|
+include program messaging (such as application data streams via ITM, maybe
|
||||||
|
+using printf type messaging; code coverage analysis or so forth. Recent
|
||||||
|
+versions of CMSIS software reserve some ITM codespace for RTOS event
|
||||||
|
tracing and include ITM messaging support.
|
||||||
|
Clearly some of that data would be valuable for interactive debugging.
|
||||||
|
+
|
||||||
|
+Should someone get ambitious, GUI reports should be possible. GNU tools
|
||||||
|
+for simpler reports like gprof may be simpler to support at first.
|
||||||
|
+In any case, OpenOCD is not currently GUI-oriented. Accordingly, we now
|
||||||
|
+expect any such graphics to come from postprocessing.
|
||||||
|
|
||||||
|
measurments for RTOS event timings should also be easy to collect.
|
||||||
|
+Examples include context and message switch times, as well as times
|
||||||
|
for application interactions.
|
||||||
|
+
|
||||||
91
contrib/gen-stellaris-part-header.pl
Executable file
91
contrib/gen-stellaris-part-header.pl
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
# Automatically generates the StellarisParts struct in src/flash/nor/stellaris.c
|
||||||
|
# Uses the header files from TI/Luminary's StellarisWare complete Firmware Development Package
|
||||||
|
# available from: http://www.luminarymicro.com/products/software_updates.html
|
||||||
|
|
||||||
|
$comment = "// Autogenerated by contrib/gen-stellaris-part-header.pl
|
||||||
|
// From Stellaris Firmware Development Package revision";
|
||||||
|
|
||||||
|
$struct_header = "static struct {
|
||||||
|
uint32_t partno;
|
||||||
|
const char *partname;
|
||||||
|
} StellarisParts[] =
|
||||||
|
{
|
||||||
|
";
|
||||||
|
|
||||||
|
$struct_footer = "\t{0,\"Unknown part\"}\n};\n";
|
||||||
|
|
||||||
|
$#ARGV == 1 || die "Usage: $0 <inc directory> <output file>\n";
|
||||||
|
-d $ARGV[0] || die $ARGV[0]." is not a directory\n";
|
||||||
|
$dir = $ARGV[0];
|
||||||
|
-f $ARGV[1] || die $ARGV[1]." is not a file\n";
|
||||||
|
$file = $ARGV[1];
|
||||||
|
print STDERR "Scanning $dir, Updating $file\n";
|
||||||
|
|
||||||
|
opendir(DIR, $dir) || die "can't open $dir: $!";
|
||||||
|
@files = readdir(DIR);
|
||||||
|
closedir(DIR);
|
||||||
|
|
||||||
|
@short_files = sort(grep(/lm3s...\.h/, @files));
|
||||||
|
@long_files = sort(grep(/lm3s....\.h/, @files));
|
||||||
|
|
||||||
|
$ver = 0;
|
||||||
|
$new_struct = $struct_header;
|
||||||
|
process_file(@short_files);
|
||||||
|
process_file(@long_files);
|
||||||
|
$new_struct .= $struct_footer;
|
||||||
|
|
||||||
|
$dump = "$comment $ver\n$new_struct";
|
||||||
|
{
|
||||||
|
local($/, *INPUT);
|
||||||
|
open(INPUT, $file) || die "can't open $file: $!";
|
||||||
|
$contents = <INPUT>;
|
||||||
|
close(INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
$old_struct = qr/((^\/\/.*?\n)*)\Q$struct_header\E.*?$struct_footer/sm;
|
||||||
|
$contents =~ s/$old_struct/$dump/;
|
||||||
|
open(OUTPUT, ">$file") || die "can't open file $file for writing: $!";
|
||||||
|
print OUTPUT $contents;
|
||||||
|
close(OUTPUT);
|
||||||
|
|
||||||
|
sub process_file {
|
||||||
|
foreach $h_file (@_) {
|
||||||
|
($base) = ($h_file =~ m/lm3s(.{3,4})\.h/ig);
|
||||||
|
$base = uc($base);
|
||||||
|
local($/, *FILE);
|
||||||
|
open(FILE, "$dir/$h_file");
|
||||||
|
$content = <FILE>;
|
||||||
|
close(FILE);
|
||||||
|
$invalid = 0;
|
||||||
|
if ($content =~ /This is part of revision (\d+) of/) {
|
||||||
|
if ($ver != 0 and $ver != $1) {
|
||||||
|
print STDERR "File version mismatch: $ver != $1\n";
|
||||||
|
$ver = max($ver, $1);
|
||||||
|
} else {
|
||||||
|
$ver = $1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($content =~ /SYSCTL_DID1_VER_[^M]\s+0x(\S+)/) {
|
||||||
|
$did1_ver = hex($1);
|
||||||
|
} else {
|
||||||
|
print STDERR "$h_file is missing SYSCTL_DID1_VER\n";
|
||||||
|
$did1_ver = 255;
|
||||||
|
$invalid = 1;
|
||||||
|
}
|
||||||
|
if ($content =~ /SYSCTL_DID1_PRTNO_$base\s+0x(\S+)/) {
|
||||||
|
$prtno = hex($1);
|
||||||
|
} else {
|
||||||
|
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
|
||||||
|
$prtno = 0;
|
||||||
|
$invalid = 1;
|
||||||
|
}
|
||||||
|
$id = ($did1_ver | $prtno) >> 16;
|
||||||
|
$new_member = sprintf "{0x%04X,\"LM3S%s\"},", $id, $base;
|
||||||
|
if ($invalid == 1) {
|
||||||
|
#$new_struct .= "\t//$new_member\t// Invalid\n";
|
||||||
|
} else {
|
||||||
|
$new_struct .= "\t$new_member\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
441
contrib/itmdump.c
Normal file
441
contrib/itmdump.c
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple utility to parse and dump ARM Cortex-M3 SWO trace output. Once the
|
||||||
|
* mechanisms work right, this information can be used for various purposes
|
||||||
|
* including profiling (particularly easy for flat PC-sample profiles) and
|
||||||
|
* for debugging.
|
||||||
|
*
|
||||||
|
* SWO is the Single Wire Output found on some ARM cores, most notably on the
|
||||||
|
* Cortex-M3. It combines data from several sources:
|
||||||
|
*
|
||||||
|
* - Software trace (ITM): so-called "printf-style" application messaging
|
||||||
|
* using "ITM stimulus ports"; and differential timestamps.
|
||||||
|
* - Hardware trace (DWT): for profiling counters and comparator matches.
|
||||||
|
* - TPIU may issue sync packets.
|
||||||
|
*
|
||||||
|
* The trace data format is defined in Appendix E, "Debug ITM and DWT packet
|
||||||
|
* protocol", of the ARMv7-M Architecture Reference Manual (DDI 0403C). It
|
||||||
|
* is a superset of the ITM data format from the Coresight TRM.
|
||||||
|
*
|
||||||
|
* The trace data has two encodings. The working assumption is that data
|
||||||
|
* gets into this program using the UART encoding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
|
||||||
|
* on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
|
||||||
|
* WWXX: event code (0..3 pre-assigned, 4..15 reserved)
|
||||||
|
* YY: task priority
|
||||||
|
* ZZ: task number
|
||||||
|
*
|
||||||
|
* NOTE that this specific encoding could be space-optimized; and that
|
||||||
|
* trace data streams could also be history-sensitive.
|
||||||
|
*/
|
||||||
|
static void show_task(int port, unsigned data)
|
||||||
|
{
|
||||||
|
unsigned code = data >> 16;
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case 0:
|
||||||
|
strcpy(buf, "run");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strcpy(buf, "block");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strcpy(buf, "create");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
strcpy(buf, "destroy");
|
||||||
|
break;
|
||||||
|
/* 4..15 reserved for other infrastructure ops */
|
||||||
|
default:
|
||||||
|
sprintf(buf, "code %d", code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("TASK %d, pri %d: %s",
|
||||||
|
(data >> 0) & 0xff,
|
||||||
|
(data >> 8) & 0xff,
|
||||||
|
buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_reserved(FILE *f, char *label, int c)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
printf("%s - %#02x", label, c);
|
||||||
|
|
||||||
|
for (i = 0; (c & 0x80) && i < 4; i++) {
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF) {
|
||||||
|
printf("(ERROR %d - %s) ", errno, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf(" %#02x", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_varlen(FILE *f, int c, unsigned *value)
|
||||||
|
{
|
||||||
|
unsigned size;
|
||||||
|
unsigned char buf[4];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
*value = 0;
|
||||||
|
|
||||||
|
switch (c & 3) {
|
||||||
|
case 3:
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("INVALID SIZE\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof buf);
|
||||||
|
if (fread(buf, 1, size, f) != size)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
*value = (buf[3] << 24)
|
||||||
|
+ (buf[2] << 16)
|
||||||
|
+ (buf[2] << 8)
|
||||||
|
+ (buf[0] << 0);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
err:
|
||||||
|
printf("(ERROR %d - %s)\n", errno, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_hard(FILE *f, int c)
|
||||||
|
{
|
||||||
|
unsigned type = c >> 3;
|
||||||
|
unsigned value;
|
||||||
|
unsigned size;
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
printf("DWT - ", type);
|
||||||
|
|
||||||
|
if (!read_varlen(f, c, &value))
|
||||||
|
return;
|
||||||
|
printf("%#x", value);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0: /* event counter wrapping */
|
||||||
|
printf("overflow %s%s%s%s%s%s",
|
||||||
|
(value & (1 << 5)) ? "cyc " : "",
|
||||||
|
(value & (1 << 4)) ? "fold " : "",
|
||||||
|
(value & (1 << 3)) ? "lsu " : "",
|
||||||
|
(value & (1 << 2)) ? "slp " : "",
|
||||||
|
(value & (1 << 1)) ? "exc " : "",
|
||||||
|
(value & (1 << 0)) ? "cpi " : "");
|
||||||
|
break;
|
||||||
|
case 1: /* exception tracing */
|
||||||
|
switch (value >> 12) {
|
||||||
|
case 1:
|
||||||
|
label = "entry to";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
label = "exit from";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
label = "return to";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
label = "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%s exception %d", label, value & 0x1ff);
|
||||||
|
break;
|
||||||
|
case 2: /* PC sampling */
|
||||||
|
if (c == 0x15)
|
||||||
|
printf("PC - sleep");
|
||||||
|
else
|
||||||
|
printf("PC - %#08x", value);
|
||||||
|
break;
|
||||||
|
case 8: /* data tracing, pc value */
|
||||||
|
case 10:
|
||||||
|
case 12:
|
||||||
|
case 14:
|
||||||
|
printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
|
||||||
|
/* optionally followed by data value */
|
||||||
|
break;
|
||||||
|
case 9: /* data tracing, address offset */
|
||||||
|
case 11:
|
||||||
|
case 13:
|
||||||
|
case 15:
|
||||||
|
printf("Data trace %d, address offset %#04x",
|
||||||
|
(c >> 4) & 3, value);
|
||||||
|
/* always followed by data value */
|
||||||
|
break;
|
||||||
|
case 16 ... 23: /* data tracing, data value */
|
||||||
|
printf("Data trace %d, ", (c >> 4) & 3);
|
||||||
|
label = (c & 0x8) ? "write" : "read";
|
||||||
|
switch (c & 3) {
|
||||||
|
case 3:
|
||||||
|
printf("word %s, value %#08x", label, value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("halfword %s, value %#04x", label, value);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
printf("byte %s, value %#02x", label, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("UNDEFINED");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table of SWIT (SoftWare InstrumentTation) message dump formats, for
|
||||||
|
* ITM port 0..31 application data.
|
||||||
|
*
|
||||||
|
* Eventually this should be customizable; all usage is application defined.
|
||||||
|
*
|
||||||
|
* REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
int port;
|
||||||
|
void (*show)(int port, unsigned data);
|
||||||
|
} format[] = {
|
||||||
|
{ .port = 31, .show = show_task, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void show_swit(FILE *f, int c)
|
||||||
|
{
|
||||||
|
unsigned size;
|
||||||
|
unsigned port = c >> 3;
|
||||||
|
unsigned char buf[4];
|
||||||
|
unsigned value = 0;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
printf("SWIT %u - ", port);
|
||||||
|
|
||||||
|
if (!read_varlen(f, c, &value))
|
||||||
|
return;
|
||||||
|
printf("%#08x", value);
|
||||||
|
|
||||||
|
for (i = 0; i <= sizeof(format) / sizeof(format[0]); i++) {
|
||||||
|
if (format[i].port == port) {
|
||||||
|
printf(", ");
|
||||||
|
format[i].show(port, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
printf("(ERROR %d - %s)\n", errno, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_timestamp(FILE *f, int c)
|
||||||
|
{
|
||||||
|
unsigned counter = 0;
|
||||||
|
char *label = "";
|
||||||
|
bool delayed = false;
|
||||||
|
|
||||||
|
printf("TIMESTAMP - ");
|
||||||
|
|
||||||
|
/* Format 2: header only */
|
||||||
|
if (!(c & 0x80)) {
|
||||||
|
switch (c) {
|
||||||
|
case 0: /* sync packet -- coding error! */
|
||||||
|
case 0x70: /* overflow -- ditto! */
|
||||||
|
printf("ERROR - %#02x\n", c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* synchronous to ITM */
|
||||||
|
counter = c >> 4;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format 1: one to four bytes of data too */
|
||||||
|
switch (c) {
|
||||||
|
default:
|
||||||
|
label = ", reserved control\n";
|
||||||
|
break;
|
||||||
|
case 0xc:
|
||||||
|
/* synchronous to ITM */
|
||||||
|
break;
|
||||||
|
case 0xd:
|
||||||
|
label = ", timestamp delayed";
|
||||||
|
delayed = true;
|
||||||
|
break;
|
||||||
|
case 0xe:
|
||||||
|
label = ", packet delayed";
|
||||||
|
delayed = true;
|
||||||
|
break;
|
||||||
|
case 0xf:
|
||||||
|
label = ", packet and timetamp delayed";
|
||||||
|
delayed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
goto err;
|
||||||
|
counter = c & 0x7f;
|
||||||
|
if (!(c & 0x80))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
goto err;
|
||||||
|
counter |= (c & 0x7f) << 7;
|
||||||
|
if (!(c & 0x80))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
goto err;
|
||||||
|
counter |= (c & 0x7f) << 14;
|
||||||
|
if (!(c & 0x80))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
goto err;
|
||||||
|
counter |= (c & 0x7f) << 21;
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* REVISIT should we try to convert from delta values? */
|
||||||
|
printf("+%u%s\n", counter, label);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
printf("(ERROR %d - %s) ", errno, strerror(errno));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *f = stdin;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
/* parse arguments */
|
||||||
|
while ((c = getopt(argc, argv, "f:")) != EOF) {
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
/* e.g. from UART connected to /dev/ttyUSB0 */
|
||||||
|
f = fopen(optarg, "r");
|
||||||
|
if (!f) {
|
||||||
|
perror(optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage:
|
||||||
|
fprintf(stderr, "usage: %s [-f input]",
|
||||||
|
basename(argv[0]));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse data ... records have a header then data bytes.
|
||||||
|
* NOTE: we assume getc() deals in 8-bit bytes.
|
||||||
|
*/
|
||||||
|
bool overflow = false;
|
||||||
|
|
||||||
|
while ((c = getc(f)) != EOF) {
|
||||||
|
|
||||||
|
/* Sync packet ... 7 zeroes, 0x80 */
|
||||||
|
if (c == 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
if (c != 0)
|
||||||
|
goto bad_sync;
|
||||||
|
}
|
||||||
|
c = fgetc(f);
|
||||||
|
if (c == 0x80) {
|
||||||
|
printf("SYNC\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bad_sync:
|
||||||
|
printf("BAD SYNC\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overflow packet */
|
||||||
|
if (c == 0x70) {
|
||||||
|
/* REVISIT later, report just what overflowed!
|
||||||
|
* Timestamp and SWIT can happen. Non-ITM too?
|
||||||
|
*/
|
||||||
|
overflow = true;
|
||||||
|
printf("OVERFLOW ...\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
overflow = false;
|
||||||
|
|
||||||
|
switch (c & 0x0f) {
|
||||||
|
case 0x00: /* Timestamp */
|
||||||
|
show_timestamp(f, c);
|
||||||
|
break;
|
||||||
|
case 0x04: /* "Reserved" */
|
||||||
|
show_reserved(f, "RESERVED", c);
|
||||||
|
break;
|
||||||
|
case 0x08: /* ITM Extension */
|
||||||
|
/* FIXME someday, handle these ... */
|
||||||
|
show_reserved(f, "ITM EXT", c);
|
||||||
|
break;
|
||||||
|
case 0x0c: /* DWT Extension */
|
||||||
|
show_reserved(f, "DWT EXT", c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c & 4)
|
||||||
|
show_hard(f, c);
|
||||||
|
else
|
||||||
|
show_swit(f, c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
33
contrib/loaders/README
Normal file
33
contrib/loaders/README
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
Included in these directories are the src to the various ram loaders used
|
||||||
|
within openocd.
|
||||||
|
|
||||||
|
** target checksum loaders **
|
||||||
|
|
||||||
|
checksum/armv4_5_crc.s :
|
||||||
|
- ARMv4 and ARMv5 checksum loader : see target/arm_crc_code.c:arm_crc_code
|
||||||
|
|
||||||
|
checksum/armv7m_crc.s :
|
||||||
|
- ARMv7m checksum loader : see target/armv7m.c:cortex_m3_crc_code
|
||||||
|
|
||||||
|
checksum/mips32.s :
|
||||||
|
- MIPS32 checksum loader : see target/mips32.c:mips_crc_code
|
||||||
|
|
||||||
|
** target flash loaders **
|
||||||
|
|
||||||
|
flash/pic32mx.s :
|
||||||
|
- Microchip PIC32 flash loader : see flash/nor/pic32mx.c:pic32mx_flash_write_code
|
||||||
|
|
||||||
|
flash/stellaris.s :
|
||||||
|
- TI Stellaris flash loader : see flash/nor/stellaris.c:stellaris_write_code
|
||||||
|
|
||||||
|
flash/stm32x.s :
|
||||||
|
- ST STM32 flash loader : see flash/nor/stm32x.c:stm32x_flash_write_code
|
||||||
|
|
||||||
|
flash/str7x.s :
|
||||||
|
- ST STR7 flash loader : see flash/nor/str7x.c:str7x_flash_write_code
|
||||||
|
|
||||||
|
flash/str9x.s :
|
||||||
|
- ST STR9 flash loader : see flash/nor/str9x.c:str9x_flash_write_code
|
||||||
|
|
||||||
|
Spencer Oliver
|
||||||
|
spen@spen-soft.co.uk
|
||||||
58
contrib/loaders/checksum/armv4_5_crc.s
Normal file
58
contrib/loaders/checksum/armv4_5_crc.s
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
r0 - address in - crc out
|
||||||
|
r1 - char count
|
||||||
|
*/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
|
||||||
|
_start:
|
||||||
|
main:
|
||||||
|
mov r2, r0
|
||||||
|
mov r0, #0xffffffff /* crc */
|
||||||
|
mov r3, r1
|
||||||
|
mov r4, #0
|
||||||
|
b ncomp
|
||||||
|
nbyte:
|
||||||
|
ldrb r1, [r2, r4]
|
||||||
|
ldr r7, CRC32XOR
|
||||||
|
eor r0, r0, r1, asl #24
|
||||||
|
mov r5, #0
|
||||||
|
loop:
|
||||||
|
cmp r0, #0
|
||||||
|
mov r6, r0, asl #1
|
||||||
|
add r5, r5, #1
|
||||||
|
mov r0, r6
|
||||||
|
eorlt r0, r6, r7
|
||||||
|
cmp r5, #8
|
||||||
|
bne loop
|
||||||
|
add r4, r4, #1
|
||||||
|
ncomp:
|
||||||
|
cmp r4, r3
|
||||||
|
bne nbyte
|
||||||
|
end:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
CRC32XOR: .word 0x04c11db7
|
||||||
|
|
||||||
|
.end
|
||||||
66
contrib/loaders/checksum/armv7m_crc.s
Normal file
66
contrib/loaders/checksum/armv7m_crc.s
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
parameters:
|
||||||
|
r0 - address in - crc out
|
||||||
|
r1 - char count
|
||||||
|
*/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-m
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
_start:
|
||||||
|
main:
|
||||||
|
mov r2, r0
|
||||||
|
mov r0, #0xffffffff /* crc */
|
||||||
|
mov r3, r1
|
||||||
|
mov r4, #0
|
||||||
|
b ncomp
|
||||||
|
nbyte:
|
||||||
|
ldrb r1, [r2, r4]
|
||||||
|
|
||||||
|
ldr r7, CRC32XOR
|
||||||
|
eor r0, r0, r1, asl #24
|
||||||
|
mov r5, #0
|
||||||
|
loop:
|
||||||
|
cmp r0, #0
|
||||||
|
mov r6, r0, asl #1
|
||||||
|
add r5, r5, #1
|
||||||
|
mov r0, r6
|
||||||
|
it lt
|
||||||
|
eorlt r0, r6, r7
|
||||||
|
cmp r5, #8
|
||||||
|
bne loop
|
||||||
|
|
||||||
|
add r4, r4, #1
|
||||||
|
ncomp:
|
||||||
|
cmp r4, r3
|
||||||
|
bne nbyte
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
CRC32XOR: .word 0x04c11db7
|
||||||
|
|
||||||
|
.end
|
||||||
72
contrib/loaders/checksum/mips32.s
Normal file
72
contrib/loaders/checksum/mips32.s
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.global main
|
||||||
|
.text
|
||||||
|
.set noreorder
|
||||||
|
|
||||||
|
/* params:
|
||||||
|
* $a0 address in
|
||||||
|
* $a1 byte count
|
||||||
|
* vars
|
||||||
|
* $a0 crc
|
||||||
|
* $a1 crc data byte
|
||||||
|
* temps:
|
||||||
|
* t3 v0 a3 a2 t0 v1
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ent main
|
||||||
|
main:
|
||||||
|
addiu $t4, $a0, 0 /* address in */
|
||||||
|
addiu $t2, $a1, 0 /* count */
|
||||||
|
|
||||||
|
addiu $a0, $zero, 0xffffffff /* a0 crc - result */
|
||||||
|
|
||||||
|
beq $zero, $zero, ncomp
|
||||||
|
addiu $t3, $zero, 0 /* clear bytes read */
|
||||||
|
|
||||||
|
nbyte:
|
||||||
|
lb $a1, ($t4) /* load byte from source address */
|
||||||
|
addi $t4, $t4, 1 /* inc byte count */
|
||||||
|
|
||||||
|
crc:
|
||||||
|
sll $a1, $a1, 24
|
||||||
|
lui $v0, 0x04c1
|
||||||
|
xor $a0, $a0, $a1
|
||||||
|
ori $a3, $v0, 0x1db7
|
||||||
|
addu $a2, $zero, $zero /* clear bit count */
|
||||||
|
loop:
|
||||||
|
sll $t0, $a0, 1
|
||||||
|
addiu $a2, $a2, 1 /* inc bit count */
|
||||||
|
slti $a0, $a0, 0
|
||||||
|
xor $t1, $t0, $a3
|
||||||
|
movn $t0, $t1, $a0
|
||||||
|
slti $v1, $a2, 8 /* 8bits processed */
|
||||||
|
bne $v1, $zero, loop
|
||||||
|
addu $a0, $t0, $zero
|
||||||
|
|
||||||
|
ncomp:
|
||||||
|
bne $t2, $t3, nbyte /* all bytes processed */
|
||||||
|
addiu $t3, $t3, 1
|
||||||
|
|
||||||
|
wait:
|
||||||
|
sdbbp
|
||||||
|
|
||||||
|
.end main
|
||||||
57
contrib/loaders/flash/armv4_5_cfi_intel_16.s
Normal file
57
contrib/loaders/flash/armv4_5_cfi_intel_16.s
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* algorithm register usage:
|
||||||
|
* r0: source address (in RAM)
|
||||||
|
* r1: target address (in Flash)
|
||||||
|
* r2: count
|
||||||
|
* r3: flash write command
|
||||||
|
* r4: status byte (returned to host)
|
||||||
|
* r5: busy test pattern
|
||||||
|
* r6: error test pattern
|
||||||
|
*/
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldrh r4, [r0], #2
|
||||||
|
strh r3, [r1]
|
||||||
|
strh r4, [r1]
|
||||||
|
busy:
|
||||||
|
ldrh r4, [r1]
|
||||||
|
and r7, r4, r5
|
||||||
|
cmp r7, r5
|
||||||
|
bne busy
|
||||||
|
tst r4, r6
|
||||||
|
bne done
|
||||||
|
subs r2, r2, #1
|
||||||
|
beq done
|
||||||
|
add r1, r1, #2
|
||||||
|
b loop
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
57
contrib/loaders/flash/armv4_5_cfi_intel_32.s
Normal file
57
contrib/loaders/flash/armv4_5_cfi_intel_32.s
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* algorithm register usage:
|
||||||
|
* r0: source address (in RAM)
|
||||||
|
* r1: target address (in Flash)
|
||||||
|
* r2: count
|
||||||
|
* r3: flash write command
|
||||||
|
* r4: status byte (returned to host)
|
||||||
|
* r5: busy test pattern
|
||||||
|
* r6: error test pattern
|
||||||
|
*/
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldr r4, [r0], #4
|
||||||
|
str r3, [r1]
|
||||||
|
str r4, [r1]
|
||||||
|
busy:
|
||||||
|
ldr r4, [r1]
|
||||||
|
and r7, r4, r5
|
||||||
|
cmp r7, r5
|
||||||
|
bne busy
|
||||||
|
tst r4, r6
|
||||||
|
bne done
|
||||||
|
subs r2, r2, #1
|
||||||
|
beq done
|
||||||
|
add r1, r1, #4
|
||||||
|
b loop
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
57
contrib/loaders/flash/armv4_5_cfi_intel_8.s
Normal file
57
contrib/loaders/flash/armv4_5_cfi_intel_8.s
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* algorithm register usage:
|
||||||
|
* r0: source address (in RAM)
|
||||||
|
* r1: target address (in Flash)
|
||||||
|
* r2: count
|
||||||
|
* r3: flash write command
|
||||||
|
* r4: status byte (returned to host)
|
||||||
|
* r5: busy test pattern
|
||||||
|
* r6: error test pattern
|
||||||
|
*/
|
||||||
|
|
||||||
|
loop:
|
||||||
|
ldrb r4, [r0], #1
|
||||||
|
strb r3, [r1]
|
||||||
|
strb r4, [r1]
|
||||||
|
busy:
|
||||||
|
ldrb r4, [r1]
|
||||||
|
and r7, r4, r5
|
||||||
|
cmp r7, r5
|
||||||
|
bne busy
|
||||||
|
tst r4, r6
|
||||||
|
bne done
|
||||||
|
subs r2, r2, #1
|
||||||
|
beq done
|
||||||
|
add r1, r1, #1
|
||||||
|
b loop
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2005 by Dominic Rath *
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
* Dominic.Rath@gmx.de *
|
* Dominic.Rath@gmx.de *
|
||||||
* *
|
* Copyright (C) 2010 Spencer Oliver *
|
||||||
* LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
|
* spen@spen-soft.co.uk *
|
||||||
* didele.deze@gmail.com *
|
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -20,52 +19,57 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#ifndef LPC2000_H
|
|
||||||
#define LPC2000_H
|
|
||||||
|
|
||||||
typedef enum
|
.text
|
||||||
{
|
.arm
|
||||||
lpc2000_v1,
|
.arch armv4
|
||||||
lpc2000_v2,
|
|
||||||
lpc1700
|
|
||||||
} lpc2000_variant;
|
|
||||||
|
|
||||||
struct lpc2000_flash_bank
|
.section .init
|
||||||
{
|
|
||||||
lpc2000_variant variant;
|
|
||||||
struct working_area *iap_working_area;
|
|
||||||
uint32_t cclk;
|
|
||||||
int cmd51_dst_boundary;
|
|
||||||
int cmd51_can_256b;
|
|
||||||
int cmd51_can_8192b;
|
|
||||||
int calc_checksum;
|
|
||||||
uint32_t cmd51_max_buffer;
|
|
||||||
int checksum_vector;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum lpc2000_status_codes
|
/* input parameters - */
|
||||||
{
|
/* R0 = source address */
|
||||||
LPC2000_CMD_SUCCESS = 0,
|
/* R1 = destination address */
|
||||||
LPC2000_INVALID_COMMAND = 1,
|
/* R2 = number of writes */
|
||||||
LPC2000_SRC_ADDR_ERROR = 2,
|
/* R3 = flash write command */
|
||||||
LPC2000_DST_ADDR_ERROR = 3,
|
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
|
||||||
LPC2000_SRC_ADDR_NOT_MAPPED = 4,
|
/* output parameters - */
|
||||||
LPC2000_DST_ADDR_NOT_MAPPED = 5,
|
/* R5 = 0x80 ok 0x00 bad */
|
||||||
LPC2000_COUNT_ERROR = 6,
|
/* temp registers - */
|
||||||
LPC2000_INVALID_SECTOR = 7,
|
/* R6 = value read from flash to test status */
|
||||||
LPC2000_SECTOR_NOT_BLANK = 8,
|
/* R7 = holding register */
|
||||||
LPC2000_SECTOR_NOT_PREPARED = 9,
|
/* unlock registers - */
|
||||||
LPC2000_COMPARE_ERROR = 10,
|
/* R8 = unlock1_addr */
|
||||||
LPC2000_BUSY = 11,
|
/* R9 = unlock1_cmd */
|
||||||
LPC2000_PARAM_ERROR = 12,
|
/* R10 = unlock2_addr */
|
||||||
LPC2000_ADDR_ERROR = 13,
|
/* R11 = unlock2_cmd */
|
||||||
LPC2000_ADDR_NOT_MAPPED = 14,
|
|
||||||
LPC2000_CMD_NOT_LOCKED = 15,
|
|
||||||
LPC2000_INVALID_CODE = 16,
|
|
||||||
LPC2000_INVALID_BAUD_RATE = 17,
|
|
||||||
LPC2000_INVALID_STOP_BIT = 18,
|
|
||||||
LPC2000_CRP_ENABLED = 19
|
|
||||||
|
|
||||||
};
|
code:
|
||||||
|
ldrh r5, [r0], #2
|
||||||
|
strh r9, [r8]
|
||||||
|
strh r11, [r10]
|
||||||
|
strh r3, [r8]
|
||||||
|
strh r5, [r1]
|
||||||
|
nop
|
||||||
|
busy:
|
||||||
|
ldrh r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
ands r6, r6, r4, lsr #2
|
||||||
|
beq busy /* b if DQ5 low */
|
||||||
|
ldrh r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
mov r5, #0 /* 0x0 - return 0x00, error */
|
||||||
|
bne done
|
||||||
|
cont:
|
||||||
|
subs r2, r2, #1 /* 0x1 */
|
||||||
|
moveq r5, #128 /* 0x80 */
|
||||||
|
beq done
|
||||||
|
add r1, r1, #2 /* 0x2 */
|
||||||
|
b code
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
#endif /* LPC2000_H */
|
.end
|
||||||
66
contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s
Normal file
66
contrib/loaders/flash/armv4_5_cfi_span_16_dq7.s
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* input parameters - */
|
||||||
|
/* R0 = source address */
|
||||||
|
/* R1 = destination address */
|
||||||
|
/* R2 = number of writes */
|
||||||
|
/* R3 = flash write command */
|
||||||
|
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
|
||||||
|
/* output parameters - */
|
||||||
|
/* R5 = 0x80 ok 0x00 bad */
|
||||||
|
/* temp registers - */
|
||||||
|
/* R6 = value read from flash to test status */
|
||||||
|
/* R7 = holding register */
|
||||||
|
/* unlock registers - */
|
||||||
|
/* R8 = unlock1_addr */
|
||||||
|
/* R9 = unlock1_cmd */
|
||||||
|
/* R10 = unlock2_addr */
|
||||||
|
/* R11 = unlock2_cmd */
|
||||||
|
|
||||||
|
code:
|
||||||
|
ldrh r5, [r0], #2
|
||||||
|
strh r9, [r8]
|
||||||
|
strh r11, [r10]
|
||||||
|
strh r3, [r8]
|
||||||
|
strh r5, [r1]
|
||||||
|
nop
|
||||||
|
busy:
|
||||||
|
ldrh r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, #0x80
|
||||||
|
bne busy
|
||||||
|
subs r2, r2, #1 /* 0x1 */
|
||||||
|
moveq r5, #128 /* 0x80 */
|
||||||
|
beq done
|
||||||
|
add r1, r1, #2 /* 0x2 */
|
||||||
|
b code
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
75
contrib/loaders/flash/armv4_5_cfi_span_32.s
Normal file
75
contrib/loaders/flash/armv4_5_cfi_span_32.s
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* input parameters - */
|
||||||
|
/* R0 = source address */
|
||||||
|
/* R1 = destination address */
|
||||||
|
/* R2 = number of writes */
|
||||||
|
/* R3 = flash write command */
|
||||||
|
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
|
||||||
|
/* output parameters - */
|
||||||
|
/* R5 = 0x80 ok 0x00 bad */
|
||||||
|
/* temp registers - */
|
||||||
|
/* R6 = value read from flash to test status */
|
||||||
|
/* R7 = holding register */
|
||||||
|
/* unlock registers - */
|
||||||
|
/* R8 = unlock1_addr */
|
||||||
|
/* R9 = unlock1_cmd */
|
||||||
|
/* R10 = unlock2_addr */
|
||||||
|
/* R11 = unlock2_cmd */
|
||||||
|
|
||||||
|
code:
|
||||||
|
ldr r5, [r0], #4
|
||||||
|
str r9, [r8]
|
||||||
|
str r11, [r10]
|
||||||
|
str r3, [r8]
|
||||||
|
str r5, [r1]
|
||||||
|
nop
|
||||||
|
busy:
|
||||||
|
ldr r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
ands r6, r6, r4, lsr #2
|
||||||
|
beq busy /* b if DQ5 low */
|
||||||
|
ldr r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
mov r5, #0 /* 0x0 - return 0x00, error */
|
||||||
|
bne done
|
||||||
|
cont:
|
||||||
|
subs r2, r2, #1 /* 0x1 */
|
||||||
|
moveq r5, #128 /* 0x80 */
|
||||||
|
beq done
|
||||||
|
add r1, r1, #4 /* 0x4 */
|
||||||
|
b code
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
75
contrib/loaders/flash/armv4_5_cfi_span_8.s
Normal file
75
contrib/loaders/flash/armv4_5_cfi_span_8.s
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
|
||||||
|
/* input parameters - */
|
||||||
|
/* R0 = source address */
|
||||||
|
/* R1 = destination address */
|
||||||
|
/* R2 = number of writes */
|
||||||
|
/* R3 = flash write command */
|
||||||
|
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
|
||||||
|
/* output parameters - */
|
||||||
|
/* R5 = 0x80 ok 0x00 bad */
|
||||||
|
/* temp registers - */
|
||||||
|
/* R6 = value read from flash to test status */
|
||||||
|
/* R7 = holding register */
|
||||||
|
/* unlock registers - */
|
||||||
|
/* R8 = unlock1_addr */
|
||||||
|
/* R9 = unlock1_cmd */
|
||||||
|
/* R10 = unlock2_addr */
|
||||||
|
/* R11 = unlock2_cmd */
|
||||||
|
|
||||||
|
code:
|
||||||
|
ldrb r5, [r0], #1
|
||||||
|
strb r9, [r8]
|
||||||
|
strb r11, [r10]
|
||||||
|
strb r3, [r8]
|
||||||
|
strb r5, [r1]
|
||||||
|
nop
|
||||||
|
busy:
|
||||||
|
ldrb r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
ands r6, r6, r4, lsr #2
|
||||||
|
beq busy /* b if DQ5 low */
|
||||||
|
ldrb r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
mov r5, #0 /* 0x0 - return 0x00, error */
|
||||||
|
bne done
|
||||||
|
cont:
|
||||||
|
subs r2, r2, #1 /* 0x1 */
|
||||||
|
moveq r5, #128 /* 0x80 */
|
||||||
|
beq done
|
||||||
|
add r1, r1, #1 /* 0x1 */
|
||||||
|
b code
|
||||||
|
done:
|
||||||
|
b done
|
||||||
|
|
||||||
|
.end
|
||||||
81
contrib/loaders/flash/armv7m_cfi_span_16.s
Normal file
81
contrib/loaders/flash/armv7m_cfi_span_16.s
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005, 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* Copyright (C) 2010 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.arch armv7-m
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
/* input parameters - */
|
||||||
|
/* R0 = source address */
|
||||||
|
/* R1 = destination address */
|
||||||
|
/* R2 = number of writes */
|
||||||
|
/* R3 = flash write command */
|
||||||
|
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
|
||||||
|
/* output parameters - */
|
||||||
|
/* R5 = 0x80 ok 0x00 bad */
|
||||||
|
/* temp registers - */
|
||||||
|
/* R6 = value read from flash to test status */
|
||||||
|
/* R7 = holding register */
|
||||||
|
/* unlock registers - */
|
||||||
|
/* R8 = unlock1_addr */
|
||||||
|
/* R9 = unlock1_cmd */
|
||||||
|
/* R10 = unlock2_addr */
|
||||||
|
/* R11 = unlock2_cmd */
|
||||||
|
|
||||||
|
code:
|
||||||
|
ldrh r5, [r0], #2
|
||||||
|
strh r9, [r8]
|
||||||
|
strh r11, [r10]
|
||||||
|
strh r3, [r8]
|
||||||
|
strh r5, [r1]
|
||||||
|
nop
|
||||||
|
busy:
|
||||||
|
ldrh r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
ands r6, r6, r4, lsr #2
|
||||||
|
beq busy /* b if DQ5 low */
|
||||||
|
ldrh r6, [r1]
|
||||||
|
eor r7, r5, r6
|
||||||
|
ands r7, r4, r7
|
||||||
|
beq cont /* b if DQ7 == Data7 */
|
||||||
|
mov r5, #0 /* 0x0 - return 0x00, error */
|
||||||
|
bne done
|
||||||
|
cont:
|
||||||
|
subs r2, r2, #1 /* 0x1 */
|
||||||
|
beq success
|
||||||
|
add r1, r1, #2 /* 0x2 */
|
||||||
|
b code
|
||||||
|
|
||||||
|
success:
|
||||||
|
mov r5, #128 /* 0x80 */
|
||||||
|
b done
|
||||||
|
|
||||||
|
done:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.end
|
||||||
132
contrib/loaders/flash/pic32mx.s
Normal file
132
contrib/loaders/flash/pic32mx.s
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arch m4k
|
||||||
|
.set noreorder
|
||||||
|
.set noat
|
||||||
|
|
||||||
|
/* params:
|
||||||
|
* $a0 src adr - ram + result
|
||||||
|
* $a1 dest adr - flash
|
||||||
|
* $a2 count (32bit words)
|
||||||
|
* vars
|
||||||
|
*
|
||||||
|
* temps:
|
||||||
|
* $t0, $t1, $t2, $t3, $t4, $t5
|
||||||
|
* $s0, $s1, $s3, $s4, $s5
|
||||||
|
*/
|
||||||
|
|
||||||
|
.type main, @function
|
||||||
|
.global main
|
||||||
|
|
||||||
|
.ent main
|
||||||
|
main:
|
||||||
|
/* setup constants */
|
||||||
|
lui $t0, 0xaa99
|
||||||
|
ori $t0, 0x6655 /* NVMKEY1 */
|
||||||
|
lui $t1, 0x5566
|
||||||
|
ori $t1, 0x99AA /* NVMKEY2 */
|
||||||
|
lui $t2, 0xBF80
|
||||||
|
ori $t2, 0xF400 /* NVMCON */
|
||||||
|
ori $t3, $zero, 0x4003 /* NVMCON row write cmd */
|
||||||
|
ori $t4, $zero, 0x8000 /* NVMCON start cmd */
|
||||||
|
|
||||||
|
write_row:
|
||||||
|
/* can we perform a row write: 128 32bit words */
|
||||||
|
sltiu $s3, $a2, 128
|
||||||
|
bne $s3, $zero, write_word
|
||||||
|
ori $t5, $zero, 0x4000 /* NVMCON clear cmd */
|
||||||
|
|
||||||
|
/* perform row write 512 bytes */
|
||||||
|
sw $a1, 32($t2) /* set NVMADDR with dest addr - real addr */
|
||||||
|
sw $a0, 64($t2) /* set NVMSRCADDR with src addr - real addr */
|
||||||
|
|
||||||
|
bal progflash
|
||||||
|
addiu $a0, $a0, 512
|
||||||
|
addiu $a1, $a1, 512
|
||||||
|
beq $zero, $zero, write_row
|
||||||
|
addiu $a2, $a2, -128
|
||||||
|
|
||||||
|
write_word:
|
||||||
|
/* write 32bit words */
|
||||||
|
lui $s5, 0xa000
|
||||||
|
ori $s5, 0x0000
|
||||||
|
or $a0, $a0, $s5 /* convert to virtual addr */
|
||||||
|
|
||||||
|
beq $zero, $zero, next_word
|
||||||
|
ori $t3, $zero, 0x4001 /* NVMCON word write cmd */
|
||||||
|
|
||||||
|
prog_word:
|
||||||
|
lw $s4, 0($a0) /* load data - from virtual addr */
|
||||||
|
sw $s4, 48($t2) /* set NVMDATA with data */
|
||||||
|
sw $a1, 32($t2) /* set NVMADDR with dest addr - real addr */
|
||||||
|
|
||||||
|
bal progflash
|
||||||
|
addiu $a0, $a0, 4
|
||||||
|
addiu $a1, $a1, 4
|
||||||
|
addiu $a2, $a2, -1
|
||||||
|
next_word:
|
||||||
|
bne $a2, $zero, prog_word
|
||||||
|
nop
|
||||||
|
|
||||||
|
done:
|
||||||
|
beq $zero, $zero, exit
|
||||||
|
addiu $a0, $zero, 0
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* save result to $a0 */
|
||||||
|
addiu $a0, $s1, 0
|
||||||
|
|
||||||
|
exit:
|
||||||
|
sdbbp
|
||||||
|
.end main
|
||||||
|
|
||||||
|
.type progflash, @function
|
||||||
|
.global progflash
|
||||||
|
|
||||||
|
.ent progflash
|
||||||
|
progflash:
|
||||||
|
sw $t3, 0($t2) /* set NVMWREN */
|
||||||
|
sw $t0, 16($t2) /* write NVMKEY1 */
|
||||||
|
sw $t1, 16($t2) /* write NVMKEY2 */
|
||||||
|
sw $t4, 8($t2) /* start operation */
|
||||||
|
|
||||||
|
waitflash:
|
||||||
|
lw $s0, 0($t2)
|
||||||
|
and $s0, $s0, $t4
|
||||||
|
bne $s0, $zero, waitflash
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* following is to comply with errata #34
|
||||||
|
* 500ns delay required */
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
/* check for errors */
|
||||||
|
lw $s1, 0($t2)
|
||||||
|
andi $s1, $zero, 0x3000
|
||||||
|
bne $s1, $zero, error
|
||||||
|
sw $t5, 4($t2) /* clear NVMWREN */
|
||||||
|
jr $ra
|
||||||
|
nop
|
||||||
|
|
||||||
|
.end progflash
|
||||||
66
contrib/loaders/flash/stellaris.s
Normal file
66
contrib/loaders/flash/stellaris.s
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Magnus Lundin *
|
||||||
|
* lundin@mlu.mine.nu *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m3
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
Call with :
|
||||||
|
r0 = buffer address
|
||||||
|
r1 = destination address
|
||||||
|
r2 = bytecount (in) - endaddr (work)
|
||||||
|
|
||||||
|
Used registers:
|
||||||
|
r3 = pFLASH_CTRL_BASE
|
||||||
|
r4 = FLASHWRITECMD
|
||||||
|
r5 = #1
|
||||||
|
r6 = bytes written
|
||||||
|
r7 = temp reg
|
||||||
|
*/
|
||||||
|
|
||||||
|
write:
|
||||||
|
ldr r3,pFLASH_CTRL_BASE
|
||||||
|
ldr r4,FLASHWRITECMD
|
||||||
|
movs r5, 1
|
||||||
|
movs r6, #0
|
||||||
|
mainloop:
|
||||||
|
str r1, [r3, #0]
|
||||||
|
ldr r7, [r0, r6]
|
||||||
|
str r7, [r3, #4]
|
||||||
|
str r4, [r3, #8]
|
||||||
|
waitloop:
|
||||||
|
ldr r7, [r3, #8]
|
||||||
|
tst r7, r5
|
||||||
|
bne waitloop
|
||||||
|
adds r1, r1, #4
|
||||||
|
adds r6, r6, #4
|
||||||
|
cmp r6, r2
|
||||||
|
bne mainloop
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
pFLASH_CTRL_BASE: .word 0x400FD000
|
||||||
|
FLASHWRITECMD: .word 0xA4420001
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2005 by Dominic Rath *
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
* Dominic.Rath@gmx.de *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2008 by Spencer Oliver *
|
|
||||||
* spen@spen-soft.co.uk *
|
* spen@spen-soft.co.uk *
|
||||||
* *
|
* *
|
||||||
|
* Copyright (C) 2011 Øyvind Harboe *
|
||||||
|
* oyvind.harboe@zylin.com *
|
||||||
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
@@ -20,58 +20,44 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#ifndef STR9XPEC_H
|
|
||||||
#define STR9XPEC_H
|
|
||||||
|
|
||||||
|
|
||||||
struct str9xpec_flash_controller
|
// Build : arm-eabi-gcc -c stm32f2xxx.S
|
||||||
{
|
.text
|
||||||
struct jtag_tap *tap;
|
.syntax unified
|
||||||
uint32_t *sector_bits;
|
.cpu cortex-m3
|
||||||
int chain_pos;
|
.thumb
|
||||||
int isc_enable;
|
.thumb_func
|
||||||
uint8_t options[8];
|
.global write
|
||||||
};
|
|
||||||
|
|
||||||
enum str9xpec_status_codes
|
/*
|
||||||
{
|
r0 - source address
|
||||||
STR9XPEC_INVALID_COMMAND = 1,
|
r1 - target address
|
||||||
STR9XPEC_ISC_SUCCESS = 2,
|
r2 - count (halfword-16bit)
|
||||||
STR9XPEC_ISC_DISABLED = 3,
|
r3 - result out
|
||||||
STR9XPEC_ISC_INTFAIL = 32,
|
r4 - flash base
|
||||||
};
|
*/
|
||||||
|
|
||||||
/* ISC commands */
|
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
||||||
|
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
||||||
|
|
||||||
#define ISC_IDCODE 0xFE
|
write:
|
||||||
#define ISC_MFG_READ 0x4C
|
|
||||||
#define ISC_CONFIGURATION 0x07
|
|
||||||
#define ISC_ENABLE 0x0C
|
|
||||||
#define ISC_DISABLE 0x0F
|
|
||||||
#define ISC_NOOP 0x10
|
|
||||||
#define ISC_ADDRESS_SHIFT 0x11
|
|
||||||
#define ISC_CLR_STATUS 0x13
|
|
||||||
#define ISC_PROGRAM 0x20
|
|
||||||
#define ISC_PROGRAM_SECURITY 0x22
|
|
||||||
#define ISC_PROGRAM_UC 0x23
|
|
||||||
#define ISC_ERASE 0x30
|
|
||||||
#define ISC_READ 0x50
|
|
||||||
#define ISC_BLANK_CHECK 0x60
|
|
||||||
|
|
||||||
/* ISC_DEFAULT bit definitions */
|
write_half_word:
|
||||||
|
ldr r3, STM32_PROG16
|
||||||
|
str r3, [r4, #STM32_FLASH_CR_OFFSET]
|
||||||
|
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
|
||||||
|
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
|
||||||
|
busy:
|
||||||
|
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
|
||||||
|
tst r3, #0x10000 /* BSY (bit0) == 1 => operation in progress */
|
||||||
|
beq busy /* wait more... */
|
||||||
|
tst r3, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */
|
||||||
|
bne exit /* fail... */
|
||||||
|
subs r2, r2, #0x01 /* decrement counter */
|
||||||
|
bne write_half_word /* write next half-word if anything left */
|
||||||
|
exit:
|
||||||
|
bkpt #0x00
|
||||||
|
|
||||||
#define ISC_STATUS_SECURITY 0x40
|
|
||||||
#define ISC_STATUS_INT_ERROR 0x30
|
|
||||||
#define ISC_STATUS_MODE 0x08
|
|
||||||
#define ISC_STATUS_BUSY 0x04
|
|
||||||
#define ISC_STATUS_ERROR 0x03
|
|
||||||
|
|
||||||
/* Option bytes definitions */
|
STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/
|
||||||
|
|
||||||
#define STR9XPEC_OPT_CSMAPBIT 48
|
|
||||||
#define STR9XPEC_OPT_LVDTHRESBIT 49
|
|
||||||
#define STR9XPEC_OPT_LVDSELBIT 50
|
|
||||||
#define STR9XPEC_OPT_LVDWARNBIT 51
|
|
||||||
#define STR9XPEC_OPT_OTPBIT 63
|
|
||||||
|
|
||||||
#endif /* STR9XPEC_H */
|
|
||||||
58
contrib/loaders/flash/stm32x.S
Normal file
58
contrib/loaders/flash/stm32x.S
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
.cpu cortex-m3
|
||||||
|
.thumb
|
||||||
|
.thumb_func
|
||||||
|
.global write
|
||||||
|
|
||||||
|
/*
|
||||||
|
r0 - source address
|
||||||
|
r1 - target address
|
||||||
|
r2 - count (halfword-16bit)
|
||||||
|
r3 - sector offet in : result out
|
||||||
|
r4 - flash base
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
|
||||||
|
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
|
||||||
|
|
||||||
|
write:
|
||||||
|
ldr r4, STM32_FLASH_BASE
|
||||||
|
add r4, r3 /* add offset 0x00 for sector 0 : 0x40 for sector 1 */
|
||||||
|
write_half_word:
|
||||||
|
movs r3, #0x01
|
||||||
|
str r3, [r4, #STM32_FLASH_CR_OFFSET] /* PG (bit0) == 1 => flash programming enabled */
|
||||||
|
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
|
||||||
|
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
|
||||||
|
busy:
|
||||||
|
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
|
||||||
|
tst r3, #0x01 /* BSY (bit0) == 1 => operation in progress */
|
||||||
|
beq busy /* wait more... */
|
||||||
|
tst r3, #0x14 /* PGERR (bit2) == 1 or WRPRTERR (bit4) == 1 => error */
|
||||||
|
bne exit /* fail... */
|
||||||
|
subs r2, r2, #0x01 /* decrement counter */
|
||||||
|
bne write_half_word /* write next half-word if anything left */
|
||||||
|
exit:
|
||||||
|
bkpt #0x00
|
||||||
|
|
||||||
|
STM32_FLASH_BASE: .word 0x40022000 /* base address of FLASH struct */
|
||||||
59
contrib/loaders/flash/str7x.s
Normal file
59
contrib/loaders/flash/str7x.s
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv4t
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
/*
|
||||||
|
r0 source address
|
||||||
|
r1 address
|
||||||
|
r2 FLASH_CR0
|
||||||
|
r3 dword count
|
||||||
|
r4 result
|
||||||
|
r5 busy mask
|
||||||
|
*/
|
||||||
|
|
||||||
|
write:
|
||||||
|
mov r4, #0x10000000 /* set DWPG bit */
|
||||||
|
str r4, [r2, #0x0] /* FLASH_CR0 */
|
||||||
|
str r1, [r2, #0x10] /* FLASH_AR */
|
||||||
|
ldr r4, [r0], #4 /* load data */
|
||||||
|
str r4, [r2, #0x8] /* FLASH_DR0 */
|
||||||
|
ldr r4, [r0], #4 /* load data */
|
||||||
|
str r4, [r2, #0xc] /* FLASH_DR1 */
|
||||||
|
mov r4, #0x90000000 /* set DWPG and WMS bits */
|
||||||
|
str r4, [r2, #0x0] /* FLASH_CR0 */
|
||||||
|
busy:
|
||||||
|
ldr r4, [r2, #0x0] /* FLASH_CR0 */
|
||||||
|
tst r4, r5
|
||||||
|
bne busy
|
||||||
|
ldr r4, [r2, #0x14] /* FLASH_ER */
|
||||||
|
tst r4, #0xff /* do we have errors */
|
||||||
|
tsteq r4, #0x100 /* write protection set */
|
||||||
|
bne exit
|
||||||
|
add r1, r1, #0x8 /* next 8 bytes */
|
||||||
|
subs r3, r3, #1 /* decremment dword count */
|
||||||
|
bne write
|
||||||
|
exit:
|
||||||
|
b exit
|
||||||
|
|
||||||
|
.end
|
||||||
56
contrib/loaders/flash/str9x.s
Normal file
56
contrib/loaders/flash/str9x.s
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.arch armv5t
|
||||||
|
|
||||||
|
.section .init
|
||||||
|
/*
|
||||||
|
r0 source address (in)
|
||||||
|
r1 target address (in)
|
||||||
|
r2 word count (in)
|
||||||
|
r3 result (out)
|
||||||
|
*/
|
||||||
|
|
||||||
|
write:
|
||||||
|
bic r4, r1, #3 /* word address */
|
||||||
|
mov r3, #0x40 /* write command */
|
||||||
|
strh r3, [r4, #0]
|
||||||
|
ldrh r3, [r0], #2 /* read data */
|
||||||
|
strh r3, [r1], #2 /* write data */
|
||||||
|
mov r3, #0x70 /* status command */
|
||||||
|
strh r3, [r4, #0]
|
||||||
|
busy:
|
||||||
|
ldrb r3, [r4, #0] /* status */
|
||||||
|
tst r3, #0x80
|
||||||
|
beq busy
|
||||||
|
mov r5, #0x50 /* clear status command */
|
||||||
|
strh r5, [r4, #0]
|
||||||
|
mov r5, #0xFF /* read array */
|
||||||
|
strh r5, [r4, #0]
|
||||||
|
tst r3, #0x12
|
||||||
|
bne exit
|
||||||
|
subs r2, r2, #1 /* decremment word count */
|
||||||
|
bne write
|
||||||
|
exit:
|
||||||
|
bkpt #0
|
||||||
|
|
||||||
|
.end
|
||||||
@@ -64,5 +64,8 @@ ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
|
|||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="664", GROUP="plugdev"
|
||||||
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
|
# Hilscher NXHX Boards
|
||||||
|
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="664", GROUP="plugdev"
|
||||||
|
|
||||||
LABEL="openocd_rules_end"
|
LABEL="openocd_rules_end"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
info_TEXINFOS = openocd.texi
|
info_TEXINFOS = openocd.texi
|
||||||
openocd_TEXINFOS = fdl.texi
|
openocd_TEXINFOS = fdl.texi
|
||||||
man_MANS = openocd.1
|
man_MANS = openocd.1
|
||||||
EXTRA_DIST = openocd.1
|
EXTRA_DIST = openocd.1 \
|
||||||
|
INSTALL.txt
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
mkdir $(distdir)/manual
|
mkdir $(distdir)/manual
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ TMS which will select different shift registers.
|
|||||||
|
|
||||||
The first thing you need to do is reset the state machine, because when
|
The first thing you need to do is reset the state machine, because when
|
||||||
you connect to a chip you do not know what state the controller is in,you need
|
you connect to a chip you do not know what state the controller is in,you need
|
||||||
to clock TMS as 1, at least 7 times. This will put you into "Test Logic
|
to clock TMS as 1, at least 5 times. This will put you into "Test Logic
|
||||||
Reset" State. Knowing this, you can, once reset, then track what each
|
Reset" State. Knowing this, you can, once reset, then track what each
|
||||||
transition on TMS will do, and hence know what state the JTAG state
|
transition on TMS will do, and hence know what state the JTAG state
|
||||||
machine is in.
|
machine is in.
|
||||||
@@ -45,9 +45,9 @@ instruction register.
|
|||||||
|
|
||||||
For example, one of the data registers will be known as "bypass" this is
|
For example, one of the data registers will be known as "bypass" this is
|
||||||
(usually) a single bit which has no function and is used to bypass the
|
(usually) a single bit which has no function and is used to bypass the
|
||||||
chip. Assume we have 3 identical chips, wired up like the picture
|
chip. Assume we have 3 identical chips, wired up like the picture(wikipedia)
|
||||||
and each has a 3 bit instruction register, and there are 2 known
|
and each has a 3 bits instruction register, and there are 2 known
|
||||||
instructions (110 = bypass, 010 = some other function) if we want to use
|
instructions (110 = bypass, 010 = "some other function") if we want to use
|
||||||
"some other function", on the second chip in the line, and not change
|
"some other function", on the second chip in the line, and not change
|
||||||
the other chips we would do the following transitions.
|
the other chips we would do the following transitions.
|
||||||
|
|
||||||
@@ -66,13 +66,13 @@ each chip [110] [010] [110]
|
|||||||
The order is reversed, because we shift out the least significant bit
|
The order is reversed, because we shift out the least significant bit
|
||||||
first. Then we transition TMS:
|
first. Then we transition TMS:
|
||||||
|
|
||||||
1 1 1 1 0 0
|
1 1 1 0 0
|
||||||
|
|
||||||
which puts us in the "Shift DR state".
|
which puts us in the "Shift DR state".
|
||||||
|
|
||||||
Now when we clock data onto TDI (again while holding TMS to 0) , the
|
Now when we clock data onto TDI (again while holding TMS to 0) , the
|
||||||
data shifts through the data registers, and because of the instruction
|
data shifts through the data registers, and because of the instruction
|
||||||
registers we selected (some other function has 8 bits in its data
|
registers we selected ("some other function" has 8 bits in its data
|
||||||
register), our total data register in the chain looks like this:
|
register), our total data register in the chain looks like this:
|
||||||
|
|
||||||
0 00000000 0
|
0 00000000 0
|
||||||
@@ -107,10 +107,6 @@ gets interesting. But in and of itself, JTAG is actually very simple.
|
|||||||
|
|
||||||
@section primerjtag More Reading
|
@section primerjtag More Reading
|
||||||
|
|
||||||
The following link goes to an HTML (or PDF) introduction to JTAG,
|
|
||||||
written by one of the original members of the JTAG committee: @par
|
|
||||||
http://www.asset-intertech.com/products/boundscan.htm
|
|
||||||
|
|
||||||
A separate primer contains information about @subpage primerjtagbs for
|
A separate primer contains information about @subpage primerjtagbs for
|
||||||
developers that want to extend OpenOCD for such purposes.
|
developers that want to extend OpenOCD for such purposes.
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ the minor version will @a also be zero (<code>y = 0, z = 0</code>).
|
|||||||
After these required numeric components, release version strings
|
After these required numeric components, release version strings
|
||||||
may contain tags such as as <em>-rc1</em> or <em>-rc2</em>.
|
may contain tags such as as <em>-rc1</em> or <em>-rc2</em>.
|
||||||
These 'rc' tags indicate "release candidate" versions of the package.
|
These 'rc' tags indicate "release candidate" versions of the package.
|
||||||
Like the major/minor/micro numbers, these tags will be manipulated
|
Like major/minor/micro numbers, these are updated
|
||||||
by the automated release process.
|
as part of the release process.
|
||||||
|
|
||||||
The release process includes version number manipulations to the tree
|
The release process includes version number manipulations to the tree
|
||||||
being released, ensuring that all numbers are incremented (or rolled
|
being released, ensuring that all numbers are incremented (or rolled
|
||||||
@@ -277,22 +277,34 @@ support; the Release Manager isn't the only participant.
|
|||||||
|
|
||||||
The following steps should be followed to produce each release:
|
The following steps should be followed to produce each release:
|
||||||
|
|
||||||
-# Produce final patches to mainline (or a release branch). Nobody
|
-# Produce final patches using a local clone of mainline. Nobody
|
||||||
except the RM should be committing anything.
|
except the RM should be committing anything. <em>Everyone with commit
|
||||||
-# Finalize @c NEWS file to describe the changes in the release
|
privileges needs to know and agree to this in advance!</em> Even the RM
|
||||||
|
only commits a handful of updates as part of the release process
|
||||||
|
itself ... to files which are part of the version identification scheme
|
||||||
|
or release process; and to create the version tag; and then to open the
|
||||||
|
merge window for the next release cycle.
|
||||||
|
-# Finalize @c the 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.
|
- This material should have been produced during the development cycle,
|
||||||
- Add a new item for each @c NEWS-worthy contribution, when committed.
|
by adding items for each @c NEWS-worthy contribution, when committed
|
||||||
|
during the merge window. (One part of closing the merge window, by
|
||||||
|
opening the RC phase of the release, is the commitment to hold all
|
||||||
|
further such contributions until the next merge window opens.)
|
||||||
|
- The RM should make sure nothing important was omitted, as part of
|
||||||
|
the RC1 cycle. From then on, no more updates to NEWS content should
|
||||||
|
be needed (except to seed the process for the next release, or maybe
|
||||||
|
if a significant and longstanding bug is fixed late in the RC phase).
|
||||||
-# Bump library version if our API changed (not yet required)
|
-# Bump library version if our API changed (not yet required)
|
||||||
-# Update and commit the final package version in @c configure.in:
|
-# Update and commit the final package version in @c configure.in:
|
||||||
<code>tools/release/version.sh</code> may help ensure the versions
|
(The <code>tools/release/version.sh</code> script might help ensure
|
||||||
are named consistently:
|
the versions are named properly.):
|
||||||
-# Remove @c -dev tag.
|
-# Remove @c -dev tag.
|
||||||
-# Update the @c -rc tag:
|
-# Update any @c -rc tag:
|
||||||
- If producing the final release from an -rc series, remove it
|
- If producing the final release from an -rc series, remove it
|
||||||
- If producing the first RC in a series, add rc1
|
- If producing the first RC in a series, add rc1
|
||||||
- If producing the next RC in a series, bump the rc number
|
- If producing the next RC in a series, bump the rc number
|
||||||
-# Commit that version change.
|
-# Commit that version change, with a good descriptive comment.
|
||||||
-# Create a git tag for the final commit, with a tag name matching
|
-# Create a git tag for the final commit, with a tag name matching
|
||||||
the version string in <code>configure.in</code> (including <em>-rcN</em>
|
the version string in <code>configure.in</code> (including <em>-rcN</em>
|
||||||
where relevant):
|
where relevant):
|
||||||
@@ -301,49 +313,92 @@ PACKAGE_VERSION="x.y.z"
|
|||||||
PACKAGE_TAG="v${PACKAGE_VERSION}"
|
PACKAGE_TAG="v${PACKAGE_VERSION}"
|
||||||
git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||||
@endverbatim
|
@endverbatim
|
||||||
-# Prepare to resume normal development on mainline (major or minor release)
|
-# Do not push those changes to mainline yet; only builds using the
|
||||||
- Update the version label
|
source archives you will be creating should ever be labeled as
|
||||||
|
official releases (with no "-dev" suffix). Since mainline is a
|
||||||
|
development tree, these will be pushed later, as part of opening
|
||||||
|
the merge window for the next release cycle (restoring the "-dev"
|
||||||
|
suffix for that next release.) Those version and tag updates are
|
||||||
|
the last ones to be included in the release being made.
|
||||||
|
-# Produce the release files, using the local clone of the source
|
||||||
|
tree which holds the release's tag and updated version in
|
||||||
|
@c configure.in ... this is used only to produce the release, and
|
||||||
|
all files should already be properly checked out.
|
||||||
|
-# Run <code>tools/release.sh package</code> to produce the
|
||||||
|
source archives. This automatically bootstraps and
|
||||||
|
configures the process.
|
||||||
|
-# Run <code>tools/release.sh stage</code> to create an @c archives
|
||||||
|
directory with the release data, including MD5 and SHA1
|
||||||
|
checksum files (which are used with Berlios).
|
||||||
|
-# Sanity check at least one of those archives, by extracting and
|
||||||
|
configuring its contents, using them to build a copy of OpenOCD,
|
||||||
|
and verifying that the result prints the correct release version
|
||||||
|
in its startup banner. (For example,
|
||||||
|
"configure --enable-ft2232_libftdi --enable-parport"
|
||||||
|
then "make" and run "src/openocd -v" as a sanity check.)
|
||||||
|
-# Run <code>make docs</code> to create the
|
||||||
|
documentation which will be published.
|
||||||
|
-# Upload packages and post announcements of their availability:
|
||||||
|
-# Release packages into files section of project sites:
|
||||||
|
- SF.net:
|
||||||
|
-# Under "Project Admin", use the "File Manager"
|
||||||
|
-# Create a new folder under "openocd" named "${PACKAGE_VERSION}"
|
||||||
|
-# Upload the @c NEWS file and mark it as the release notes.
|
||||||
|
-# Upload the three source archive files, using the Web interface,
|
||||||
|
into that folder. Verify the upload worked OK by checking the
|
||||||
|
MD5 and SHA1 checksums computed by SourceForge against the
|
||||||
|
versions created as part of staging the release.
|
||||||
|
-# Also upload doc/openocd.pdf (the User's Guide) so the version
|
||||||
|
matching each release will be easily available.
|
||||||
|
-# Select each file in the release, and use the property panel
|
||||||
|
to set its type and select the right release notes.
|
||||||
|
- .tar.bz2: Linux, Mac
|
||||||
|
- .tar.gz: BSD, Solaris, Others
|
||||||
|
- .zip: Windows
|
||||||
|
- For openocd.pdf just associate it with the right release notes.
|
||||||
|
-# Create an SF.net project news update.
|
||||||
|
- Berlios:
|
||||||
|
-# Provide @c NEWS file, as requested.
|
||||||
|
-# Upload the release files via FTP to ftp://ftp.berlios.de/incoming/
|
||||||
|
-# Edit descriptions for each file (one at a time) Note that Berlios
|
||||||
|
does not automatically checksum files, and it uses a very old
|
||||||
|
version of the SourceForge code with user interface issues.
|
||||||
|
-# Click button to send E-mail Release Notice.
|
||||||
|
-# Depending on how paranoid you're feeling today, verify the images by
|
||||||
|
downloading them from the websites and making sure there are no
|
||||||
|
differences between the downloaded copies and your originals.
|
||||||
|
-# Publish User's and Developer's Guides to the project web sites:
|
||||||
|
-# Use SCP to update the SF.net web site with PDF and HTML for the
|
||||||
|
User's Guide, and HTML for the developer's guide ... you can
|
||||||
|
instantiate a shell.sourceforge.net instance and set up symlinks
|
||||||
|
from your home directory, to simplify this process.
|
||||||
|
-# (How to update the Berlios web site with the same data?)
|
||||||
|
-# Post announcement e-mail to the openocd-development list.
|
||||||
|
-# optionally:
|
||||||
|
-# Post an update on the Berlios blog (if it lets you)
|
||||||
|
-# Announce updates on freshmeat.net and other trackers.
|
||||||
|
-# Submit updates to news feeds (e.g. Digg, Reddit, etc.).
|
||||||
|
-# Resume normal development on mainline, by opening the merge window for
|
||||||
|
the next major or minor release cycle. (You might want to do this
|
||||||
|
before all the release bits are fully published.)
|
||||||
|
- Update the version label in the @c configure.in file:
|
||||||
- Restore @c -dev version tag.
|
- Restore @c -dev version tag.
|
||||||
- For a new minor release cycle, increment the release's minor number
|
- For a new minor release cycle, increment the release's minor number
|
||||||
- For a new major release cycle, increment the release's major number
|
- For a new major release cycle, increment the release's major number
|
||||||
and zero its minor number
|
and zero its minor number
|
||||||
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
|
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
|
||||||
- Create a new @c NEWS file for the next release
|
- Create a new @c NEWS file for the next release
|
||||||
- Commit those changes, and push the commit and the release tag
|
- Commit those changes.
|
||||||
to mainline.
|
- Push all the updates to mainline.
|
||||||
-# Produce the package source archives:
|
- Last updates for the release, including the release tag (you
|
||||||
-# <em>Start with a new clone of the source tree</em>, with the
|
will need to "git push --tags").
|
||||||
release's tag. This is used only for producing these packages.
|
- Updates opening the merge window
|
||||||
-# Checkout the appropriate tag:
|
- At this point, it's OK for commiters to start pushing changes
|
||||||
<code>git checkout "${PACKAGE_VERSION}"</code>
|
which have been held off until the next release. (Any bugfixes to
|
||||||
-# @c bootstrap, @c configure, and @c make the package.
|
this release will be against a bug-fix release branch starting from
|
||||||
-# Run <code>make distcheck</code> to produce the distribution archives.
|
the commit you tagged as this release, not mainline.)
|
||||||
-# Run <code>make maintainer-clean</code> verify the repository is empty.
|
- Announce to the openocd-development list. Ideally, you will also
|
||||||
-# Create signature files using @c md5sum, @c sha1sum, etc.
|
be able to say who is managing the next release cycle.
|
||||||
-# Publish documentation for the release:
|
|
||||||
- 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
|
|
||||||
- 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:
|
|
||||||
-# Create a new folder named "${PACKAGE_VERSION}"
|
|
||||||
-# Select new folder as the target for uploads.
|
|
||||||
-# Upload files via Web interface into new
|
|
||||||
-# Set platform types for each archive:
|
|
||||||
- .tar.bz2: Linux, Mac
|
|
||||||
- .tar.gz: BSD, Solaris, Others
|
|
||||||
- .zip: Windows
|
|
||||||
- Berlios:
|
|
||||||
-# Create the new release for the new version.
|
|
||||||
-# 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.
|
|
||||||
-# Post announcement e-mail to the openocd-development list.
|
|
||||||
-# Announce updates on freshmeat.net and other trackers.
|
|
||||||
-# Submit big updates to news feeds (e.g. Digg, Reddit, etc.).
|
|
||||||
|
|
||||||
To start a bug-fix release branch:
|
To start a bug-fix release branch:
|
||||||
-# Create a new branch, starting from a major or
|
-# Create a new branch, starting from a major or
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ upon it, sometimes that is the only scheme available.
|
|||||||
|
|
||||||
As a small group of developers, supporting all the platforms and
|
As a small group of developers, supporting all the platforms and
|
||||||
targets in the debugger will be difficult, as there are enough problem
|
targets in the debugger will be difficult, as there are enough problem
|
||||||
with the plethora of Dongles, Chips, and different target boards.
|
with the plethora of Adapters, Chips, and different target boards.
|
||||||
Yes, the TCL interface might be suitable, but it has not received much
|
Yes, the TCL interface might be suitable, but it has not received much
|
||||||
love or attention. Perhaps it will after you read and understand this.
|
love or attention. Perhaps it will after you read and understand this.
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ different host-side GDB..
|
|||||||
Sure - a <em>man on a mission</em> can make that work. The GUI might be
|
Sure - a <em>man on a mission</em> can make that work. The GUI might be
|
||||||
libopenocd + Perl/TK, or maybe an Eclipse Plug-in.
|
libopenocd + Perl/TK, or maybe an Eclipse Plug-in.
|
||||||
That is a development support nightmare for reasons described
|
That is a development support nightmare for reasons described
|
||||||
above. We have enough support problems as it is with targets, dongles,
|
above. We have enough support problems as it is with targets, adapters,
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
@section serverdocshttpbg HTTP Server Background
|
@section serverdocshttpbg HTTP Server Background
|
||||||
@@ -270,8 +270,8 @@ every peripheral register on the target platform.
|
|||||||
|
|
||||||
That also is transportable, regardless of the OpenOCD host
|
That also is transportable, regardless of the OpenOCD host
|
||||||
platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX.
|
platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX.
|
||||||
You could even port OpenOCD to an Google Android and use it as a
|
You could even port OpenOCD to an Android system and use it as a
|
||||||
bit-bang dongle JTAG serving web pages.
|
bit-banging JTAG Adapter serving web pages.
|
||||||
|
|
||||||
@subsection serverdocshtmladv Advanced HTML Pages
|
@subsection serverdocshtmladv Advanced HTML Pages
|
||||||
|
|
||||||
@@ -309,17 +309,3 @@ This section needs to be expanded.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @page serverhttp OpenOCD HTTP Server API
|
|
||||||
|
|
||||||
|
|
||||||
Smoketest:
|
|
||||||
|
|
||||||
configure --enable-httpd --enable-dummy --enable-ioutil
|
|
||||||
|
|
||||||
openocd -s /usr/local/share/openocd -f httpd/httpd.tcl -f interface/dummy.cfg -f target/lpc2148.cfg
|
|
||||||
|
|
||||||
Navigate to: http://localhost:8888/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|||||||
746
doc/openocd.texi
746
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
1
jimtcl
Submodule
1
jimtcl
Submodule
Submodule jimtcl added at 60dfb023c4
@@ -1,12 +1,16 @@
|
|||||||
|
include $(top_srcdir)/common.mk
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
helper \
|
|
||||||
jtag \
|
jtag \
|
||||||
|
helper \
|
||||||
target \
|
target \
|
||||||
|
transport \
|
||||||
flash \
|
flash \
|
||||||
svf \
|
svf \
|
||||||
xsvf \
|
xsvf \
|
||||||
pld \
|
pld \
|
||||||
server
|
server \
|
||||||
|
rtos
|
||||||
|
|
||||||
lib_LTLIBRARIES = libopenocd.la
|
lib_LTLIBRARIES = libopenocd.la
|
||||||
bin_PROGRAMS = openocd
|
bin_PROGRAMS = openocd
|
||||||
@@ -20,6 +24,12 @@ endif
|
|||||||
openocd_SOURCES = $(MAINFILE)
|
openocd_SOURCES = $(MAINFILE)
|
||||||
openocd_LDADD = libopenocd.la
|
openocd_LDADD = libopenocd.la
|
||||||
|
|
||||||
|
if INTERNAL_JIMTCL
|
||||||
|
openocd_LDADD += $(top_builddir)/jimtcl/libjim.a
|
||||||
|
else
|
||||||
|
openocd_LDADD += -ljim
|
||||||
|
endif
|
||||||
|
|
||||||
libopenocd_la_SOURCES = \
|
libopenocd_la_SOURCES = \
|
||||||
hello.c \
|
hello.c \
|
||||||
openocd.c \
|
openocd.c \
|
||||||
@@ -29,12 +39,6 @@ noinst_HEADERS = \
|
|||||||
hello.h \
|
hello.h \
|
||||||
openocd.h
|
openocd.h
|
||||||
|
|
||||||
|
|
||||||
# set the include path found by configure
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-I$(top_builddir)/src
|
|
||||||
|
|
||||||
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
||||||
|
|
||||||
# banner output includes RELSTR appended to $VERSION from the configure script
|
# banner output includes RELSTR appended to $VERSION from the configure script
|
||||||
@@ -44,6 +48,7 @@ libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
|||||||
else
|
else
|
||||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||||
endif
|
endif
|
||||||
|
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
|
||||||
|
|
||||||
# add default CPPFLAGS
|
# add default CPPFLAGS
|
||||||
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||||
@@ -80,6 +85,9 @@ else
|
|||||||
if RLINK
|
if RLINK
|
||||||
LIBUSB = -lusb
|
LIBUSB = -lusb
|
||||||
else
|
else
|
||||||
|
if ULINK
|
||||||
|
LIBUSB = -lusb
|
||||||
|
else
|
||||||
if VSLLINK
|
if VSLLINK
|
||||||
LIBUSB = -lusb
|
LIBUSB = -lusb
|
||||||
else
|
else
|
||||||
@@ -88,22 +96,21 @@ endif
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
libopenocd_la_LIBADD = \
|
libopenocd_la_LIBADD = \
|
||||||
$(top_builddir)/src/xsvf/libxsvf.la \
|
$(top_builddir)/src/xsvf/libxsvf.la \
|
||||||
$(top_builddir)/src/svf/libsvf.la \
|
$(top_builddir)/src/svf/libsvf.la \
|
||||||
$(top_builddir)/src/pld/libpld.la \
|
$(top_builddir)/src/pld/libpld.la \
|
||||||
$(top_builddir)/src/jtag/libjtag.la \
|
$(top_builddir)/src/jtag/libjtag.la \
|
||||||
|
$(top_builddir)/src/transport/libtransport.la \
|
||||||
$(top_builddir)/src/flash/libflash.la \
|
$(top_builddir)/src/flash/libflash.la \
|
||||||
$(top_builddir)/src/target/libtarget.la \
|
$(top_builddir)/src/target/libtarget.la \
|
||||||
$(top_builddir)/src/server/libserver.la \
|
$(top_builddir)/src/server/libserver.la \
|
||||||
|
$(top_builddir)/src/rtos/librtos.la \
|
||||||
$(top_builddir)/src/helper/libhelper.la \
|
$(top_builddir)/src/helper/libhelper.la \
|
||||||
$(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB)
|
$(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB)
|
||||||
|
|
||||||
if HTTPD
|
|
||||||
libopenocd_la_LIBADD += -lmicrohttpd
|
|
||||||
endif
|
|
||||||
|
|
||||||
STARTUP_TCL_SRCS = \
|
STARTUP_TCL_SRCS = \
|
||||||
$(srcdir)/helper/startup.tcl \
|
$(srcdir)/helper/startup.tcl \
|
||||||
$(srcdir)/jtag/startup.tcl \
|
$(srcdir)/jtag/startup.tcl \
|
||||||
@@ -127,6 +134,9 @@ startup_tcl.c: startup.tcl $(BIN2C)
|
|||||||
# add startup_tcl.c to make clean list
|
# add startup_tcl.c to make clean list
|
||||||
CLEANFILES = startup.tcl startup_tcl.c
|
CLEANFILES = startup.tcl startup_tcl.c
|
||||||
|
|
||||||
|
# we do not want generated file in the dist
|
||||||
|
dist-hook:
|
||||||
|
rm -f $(distdir)/startup_tcl.c
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2007-2009 by Øyvind Harboe *
|
* Copyright (C) 2007-2010 by Øyvind Harboe *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <helper/types.h>
|
#include <helper/types.h>
|
||||||
#include <jtag/jtag.h>
|
#include <jtag/jtag.h>
|
||||||
#include <helper/ioutil.h>
|
#include <helper/ioutil.h>
|
||||||
|
#include <helper/util.h>
|
||||||
#include <helper/configuration.h>
|
#include <helper/configuration.h>
|
||||||
|
|
||||||
#include <server/server.h>
|
#include <server/server.h>
|
||||||
@@ -99,10 +100,6 @@ static bool writeLog = true;
|
|||||||
|
|
||||||
char hwaddr[512];
|
char hwaddr[512];
|
||||||
|
|
||||||
|
|
||||||
extern struct flash_driver *flash_drivers[];
|
|
||||||
extern struct target_type *target_types[];
|
|
||||||
|
|
||||||
#ifdef CYGPKG_PROFILE_GPROF
|
#ifdef CYGPKG_PROFILE_GPROF
|
||||||
#include <cyg/profile/profile.h>
|
#include <cyg/profile/profile.h>
|
||||||
|
|
||||||
@@ -503,6 +500,10 @@ static void zylinjtag_startNetwork(void)
|
|||||||
|
|
||||||
cyg_httpd_init_tcl_interpreter();
|
cyg_httpd_init_tcl_interpreter();
|
||||||
|
|
||||||
|
// Kludge! Why can't I do this from httpd.c??? I get linker errors...
|
||||||
|
// some of that --start/end-group stuff?
|
||||||
|
Jim_InitStaticExtensions(httpstate.jim_interp);
|
||||||
|
|
||||||
Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log,
|
Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
Jim_CreateCommand(httpstate.jim_interp, "zy1000_reboot",
|
Jim_CreateCommand(httpstate.jim_interp, "zy1000_reboot",
|
||||||
@@ -1093,6 +1094,9 @@ int main(int argc, char *argv[])
|
|||||||
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
|
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
|
||||||
command_context_mode(cmd_ctx, COMMAND_CONFIG);
|
command_context_mode(cmd_ctx, COMMAND_CONFIG);
|
||||||
|
|
||||||
|
if (util_init(cmd_ctx) != ERROR_OK)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
if (ioutil_init(cmd_ctx) != ERROR_OK)
|
if (ioutil_init(cmd_ctx) != ERROR_OK)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
@@ -1277,6 +1281,7 @@ struct Tftp
|
|||||||
cyg_uint8 *mem;
|
cyg_uint8 *mem;
|
||||||
int actual;
|
int actual;
|
||||||
char *server;
|
char *server;
|
||||||
|
int port;
|
||||||
char *file;
|
char *file;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1333,6 +1338,15 @@ static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
|
|||||||
strncpy(tftp->server, name, server - name);
|
strncpy(tftp->server, name, server - name);
|
||||||
tftp->server[server - name] = 0;
|
tftp->server[server - name] = 0;
|
||||||
|
|
||||||
|
tftp->port = 0; /* default port 69 */
|
||||||
|
char *port;
|
||||||
|
port = strchr(tftp->server, ':');
|
||||||
|
if (port != NULL)
|
||||||
|
{
|
||||||
|
tftp->port = atoi(port + 1);
|
||||||
|
*port = 0;
|
||||||
|
}
|
||||||
|
|
||||||
tftp->file = strdup(server + 1);
|
tftp->file = strdup(server + 1);
|
||||||
if (tftp->file == NULL)
|
if (tftp->file == NULL)
|
||||||
{
|
{
|
||||||
@@ -1350,7 +1364,7 @@ static int fetchTftp(struct Tftp *tftp)
|
|||||||
if (!tftp->readFile)
|
if (!tftp->readFile)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
tftp->actual = tftp_client_get(tftp->file, tftp->server, 0, tftp->mem,
|
tftp->actual = tftp_client_get(tftp->file, tftp->server, tftp->port, tftp->mem,
|
||||||
tftpMaxSize, TFTP_OCTET, &err);
|
tftpMaxSize, TFTP_OCTET, &err);
|
||||||
|
|
||||||
if (tftp->actual < 0)
|
if (tftp->actual < 0)
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
include $(top_srcdir)/common.mk
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
nor \
|
nor \
|
||||||
nand
|
nand
|
||||||
|
|
||||||
AM_CPPFLAGS = \
|
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-I$(top_builddir)/src
|
|
||||||
|
|
||||||
METASOURCES = AUTO
|
METASOURCES = AUTO
|
||||||
noinst_LTLIBRARIES = libflash.la
|
noinst_LTLIBRARIES = libflash.la
|
||||||
libflash_la_SOURCES = \
|
libflash_la_SOURCES = \
|
||||||
|
|||||||
@@ -25,13 +25,13 @@
|
|||||||
|
|
||||||
unsigned get_flash_name_index(const char *name)
|
unsigned get_flash_name_index(const char *name)
|
||||||
{
|
{
|
||||||
const char *index = strrchr(name, '.');
|
const char *name_index = strrchr(name, '.');
|
||||||
if (NULL == index)
|
if (NULL == name_index)
|
||||||
return 0;
|
return 0;
|
||||||
if (index[1] < '0' || index[1] > '9')
|
if (name_index[1] < '0' || name_index[1] > '9')
|
||||||
return ~0U;
|
return ~0U;
|
||||||
unsigned requested;
|
unsigned requested;
|
||||||
int retval = parse_uint(index + 1, &requested);
|
int retval = parse_uint(name_index + 1, &requested);
|
||||||
// detect parsing error by forcing past end of bank list
|
// detect parsing error by forcing past end of bank list
|
||||||
return (ERROR_OK == retval) ? requested : ~0U;
|
return (ERROR_OK == retval) ? requested : ~0U;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,13 +36,14 @@ unsigned get_flash_name_index(const char *name);
|
|||||||
*/
|
*/
|
||||||
bool flash_driver_name_matches(const char *name, const char *expected);
|
bool flash_driver_name_matches(const char *name, const char *expected);
|
||||||
|
|
||||||
#define ERROR_FLASH_BANK_INVALID -900
|
#define ERROR_FLASH_BANK_INVALID (-900)
|
||||||
#define ERROR_FLASH_SECTOR_INVALID -901
|
#define ERROR_FLASH_SECTOR_INVALID (-901)
|
||||||
#define ERROR_FLASH_OPERATION_FAILED -902
|
#define ERROR_FLASH_OPERATION_FAILED (-902)
|
||||||
#define ERROR_FLASH_DST_OUT_OF_BANK -903
|
#define ERROR_FLASH_DST_OUT_OF_BANK (-903)
|
||||||
#define ERROR_FLASH_DST_BREAKS_ALIGNMENT -904
|
#define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
|
||||||
#define ERROR_FLASH_BUSY -905
|
#define ERROR_FLASH_BUSY (-905)
|
||||||
#define ERROR_FLASH_SECTOR_NOT_ERASED -906
|
#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
|
||||||
#define ERROR_FLASH_BANK_NOT_PROBED -907
|
#define ERROR_FLASH_BANK_NOT_PROBED (-907)
|
||||||
|
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
|
||||||
|
|
||||||
#endif // FLASH_COMMON_H
|
#endif // FLASH_COMMON_H
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ static int mg_init_gpio (void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
|
||||||
{
|
{
|
||||||
uint8_t status, error;
|
uint8_t status, error;
|
||||||
struct target *target = mflash_bank->target;
|
struct target *target = mflash_bank->target;
|
||||||
@@ -220,7 +220,7 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
|||||||
struct duration bench;
|
struct duration bench;
|
||||||
duration_start(&bench);
|
duration_start(&bench);
|
||||||
|
|
||||||
while (time) {
|
while (time_var) {
|
||||||
|
|
||||||
ret = target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status);
|
ret = target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status);
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
@@ -228,10 +228,10 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
|||||||
|
|
||||||
if (status & mg_io_rbit_status_busy)
|
if (status & mg_io_rbit_status_busy)
|
||||||
{
|
{
|
||||||
if (wait == mg_io_wait_bsy)
|
if (wait_local == mg_io_wait_bsy)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else {
|
} else {
|
||||||
switch (wait)
|
switch (wait_local)
|
||||||
{
|
{
|
||||||
case mg_io_wait_not_bsy:
|
case mg_io_wait_not_bsy:
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -259,7 +259,7 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
|||||||
return ERROR_MG_IO;
|
return ERROR_MG_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (wait)
|
switch (wait_local)
|
||||||
{
|
{
|
||||||
case mg_io_wait_rdy:
|
case mg_io_wait_rdy:
|
||||||
if (status & mg_io_rbit_status_ready)
|
if (status & mg_io_rbit_status_ready)
|
||||||
@@ -280,7 +280,7 @@ static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
|
|||||||
else
|
else
|
||||||
LOG_ERROR("mflash: duration measurement failed: %d", ret);
|
LOG_ERROR("mflash: duration measurement failed: %d", ret);
|
||||||
|
|
||||||
if (t > time)
|
if (t > time_var)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,14 +720,20 @@ COMMAND_HANDLER(mg_write_cmd)
|
|||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
int filesize;
|
||||||
buffer = malloc(MG_FILEIO_CHUNK);
|
buffer = malloc(MG_FILEIO_CHUNK);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
fileio_close(&fileio);
|
fileio_close(&fileio);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
int retval = fileio_size(&fileio, &filesize);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
fileio_close(&fileio);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
cnt = fileio.size / MG_FILEIO_CHUNK;
|
cnt = filesize / MG_FILEIO_CHUNK;
|
||||||
res = fileio.size % MG_FILEIO_CHUNK;
|
res = filesize % MG_FILEIO_CHUNK;
|
||||||
|
|
||||||
struct duration bench;
|
struct duration bench;
|
||||||
duration_start(&bench);
|
duration_start(&bench);
|
||||||
@@ -752,8 +758,8 @@ COMMAND_HANDLER(mg_write_cmd)
|
|||||||
if (duration_measure(&bench) == ERROR_OK)
|
if (duration_measure(&bench) == ERROR_OK)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "wrote %ld bytes from file %s "
|
command_print(CMD_CTX, "wrote %ld bytes from file %s "
|
||||||
"in %fs (%0.3f kB/s)", (long)fileio.size, CMD_ARGV[1],
|
"in %fs (%0.3f kB/s)", (long)filesize, CMD_ARGV[1],
|
||||||
duration_elapsed(&bench), duration_kbps(&bench, fileio.size));
|
duration_elapsed(&bench), duration_kbps(&bench, filesize));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -1121,7 +1127,7 @@ static int mg_storage_config(void)
|
|||||||
!= ERROR_OK)
|
!= ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mg_gen_ataid((mg_io_type_drv_info *)buff);
|
mg_gen_ataid((mg_io_type_drv_info *)(void *)buff);
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo))
|
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo))
|
||||||
!= ERROR_OK)
|
!= ERROR_OK)
|
||||||
@@ -1149,7 +1155,7 @@ static int mg_boot_config(void)
|
|||||||
buff[0] = mg_op_mode_snd; /* operation mode */
|
buff[0] = mg_op_mode_snd; /* operation mode */
|
||||||
buff[1] = MG_UNLOCK_OTP_AREA;
|
buff[1] = MG_UNLOCK_OTP_AREA;
|
||||||
buff[2] = 4; /* boot size */
|
buff[2] = 4; /* boot size */
|
||||||
*((uint32_t *)(buff + 4)) = 0; /* XIP size */
|
*((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */
|
||||||
|
|
||||||
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo))
|
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo))
|
||||||
!= ERROR_OK)
|
!= ERROR_OK)
|
||||||
@@ -1302,7 +1308,7 @@ static const struct command_registration mflash_exec_command_handlers[] = {
|
|||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
int mflash_init_drivers(struct command_context *cmd_ctx)
|
static int mflash_init_drivers(struct command_context *cmd_ctx)
|
||||||
{
|
{
|
||||||
if (!mflash_bank)
|
if (!mflash_bank)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ struct mflash_gpio_num
|
|||||||
|
|
||||||
struct mflash_gpio_drv
|
struct mflash_gpio_drv
|
||||||
{
|
{
|
||||||
char *name;
|
const char *name;
|
||||||
int (*set_gpio_to_output) (struct mflash_gpio_num gpio);
|
int (*set_gpio_to_output) (struct mflash_gpio_num gpio);
|
||||||
int (*set_gpio_output_val) (struct mflash_gpio_num gpio, uint8_t val);
|
int (*set_gpio_output_val) (struct mflash_gpio_num gpio, uint8_t val);
|
||||||
};
|
};
|
||||||
@@ -142,7 +142,6 @@ struct mflash_bank
|
|||||||
};
|
};
|
||||||
|
|
||||||
int mflash_register_commands(struct command_context *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 (0x200) /* 512Bytes = 2^9 */
|
||||||
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)
|
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
AM_CPPFLAGS = \
|
include $(top_srcdir)/common.mk
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-I$(top_builddir)/src
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libocdflashnand.la
|
noinst_LTLIBRARIES = libocdflashnand.la
|
||||||
|
|
||||||
@@ -18,6 +16,8 @@ NAND_DRIVERS = \
|
|||||||
nonce.c \
|
nonce.c \
|
||||||
davinci.c \
|
davinci.c \
|
||||||
lpc3180.c \
|
lpc3180.c \
|
||||||
|
lpc32xx.c \
|
||||||
|
mx2.c \
|
||||||
mx3.c \
|
mx3.c \
|
||||||
orion.c \
|
orion.c \
|
||||||
s3c24xx.c \
|
s3c24xx.c \
|
||||||
@@ -26,7 +26,8 @@ NAND_DRIVERS = \
|
|||||||
s3c2440.c \
|
s3c2440.c \
|
||||||
s3c2443.c \
|
s3c2443.c \
|
||||||
s3c6400.c \
|
s3c6400.c \
|
||||||
at91sam9.c
|
at91sam9.c \
|
||||||
|
nuc910.c
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
arm_io.h \
|
arm_io.h \
|
||||||
@@ -35,8 +36,11 @@ noinst_HEADERS = \
|
|||||||
fileio.h \
|
fileio.h \
|
||||||
imp.h \
|
imp.h \
|
||||||
lpc3180.h \
|
lpc3180.h \
|
||||||
|
lpc32xx.h \
|
||||||
|
mx2.h \
|
||||||
mx3.h \
|
mx3.h \
|
||||||
s3c24xx.h \
|
s3c24xx.h \
|
||||||
s3c24xx_regs.h
|
s3c24xx_regs.h \
|
||||||
|
nuc910.h
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
* @param area Pointer to a pointer to a working area to copy code to
|
* @param area Pointer to a pointer to a working area to copy code to
|
||||||
* @return Success or failure of the operation
|
* @return Success or failure of the operation
|
||||||
*/
|
*/
|
||||||
int arm_code_to_working_area(struct target *target,
|
static int arm_code_to_working_area(struct target *target,
|
||||||
const uint32_t *code, unsigned code_size,
|
const uint32_t *code, unsigned code_size,
|
||||||
unsigned additional, struct working_area **area)
|
unsigned additional, struct working_area **area)
|
||||||
{
|
{
|
||||||
@@ -100,7 +100,7 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
struct arm *armv4_5 = target->arch_info;
|
struct arm *armv4_5 = target->arch_info;
|
||||||
struct reg_param reg_params[3];
|
struct reg_param reg_params[3];
|
||||||
uint32_t target_buf;
|
uint32_t target_buf;
|
||||||
uint32_t exit = 0;
|
uint32_t exit_var = 0;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* Inputs:
|
/* Inputs:
|
||||||
@@ -153,11 +153,11 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
|||||||
|
|
||||||
/* armv4 must exit using a hardware breakpoint */
|
/* armv4 must exit using a hardware breakpoint */
|
||||||
if (armv4_5->is_armv4)
|
if (armv4_5->is_armv4)
|
||||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
exit_var = nand->copy_area->address + sizeof(code) - 4;
|
||||||
|
|
||||||
/* use alg to write data from work area to NAND chip */
|
/* use alg to write data from work area to NAND chip */
|
||||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||||
nand->copy_area->address, exit, 1000, &algo);
|
nand->copy_area->address, exit_var, 1000, &algo);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
LOG_ERROR("error executing hosted NAND write");
|
LOG_ERROR("error executing hosted NAND write");
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
struct arm *armv4_5 = target->arch_info;
|
struct arm *armv4_5 = target->arch_info;
|
||||||
struct reg_param reg_params[3];
|
struct reg_param reg_params[3];
|
||||||
uint32_t target_buf;
|
uint32_t target_buf;
|
||||||
uint32_t exit = 0;
|
uint32_t exit_var = 0;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* Inputs:
|
/* Inputs:
|
||||||
@@ -229,11 +229,11 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
|
|||||||
|
|
||||||
/* armv4 must exit using a hardware breakpoint */
|
/* armv4 must exit using a hardware breakpoint */
|
||||||
if (armv4_5->is_armv4)
|
if (armv4_5->is_armv4)
|
||||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
exit_var = nand->copy_area->address + sizeof(code) - 4;
|
||||||
|
|
||||||
/* use alg to write data from NAND chip to work area */
|
/* use alg to write data from NAND chip to work area */
|
||||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||||
nand->copy_area->address, exit, 1000, &algo);
|
nand->copy_area->address, exit_var, 1000, &algo);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
LOG_ERROR("error executing hosted NAND read");
|
LOG_ERROR("error executing hosted NAND read");
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,6 @@
|
|||||||
* Representation of a pin on an AT91SAM9 chip.
|
* Representation of a pin on an AT91SAM9 chip.
|
||||||
*/
|
*/
|
||||||
struct at91sam9_pin {
|
struct at91sam9_pin {
|
||||||
/** Target this pin is on. */
|
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
/** Address of the PIO controller. */
|
/** Address of the PIO controller. */
|
||||||
uint32_t pioc;
|
uint32_t pioc;
|
||||||
|
|
||||||
@@ -52,9 +49,6 @@ struct at91sam9_pin {
|
|||||||
* Private data for the controller that is stored in the NAND device structure.
|
* Private data for the controller that is stored in the NAND device structure.
|
||||||
*/
|
*/
|
||||||
struct at91sam9_nand {
|
struct at91sam9_nand {
|
||||||
/** Target the NAND is attached to. */
|
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
/** Address of the ECC controller for NAND. */
|
/** Address of the ECC controller for NAND. */
|
||||||
uint32_t ecc;
|
uint32_t ecc;
|
||||||
|
|
||||||
@@ -101,8 +95,7 @@ static int at91sam9_halted(struct target *target, const char *label)
|
|||||||
*/
|
*/
|
||||||
static int at91sam9_init(struct nand_device *nand)
|
static int at91sam9_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = info->target;
|
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "init")) {
|
if (!at91sam9_halted(target, "init")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -117,9 +110,10 @@ static int at91sam9_init(struct nand_device *nand)
|
|||||||
* @param info NAND controller information for controlling NAND device.
|
* @param info NAND controller information for controlling NAND device.
|
||||||
* @return Success or failure of the enabling.
|
* @return Success or failure of the enabling.
|
||||||
*/
|
*/
|
||||||
static int at91sam9_enable(struct at91sam9_nand *info)
|
static int at91sam9_enable(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct target *target = info->target;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num);
|
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num);
|
||||||
}
|
}
|
||||||
@@ -130,9 +124,10 @@ static int at91sam9_enable(struct at91sam9_nand *info)
|
|||||||
* @param info NAND controller information for controlling NAND device.
|
* @param info NAND controller information for controlling NAND device.
|
||||||
* @return Success or failure of the disabling.
|
* @return Success or failure of the disabling.
|
||||||
*/
|
*/
|
||||||
static int at91sam9_disable(struct at91sam9_nand *info)
|
static int at91sam9_disable(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct target *target = info->target;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num);
|
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num);
|
||||||
}
|
}
|
||||||
@@ -147,13 +142,13 @@ static int at91sam9_disable(struct at91sam9_nand *info)
|
|||||||
static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "command")) {
|
if (!at91sam9_halted(target, "command")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
at91sam9_enable(info);
|
at91sam9_enable(nand);
|
||||||
|
|
||||||
return target_write_u8(target, info->cmd, command);
|
return target_write_u8(target, info->cmd, command);
|
||||||
}
|
}
|
||||||
@@ -166,13 +161,11 @@ static int at91sam9_command(struct nand_device *nand, uint8_t command)
|
|||||||
*/
|
*/
|
||||||
static int at91sam9_reset(struct nand_device *nand)
|
static int at91sam9_reset(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
if (!at91sam9_halted(nand->target, "reset")) {
|
||||||
|
|
||||||
if (!at91sam9_halted(info->target, "reset")) {
|
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return at91sam9_disable(info);
|
return at91sam9_disable(nand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,9 +178,9 @@ static int at91sam9_reset(struct nand_device *nand)
|
|||||||
static int at91sam9_address(struct nand_device *nand, uint8_t address)
|
static int at91sam9_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(info->target, "address")) {
|
if (!at91sam9_halted(nand->target, "address")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,9 +198,9 @@ static int at91sam9_address(struct nand_device *nand, uint8_t address)
|
|||||||
static int at91sam9_read_data(struct nand_device *nand, void *data)
|
static int at91sam9_read_data(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(info->target, "read data")) {
|
if (!at91sam9_halted(nand->target, "read data")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +218,7 @@ static int at91sam9_read_data(struct nand_device *nand, void *data)
|
|||||||
static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
|
static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "write data")) {
|
if (!at91sam9_halted(target, "write data")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -244,7 +237,7 @@ static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
|
static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
if (!at91sam9_halted(target, "nand ready")) {
|
if (!at91sam9_halted(target, "nand ready")) {
|
||||||
@@ -279,7 +272,7 @@ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int
|
|||||||
struct arm_nand_data *io = &info->io;
|
struct arm_nand_data *io = &info->io;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!at91sam9_halted(info->target, "read block")) {
|
if (!at91sam9_halted(nand->target, "read block")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +297,7 @@ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, in
|
|||||||
struct arm_nand_data *io = &info->io;
|
struct arm_nand_data *io = &info->io;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!at91sam9_halted(info->target, "write block")) {
|
if (!at91sam9_halted(nand->target, "write block")) {
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +374,7 @@ static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint8_t *oob_data;
|
uint8_t *oob_data;
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
@@ -458,7 +451,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||||
{
|
{
|
||||||
struct at91sam9_nand *info = nand->controller_priv;
|
struct at91sam9_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
int retval;
|
int retval;
|
||||||
uint8_t *oob_data = oob;
|
uint8_t *oob_data = oob;
|
||||||
uint32_t parity, nparity;
|
uint32_t parity, nparity;
|
||||||
@@ -517,23 +510,16 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
*/
|
*/
|
||||||
NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
|
||||||
{
|
{
|
||||||
struct target *target = NULL;
|
|
||||||
unsigned long chip = 0, ecc = 0;
|
unsigned long chip = 0, ecc = 0;
|
||||||
struct at91sam9_nand *info = NULL;
|
struct at91sam9_nand *info = NULL;
|
||||||
|
|
||||||
LOG_DEBUG("AT91SAM9 NAND Device Command\n");
|
LOG_DEBUG("AT91SAM9 NAND Device Command");
|
||||||
|
|
||||||
if (CMD_ARGC < 3 || CMD_ARGC > 4) {
|
if (CMD_ARGC < 3 || CMD_ARGC > 4) {
|
||||||
LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]);
|
LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]);
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
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);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||||
if (chip == 0) {
|
if (chip == 0) {
|
||||||
LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]);
|
LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]);
|
||||||
@@ -554,14 +540,13 @@ NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->target = target;
|
|
||||||
info->data = chip;
|
info->data = chip;
|
||||||
info->cmd = chip | (1 << 22);
|
info->cmd = chip | (1 << 22);
|
||||||
info->addr = chip | (1 << 21);
|
info->addr = chip | (1 << 21);
|
||||||
info->ecc = ecc;
|
info->ecc = ecc;
|
||||||
|
|
||||||
nand->controller_priv = info;
|
nand->controller_priv = info;
|
||||||
info->io.target = target;
|
info->io.target = nand->target;
|
||||||
info->io.data = info->data;
|
info->io.data = info->data;
|
||||||
info->io.op = ARM_NAND_NONE;
|
info->io.op = ARM_NAND_NONE;
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ void nand_device_add(struct nand_device *c)
|
|||||||
|
|
||||||
/* Chip ID list
|
/* Chip ID list
|
||||||
*
|
*
|
||||||
* Name, ID code, pagesize, chipsize in MegaByte, eraseblock size,
|
* Manufacturer, ID code, pagesize, chipsize in MegaByte, eraseblock size,
|
||||||
* options
|
* options, name
|
||||||
*
|
*
|
||||||
* Pagesize; 0, 256, 512
|
* Pagesize; 0, 256, 512
|
||||||
* 0 get this information from the extended chip ID
|
* 0 get this information from the extended chip ID
|
||||||
@@ -52,80 +52,86 @@ void nand_device_add(struct nand_device *c)
|
|||||||
*/
|
*/
|
||||||
static struct nand_info nand_flash_ids[] =
|
static struct nand_info nand_flash_ids[] =
|
||||||
{
|
{
|
||||||
/* start "museum" IDs */
|
/* Vendor Specific Entries */
|
||||||
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"},
|
||||||
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
|
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"},
|
||||||
{"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},
|
/* start "museum" IDs */
|
||||||
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
|
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
|
||||||
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"},
|
||||||
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"},
|
||||||
|
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||||
|
|
||||||
|
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"},
|
||||||
|
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
|
||||||
|
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"},
|
||||||
|
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"},
|
||||||
/* end "museum" IDs */
|
/* end "museum" IDs */
|
||||||
|
|
||||||
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"},
|
||||||
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"},
|
||||||
{"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 1.8V 16-bit"},
|
||||||
{"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
|
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"},
|
||||||
{"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
|
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"},
|
||||||
{"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 1.8V 16-bit"},
|
||||||
{"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
|
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"},
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
|
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 1.8V 16-bit"},
|
||||||
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
|
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||||
{"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
|
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
|
||||||
{"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
|
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"},
|
||||||
{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
|
||||||
{"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
|
||||||
{"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
|
||||||
{"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
|
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
|
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"},
|
||||||
|
|
||||||
{"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
|
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"},
|
||||||
{"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
|
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"},
|
||||||
{"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
|
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"},
|
||||||
{"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
|
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
|
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"},
|
||||||
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
|
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"},
|
||||||
{"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
|
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"},
|
||||||
{"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
|
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
|
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"},
|
||||||
{"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
|
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"},
|
||||||
{"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
|
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"},
|
||||||
{"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
|
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
|
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"},
|
||||||
{"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
|
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"},
|
||||||
{"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
|
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"},
|
||||||
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
|
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
|
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"},
|
||||||
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
|
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"},
|
||||||
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
|
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"},
|
||||||
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
|
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
|
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"},
|
||||||
{"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
|
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||||
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
|
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"},
|
||||||
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
|
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"},
|
||||||
|
|
||||||
{NULL, 0, 0, 0, 0, 0 }
|
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
|
||||||
|
|
||||||
|
{0, 0, 0, 0, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Manufacturer ID list
|
/* Manufacturer ID list
|
||||||
@@ -160,7 +166,14 @@ static struct nand_ecclayout nand_oob_8 = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct nand_device *get_nand_device_by_name(const char *name)
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
static struct nand_device *get_nand_device_by_name(const char *name)
|
||||||
{
|
{
|
||||||
unsigned requested = get_flash_name_index(name);
|
unsigned requested = get_flash_name_index(name);
|
||||||
unsigned found = 0;
|
unsigned found = 0;
|
||||||
@@ -215,9 +228,11 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
|||||||
|
|
||||||
int nand_build_bbt(struct nand_device *nand, int first, int last)
|
int nand_build_bbt(struct nand_device *nand, int first, int last)
|
||||||
{
|
{
|
||||||
uint32_t page = 0x0;
|
uint32_t page;
|
||||||
int i;
|
int i;
|
||||||
|
int pages_per_block = (nand->erase_size / nand->page_size);
|
||||||
uint8_t oob[6];
|
uint8_t oob[6];
|
||||||
|
int ret;
|
||||||
|
|
||||||
if ((first < 0) || (first >= nand->num_blocks))
|
if ((first < 0) || (first >= nand->num_blocks))
|
||||||
first = 0;
|
first = 0;
|
||||||
@@ -225,9 +240,12 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
|
|||||||
if ((last >= nand->num_blocks) || (last == -1))
|
if ((last >= nand->num_blocks) || (last == -1))
|
||||||
last = nand->num_blocks - 1;
|
last = nand->num_blocks - 1;
|
||||||
|
|
||||||
for (i = first; i < last; i++)
|
page = first * pages_per_block;
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
{
|
{
|
||||||
nand_read_page(nand, page, NULL, 0, oob, 6);
|
ret = nand_read_page(nand, page, NULL, 0, oob, 6);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|
||||||
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
|
||||||
@@ -241,7 +259,7 @@ int nand_build_bbt(struct nand_device *nand, int first, int last)
|
|||||||
nand->blocks[i].is_bad = 0;
|
nand->blocks[i].is_bad = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
page += (nand->erase_size / nand->page_size);
|
page += pages_per_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -349,7 +367,9 @@ int nand_probe(struct nand_device *nand)
|
|||||||
|
|
||||||
for (i = 0; nand_flash_ids[i].name; i++)
|
for (i = 0; nand_flash_ids[i].name; i++)
|
||||||
{
|
{
|
||||||
if (nand_flash_ids[i].id == device_id)
|
if (nand_flash_ids[i].id == device_id &&
|
||||||
|
(nand_flash_ids[i].mfr_id == manufacturer_id ||
|
||||||
|
nand_flash_ids[i].mfr_id == 0 ))
|
||||||
{
|
{
|
||||||
nand->device = &nand_flash_ids[i];
|
nand->device = &nand_flash_ids[i];
|
||||||
break;
|
break;
|
||||||
@@ -521,7 +541,7 @@ int nand_erase(struct nand_device *nand, int first_block, int last_block)
|
|||||||
if (!nand->device)
|
if (!nand->device)
|
||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
|
|
||||||
if ((first_block < 0) || (last_block > nand->num_blocks))
|
if ((first_block < 0) || (last_block >= nand->num_blocks))
|
||||||
return ERROR_INVALID_ARGUMENTS;
|
return ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
/* make sure we know if a block is bad before erasing it */
|
/* make sure we know if a block is bad before erasing it */
|
||||||
@@ -764,6 +784,7 @@ int nand_page_command(struct nand_device *nand, uint32_t page,
|
|||||||
if (!nand->controller->nand_ready(nand, 100))
|
if (!nand->controller->nand_ready(nand, 100))
|
||||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||||
} else {
|
} else {
|
||||||
|
/* nand_poll_read() cannot be used during nand read */
|
||||||
alive_sleep(1);
|
alive_sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ struct nand_ecclayout {
|
|||||||
|
|
||||||
struct nand_device
|
struct nand_device
|
||||||
{
|
{
|
||||||
char *name;
|
const char *name;
|
||||||
|
struct target *target;
|
||||||
struct nand_flash_controller *controller;
|
struct nand_flash_controller *controller;
|
||||||
void *controller_priv;
|
void *controller_priv;
|
||||||
struct nand_manufacturer *manufacturer;
|
struct nand_manufacturer *manufacturer;
|
||||||
@@ -91,17 +92,18 @@ enum
|
|||||||
struct nand_manufacturer
|
struct nand_manufacturer
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nand_info
|
struct nand_info
|
||||||
{
|
{
|
||||||
char *name;
|
int mfr_id;
|
||||||
int id;
|
int id;
|
||||||
int page_size;
|
int page_size;
|
||||||
int chip_size;
|
int chip_size;
|
||||||
int erase_size;
|
int erase_size;
|
||||||
int options;
|
int options;
|
||||||
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Option constants for bizarre disfunctionality and real features
|
/* Option constants for bizarre disfunctionality and real features
|
||||||
@@ -197,15 +199,6 @@ enum oob_formats
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
struct nand_device *get_nand_device_by_num(int num);
|
||||||
|
|
||||||
int nand_page_command(struct nand_device *nand, uint32_t page,
|
int nand_page_command(struct nand_device *nand, uint32_t page,
|
||||||
@@ -230,7 +223,6 @@ int nand_calculate_ecc_kw(struct nand_device *nand,
|
|||||||
const uint8_t *dat, uint8_t *ecc_code);
|
const uint8_t *dat, uint8_t *ecc_code);
|
||||||
|
|
||||||
int nand_register_commands(struct command_context *cmd_ctx);
|
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
|
/// helper for parsing a nand device command argument string
|
||||||
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ enum ecc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct davinci_nand {
|
struct davinci_nand {
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
||||||
uint8_t eccmode;
|
uint8_t eccmode;
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ static int halted(struct target *target, const char *label)
|
|||||||
static int davinci_init(struct nand_device *nand)
|
static int davinci_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nandfcr;
|
uint32_t nandfcr;
|
||||||
|
|
||||||
if (!halted(target, "init"))
|
if (!halted(target, "init"))
|
||||||
@@ -112,7 +110,7 @@ static int davinci_reset(struct nand_device *nand)
|
|||||||
static int davinci_nand_ready(struct nand_device *nand, int timeout)
|
static int davinci_nand_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nandfsr;
|
uint32_t nandfsr;
|
||||||
|
|
||||||
/* NOTE: return code is zero/error, else success; not ERROR_* */
|
/* NOTE: return code is zero/error, else success; not ERROR_* */
|
||||||
@@ -135,7 +133,7 @@ static int davinci_nand_ready(struct nand_device *nand, int timeout)
|
|||||||
static int davinci_command(struct nand_device *nand, uint8_t command)
|
static int davinci_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!halted(target, "command"))
|
if (!halted(target, "command"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -147,7 +145,7 @@ static int davinci_command(struct nand_device *nand, uint8_t command)
|
|||||||
static int davinci_address(struct nand_device *nand, uint8_t address)
|
static int davinci_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!halted(target, "address"))
|
if (!halted(target, "address"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -159,7 +157,7 @@ static int davinci_address(struct nand_device *nand, uint8_t address)
|
|||||||
static int davinci_write_data(struct nand_device *nand, uint16_t data)
|
static int davinci_write_data(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!halted(target, "write_data"))
|
if (!halted(target, "write_data"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -171,7 +169,7 @@ static int davinci_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
static int davinci_read_data(struct nand_device *nand, void *data)
|
static int davinci_read_data(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (!halted(target, "read_data"))
|
if (!halted(target, "read_data"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
@@ -186,7 +184,7 @@ static int davinci_read_block_data(struct nand_device *nand,
|
|||||||
uint8_t *data, int data_size)
|
uint8_t *data, int data_size)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nfdata = info->data;
|
uint32_t nfdata = info->data;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
@@ -219,7 +217,7 @@ static int davinci_write_block_data(struct nand_device *nand,
|
|||||||
uint8_t *data, int data_size)
|
uint8_t *data, int data_size)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nfdata = info->data;
|
uint32_t nfdata = info->data;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
int status;
|
int status;
|
||||||
@@ -260,12 +258,12 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
if (!nand->device)
|
if (!nand->device)
|
||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
if (!halted(info->target, "write_page"))
|
if (!halted(nand->target, "write_page"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
|
||||||
/* Always write both data and OOB ... we are not "raw" I/O! */
|
/* Always write both data and OOB ... we are not "raw" I/O! */
|
||||||
if (!data) {
|
if (!data) {
|
||||||
LOG_ERROR("Missing NAND data; try 'nand raw_access enable'\n");
|
LOG_ERROR("Missing NAND data; try 'nand raw_access enable'");
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +307,7 @@ static int davinci_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
if (!nand->device)
|
if (!nand->device)
|
||||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||||
if (!halted(info->target, "read_page"))
|
if (!halted(nand->target, "read_page"))
|
||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
|
||||||
return info->read_page(nand, page, data, data_size, oob, oob_size);
|
return info->read_page(nand, page, data, data_size, oob, oob_size);
|
||||||
@@ -318,7 +316,7 @@ static int davinci_read_page(struct nand_device *nand, uint32_t page,
|
|||||||
static void davinci_write_pagecmd(struct nand_device *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;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
int page3 = nand->address_cycles - (nand->page_size == 512);
|
int page3 = nand->address_cycles - (nand->page_size == 512);
|
||||||
|
|
||||||
/* write command ({page,otp}x{read,program} */
|
/* write command ({page,otp}x{read,program} */
|
||||||
@@ -338,11 +336,32 @@ static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_
|
|||||||
target_write_u8(target, info->addr, page >> 24);
|
target_write_u8(target, info->addr, page >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int davinci_seek_column(struct nand_device *nand, uint16_t column)
|
||||||
|
{
|
||||||
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
/* Random read, we must have issued a page read already */
|
||||||
|
target_write_u8(target, info->cmd, NAND_CMD_RNDOUT);
|
||||||
|
|
||||||
|
target_write_u8(target, info->addr, column);
|
||||||
|
|
||||||
|
if (nand->page_size > 512) {
|
||||||
|
target_write_u8(target, info->addr, column >> 8);
|
||||||
|
target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!davinci_nand_ready(nand, 100))
|
||||||
|
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int davinci_writepage_tail(struct nand_device *nand,
|
static int davinci_writepage_tail(struct nand_device *nand,
|
||||||
uint8_t *oob, uint32_t oob_size)
|
uint8_t *oob, uint32_t oob_size)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
if (oob_size)
|
if (oob_size)
|
||||||
@@ -375,7 +394,7 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
|
|||||||
{
|
{
|
||||||
unsigned oob_offset;
|
unsigned oob_offset;
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||||
const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
|
const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
|
||||||
uint32_t fcr, ecc1;
|
uint32_t fcr, ecc1;
|
||||||
@@ -463,7 +482,7 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
const uint8_t *l;
|
const uint8_t *l;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||||
uint32_t fcr, ecc4;
|
uint32_t fcr, ecc4;
|
||||||
@@ -543,7 +562,7 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
|||||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info = nand->controller_priv;
|
struct davinci_nand *info = nand->controller_priv;
|
||||||
struct target *target = info->target;
|
struct target *target = nand->target;
|
||||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||||
uint32_t fcr, ecc4;
|
uint32_t fcr, ecc4;
|
||||||
@@ -599,6 +618,10 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
|||||||
static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
||||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||||
{
|
{
|
||||||
|
int read_size;
|
||||||
|
int want_col, at_col;
|
||||||
|
int ret;
|
||||||
|
|
||||||
davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
|
davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
|
||||||
|
|
||||||
/* large page devices need a start command */
|
/* large page devices need a start command */
|
||||||
@@ -610,25 +633,49 @@ static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
|
|||||||
|
|
||||||
/* NOTE: not bothering to compute and use ECC data for now */
|
/* NOTE: not bothering to compute and use ECC data for now */
|
||||||
|
|
||||||
do {
|
want_col = 0;
|
||||||
/* write 512 bytes */
|
at_col = 0;
|
||||||
davinci_read_block_data(nand, data, 512);
|
while ((data && data_size) || (oob && oob_size)) {
|
||||||
data += 512;
|
|
||||||
data_size -= 512;
|
|
||||||
|
|
||||||
|
if (data && data_size) {
|
||||||
|
if (want_col != at_col) {
|
||||||
|
/* Reads are slow, so seek past them when we can */
|
||||||
|
ret = davinci_seek_column(nand, want_col);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
at_col = want_col;
|
||||||
|
}
|
||||||
|
/* read 512 bytes or data_size, whichever is smaller*/
|
||||||
|
read_size = data_size > 512 ? 512 : data_size;
|
||||||
|
davinci_read_block_data(nand, data, read_size);
|
||||||
|
data += read_size;
|
||||||
|
data_size -= read_size;
|
||||||
|
at_col += read_size;
|
||||||
|
}
|
||||||
|
want_col += 512;
|
||||||
|
|
||||||
|
if (oob && oob_size) {
|
||||||
|
if (want_col != at_col) {
|
||||||
|
ret = davinci_seek_column(nand, want_col);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
at_col = want_col;
|
||||||
|
}
|
||||||
/* read this "out-of-band" data -- infix */
|
/* read this "out-of-band" data -- infix */
|
||||||
davinci_read_block_data(nand, oob, 16);
|
read_size = oob_size > 16 ? 16 : oob_size;
|
||||||
oob += 16;
|
davinci_read_block_data(nand, oob, read_size);
|
||||||
oob_size -= 16;
|
oob += read_size;
|
||||||
} while (data_size);
|
oob_size -= read_size;
|
||||||
|
at_col += read_size;
|
||||||
|
}
|
||||||
|
want_col += 16;
|
||||||
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||||
{
|
{
|
||||||
struct davinci_nand *info;
|
struct davinci_nand *info;
|
||||||
struct target *target;
|
|
||||||
unsigned long chip, aemif;
|
unsigned long chip, aemif;
|
||||||
enum ecc eccmode;
|
enum ecc eccmode;
|
||||||
int chipsel;
|
int chipsel;
|
||||||
@@ -648,12 +695,6 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
target = get_target(CMD_ARGV[1]);
|
|
||||||
if (!target) {
|
|
||||||
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
|
||||||
if (chip == 0) {
|
if (chip == 0) {
|
||||||
LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
|
LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
|
||||||
@@ -699,7 +740,6 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
|||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
info->target = target;
|
|
||||||
info->eccmode = eccmode;
|
info->eccmode = eccmode;
|
||||||
info->chipsel = chipsel;
|
info->chipsel = chipsel;
|
||||||
info->aemif = aemif;
|
info->aemif = aemif;
|
||||||
@@ -709,7 +749,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
|||||||
|
|
||||||
nand->controller_priv = info;
|
nand->controller_priv = info;
|
||||||
|
|
||||||
info->io.target = target;
|
info->io.target = nand->target;
|
||||||
info->io.data = info->data;
|
info->io.data = info->data;
|
||||||
info->io.op = ARM_NAND_NONE;
|
info->io.op = ARM_NAND_NONE;
|
||||||
|
|
||||||
|
|||||||
@@ -31,14 +31,17 @@
|
|||||||
extern struct nand_flash_controller nonce_nand_controller;
|
extern struct nand_flash_controller nonce_nand_controller;
|
||||||
extern struct nand_flash_controller davinci_nand_controller;
|
extern struct nand_flash_controller davinci_nand_controller;
|
||||||
extern struct nand_flash_controller lpc3180_nand_controller;
|
extern struct nand_flash_controller lpc3180_nand_controller;
|
||||||
|
extern struct nand_flash_controller lpc32xx_nand_controller;
|
||||||
extern struct nand_flash_controller orion_nand_controller;
|
extern struct nand_flash_controller orion_nand_controller;
|
||||||
extern struct nand_flash_controller s3c2410_nand_controller;
|
extern struct nand_flash_controller s3c2410_nand_controller;
|
||||||
extern struct nand_flash_controller s3c2412_nand_controller;
|
extern struct nand_flash_controller s3c2412_nand_controller;
|
||||||
extern struct nand_flash_controller s3c2440_nand_controller;
|
extern struct nand_flash_controller s3c2440_nand_controller;
|
||||||
extern struct nand_flash_controller s3c2443_nand_controller;
|
extern struct nand_flash_controller s3c2443_nand_controller;
|
||||||
extern struct nand_flash_controller s3c6400_nand_controller;
|
extern struct nand_flash_controller s3c6400_nand_controller;
|
||||||
|
extern struct nand_flash_controller imx27_nand_flash_controller;
|
||||||
extern struct nand_flash_controller imx31_nand_flash_controller;
|
extern struct nand_flash_controller imx31_nand_flash_controller;
|
||||||
extern struct nand_flash_controller at91sam9_nand_controller;
|
extern struct nand_flash_controller at91sam9_nand_controller;
|
||||||
|
extern struct nand_flash_controller nuc910_nand_controller;
|
||||||
|
|
||||||
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
|
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
|
||||||
|
|
||||||
@@ -47,14 +50,17 @@ static struct nand_flash_controller *nand_flash_controllers[] =
|
|||||||
&nonce_nand_controller,
|
&nonce_nand_controller,
|
||||||
&davinci_nand_controller,
|
&davinci_nand_controller,
|
||||||
&lpc3180_nand_controller,
|
&lpc3180_nand_controller,
|
||||||
|
&lpc32xx_nand_controller,
|
||||||
&orion_nand_controller,
|
&orion_nand_controller,
|
||||||
&s3c2410_nand_controller,
|
&s3c2410_nand_controller,
|
||||||
&s3c2412_nand_controller,
|
&s3c2412_nand_controller,
|
||||||
&s3c2440_nand_controller,
|
&s3c2440_nand_controller,
|
||||||
&s3c2443_nand_controller,
|
&s3c2443_nand_controller,
|
||||||
&s3c6400_nand_controller,
|
&s3c6400_nand_controller,
|
||||||
|
&imx27_nand_flash_controller,
|
||||||
&imx31_nand_flash_controller,
|
&imx31_nand_flash_controller,
|
||||||
&at91sam9_nand_controller,
|
&at91sam9_nand_controller,
|
||||||
|
&nuc910_nand_controller,
|
||||||
/* &boundary_scan_nand_controller, */
|
/* &boundary_scan_nand_controller, */
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,16 +35,13 @@ struct nand_device;
|
|||||||
struct nand_flash_controller
|
struct nand_flash_controller
|
||||||
{
|
{
|
||||||
/** Driver name that is used to select it from configuration files. */
|
/** Driver name that is used to select it from configuration files. */
|
||||||
char *name;
|
const char *name;
|
||||||
|
|
||||||
const struct command_registration *commands;
|
const struct command_registration *commands;
|
||||||
|
|
||||||
/** NAND device command called when driver is instantiated during configuration. */
|
/** NAND device command called when driver is instantiated during configuration. */
|
||||||
__NAND_DEVICE_COMMAND((*nand_device_command));
|
__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. */
|
/** Initialize the NAND device. */
|
||||||
int (*init)(struct nand_device *nand);
|
int (*init)(struct nand_device *nand);
|
||||||
|
|
||||||
@@ -75,9 +72,6 @@ struct nand_flash_controller
|
|||||||
/** Read a page from the NAND device. */
|
/** Read a page from the NAND device. */
|
||||||
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||||
|
|
||||||
/** Check if the 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. */
|
/** Check if the NAND device is ready for more instructions with timeout. */
|
||||||
int (*nand_ready)(struct nand_device *nand, int timeout);
|
int (*nand_ready)(struct nand_device *nand, int timeout);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,3 +120,64 @@ int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ec
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int countbits(uint32_t b)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
for (;b; b >>= 1)
|
||||||
|
res += b & 0x01;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_correct_data - Detect and correct a 1 bit error for 256 byte block
|
||||||
|
*/
|
||||||
|
int nand_correct_data(struct nand_device *nand, u_char *dat,
|
||||||
|
u_char *read_ecc, u_char *calc_ecc)
|
||||||
|
{
|
||||||
|
uint8_t s0, s1, s2;
|
||||||
|
|
||||||
|
#ifdef NAND_ECC_SMC
|
||||||
|
s0 = calc_ecc[0] ^ read_ecc[0];
|
||||||
|
s1 = calc_ecc[1] ^ read_ecc[1];
|
||||||
|
s2 = calc_ecc[2] ^ read_ecc[2];
|
||||||
|
#else
|
||||||
|
s1 = calc_ecc[0] ^ read_ecc[0];
|
||||||
|
s0 = calc_ecc[1] ^ read_ecc[1];
|
||||||
|
s2 = calc_ecc[2] ^ read_ecc[2];
|
||||||
|
#endif
|
||||||
|
if ((s0 | s1 | s2) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check for a single bit error */
|
||||||
|
if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 &&
|
||||||
|
((s1 ^ (s1 >> 1)) & 0x55) == 0x55 &&
|
||||||
|
((s2 ^ (s2 >> 1)) & 0x54) == 0x54) {
|
||||||
|
|
||||||
|
uint32_t byteoffs, bitnum;
|
||||||
|
|
||||||
|
byteoffs = (s1 << 0) & 0x80;
|
||||||
|
byteoffs |= (s1 << 1) & 0x40;
|
||||||
|
byteoffs |= (s1 << 2) & 0x20;
|
||||||
|
byteoffs |= (s1 << 3) & 0x10;
|
||||||
|
|
||||||
|
byteoffs |= (s0 >> 4) & 0x08;
|
||||||
|
byteoffs |= (s0 >> 3) & 0x04;
|
||||||
|
byteoffs |= (s0 >> 2) & 0x02;
|
||||||
|
byteoffs |= (s0 >> 1) & 0x01;
|
||||||
|
|
||||||
|
bitnum = (s2 >> 5) & 0x04;
|
||||||
|
bitnum |= (s2 >> 4) & 0x02;
|
||||||
|
bitnum |= (s2 >> 3) & 0x01;
|
||||||
|
|
||||||
|
dat[byteoffs] ^= (1 << bitnum);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -180,7 +180,13 @@ COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!need_size)
|
if (!need_size)
|
||||||
state->size = state->fileio.size;
|
{
|
||||||
|
int filesize;
|
||||||
|
retval = fileio_size(&state->fileio, &filesize);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
state->size = filesize;
|
||||||
|
}
|
||||||
|
|
||||||
*dev = nand;
|
*dev = nand;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2007 by Dominic Rath *
|
* Copyright (C) 2007 by Dominic Rath *
|
||||||
* Dominic.Rath@gmx.de *
|
* Dominic.Rath@gmx.de *
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 richard vegh <vegh.ricsi@gmail.com> *
|
||||||
|
* Copyright (C) 2010 Oyvind Harboe <oyvind.harboe@zylin.com> *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -28,6 +31,13 @@
|
|||||||
|
|
||||||
static int lpc3180_reset(struct nand_device *nand);
|
static int lpc3180_reset(struct nand_device *nand);
|
||||||
static int lpc3180_controller_ready(struct nand_device *nand, int timeout);
|
static int lpc3180_controller_ready(struct nand_device *nand, int timeout);
|
||||||
|
static int lpc3180_tc_ready(struct nand_device *nand, int timeout);
|
||||||
|
|
||||||
|
|
||||||
|
#define ECC_OFFS 0x120
|
||||||
|
#define SPARE_OFFS 0x140
|
||||||
|
#define DATA_OFFS 0x200
|
||||||
|
|
||||||
|
|
||||||
/* nand device lpc3180 <target#> <oscillator_frequency>
|
/* nand device lpc3180 <target#> <oscillator_frequency>
|
||||||
*/
|
*/
|
||||||
@@ -39,13 +49,6 @@ NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command)
|
|||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct target *target = get_target(CMD_ARGV[1]);
|
|
||||||
if (NULL == target)
|
|
||||||
{
|
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
|
||||||
return ERROR_NAND_DEVICE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t osc_freq;
|
uint32_t osc_freq;
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq);
|
||||||
|
|
||||||
@@ -53,7 +56,6 @@ NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command)
|
|||||||
lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller));
|
lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller));
|
||||||
nand->controller_priv = lpc3180_info;
|
nand->controller_priv = lpc3180_info;
|
||||||
|
|
||||||
lpc3180_info->target = target;
|
|
||||||
lpc3180_info->osc_freq = osc_freq;
|
lpc3180_info->osc_freq = osc_freq;
|
||||||
|
|
||||||
if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
|
if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
|
||||||
@@ -96,9 +98,10 @@ static int lpc3180_pll(int fclkin, uint32_t pll_ctrl)
|
|||||||
return (m / (2 * p)) * (fclkin / n);
|
return (m / (2 * p)) * (fclkin / n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float lpc3180_cycle_time(struct lpc3180_nand_controller *lpc3180_info)
|
static float lpc3180_cycle_time(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct target *target = lpc3180_info->target;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
|
uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
|
||||||
int sysclk;
|
int sysclk;
|
||||||
int hclk;
|
int hclk;
|
||||||
@@ -149,7 +152,7 @@ static float lpc3180_cycle_time(struct lpc3180_nand_controller *lpc3180_info)
|
|||||||
static int lpc3180_init(struct nand_device *nand)
|
static int lpc3180_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
int bus_width = nand->bus_width ? : 8;
|
int bus_width = nand->bus_width ? : 8;
|
||||||
int address_cycles = nand->address_cycles ? : 3;
|
int address_cycles = nand->address_cycles ? : 3;
|
||||||
int page_size = nand->page_size ? : 512;
|
int page_size = nand->page_size ? : 512;
|
||||||
@@ -224,7 +227,7 @@ static int lpc3180_init(struct nand_device *nand)
|
|||||||
target_write_u32(target, 0x200b8030, mlc_icr_value);
|
target_write_u32(target, 0x200b8030, mlc_icr_value);
|
||||||
|
|
||||||
/* calculate NAND controller timings */
|
/* calculate NAND controller timings */
|
||||||
cycle = lpc3180_cycle_time(lpc3180_info);
|
cycle = lpc3180_cycle_time(nand);
|
||||||
|
|
||||||
twp = ((40 / cycle) + 1);
|
twp = ((40 / cycle) + 1);
|
||||||
twh = ((20 / cycle) + 1);
|
twh = ((20 / cycle) + 1);
|
||||||
@@ -253,11 +256,24 @@ static int lpc3180_init(struct nand_device *nand)
|
|||||||
/* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */
|
/* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */
|
||||||
target_write_u32(target, 0x400040c8, 0x05);
|
target_write_u32(target, 0x400040c8, 0x05);
|
||||||
|
|
||||||
/* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */
|
/* after reset set other registers of SLC so reset calling is here at the begining*/
|
||||||
target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);
|
lpc3180_reset(nand);
|
||||||
|
|
||||||
|
/* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width) */
|
||||||
|
target_write_u32(target, 0x20020014, 0x3e | (bus_width == 16) ? 1 : 0);
|
||||||
|
|
||||||
|
/* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */
|
||||||
|
target_write_u32(target, 0x20020020, 0x03);
|
||||||
|
|
||||||
|
/* DMA configuration */
|
||||||
|
/* DMACLK_CTRL = 0x01 (enable clock for DMA controller) */
|
||||||
|
target_write_u32(target, 0x400040e8, 0x01);
|
||||||
|
/* DMACConfig = DMA enabled*/
|
||||||
|
target_write_u32(target, 0x31000030, 0x01);
|
||||||
|
|
||||||
|
|
||||||
/* calculate NAND controller timings */
|
/* calculate NAND controller timings */
|
||||||
cycle = lpc3180_cycle_time(lpc3180_info);
|
cycle = lpc3180_cycle_time(nand);
|
||||||
|
|
||||||
r_setup = w_setup = 0;
|
r_setup = w_setup = 0;
|
||||||
r_hold = w_hold = 10 / cycle;
|
r_hold = w_hold = 10 / cycle;
|
||||||
@@ -270,7 +286,6 @@ static int lpc3180_init(struct nand_device *nand)
|
|||||||
((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) |
|
((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) |
|
||||||
((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28));
|
((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28));
|
||||||
|
|
||||||
lpc3180_reset(nand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -279,7 +294,7 @@ static int lpc3180_init(struct nand_device *nand)
|
|||||||
static int lpc3180_reset(struct nand_device *nand)
|
static int lpc3180_reset(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -321,7 +336,7 @@ static int lpc3180_reset(struct nand_device *nand)
|
|||||||
static int lpc3180_command(struct nand_device *nand, uint8_t command)
|
static int lpc3180_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -351,7 +366,7 @@ static int lpc3180_command(struct nand_device *nand, uint8_t command)
|
|||||||
static int lpc3180_address(struct nand_device *nand, uint8_t address)
|
static int lpc3180_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -381,7 +396,7 @@ static int lpc3180_address(struct nand_device *nand, uint8_t address)
|
|||||||
static int lpc3180_write_data(struct nand_device *nand, uint16_t data)
|
static int lpc3180_write_data(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -411,7 +426,7 @@ static int lpc3180_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
static int lpc3180_read_data(struct nand_device *nand, void *data)
|
static int lpc3180_read_data(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -473,9 +488,10 @@ static int lpc3180_read_data(struct nand_device *nand, void *data)
|
|||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
int retval;
|
int retval;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
uint8_t *page_buffer;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -490,7 +506,6 @@ static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *
|
|||||||
}
|
}
|
||||||
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||||
{
|
{
|
||||||
uint8_t *page_buffer;
|
|
||||||
uint8_t *oob_buffer;
|
uint8_t *oob_buffer;
|
||||||
int quarter, num_quarters;
|
int quarter, num_quarters;
|
||||||
|
|
||||||
@@ -606,8 +621,202 @@ static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *
|
|||||||
}
|
}
|
||||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Write both SLC NAND flash page main area and spare area.
|
||||||
|
* Small page -
|
||||||
|
* ------------------------------------------
|
||||||
|
* | 512 bytes main | 16 bytes spare |
|
||||||
|
* ------------------------------------------
|
||||||
|
* Large page -
|
||||||
|
* ------------------------------------------
|
||||||
|
* | 2048 bytes main | 64 bytes spare |
|
||||||
|
* ------------------------------------------
|
||||||
|
* If DMA & ECC enabled, then the ECC generated for the 1st 256-byte
|
||||||
|
* data is written to the 3rd word of the spare area. The ECC
|
||||||
|
* generated for the 2nd 256-byte data is written to the 4th word
|
||||||
|
* of the spare area. The ECC generated for the 3rd 256-byte data is
|
||||||
|
* written to the 7th word of the spare area. The ECC generated
|
||||||
|
* for the 4th 256-byte data is written to the 8th word of the
|
||||||
|
* spare area and so on.
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
int i=0,target_mem_base;
|
||||||
|
uint8_t *ecc_flash_buffer;
|
||||||
|
struct working_area *pworking_area;
|
||||||
|
|
||||||
|
|
||||||
|
if(lpc3180_info->is_bulk){
|
||||||
|
|
||||||
|
if (!data && oob){
|
||||||
|
/*if oob only mode is active original method is used as SLC controller hangs during DMA interworking. Anyway the code supports the oob only mode below. */
|
||||||
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
|
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||||
}
|
}
|
||||||
|
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* allocate a working area */
|
||||||
|
if (target->working_area_size < (uint32_t) nand->page_size + 0x200){
|
||||||
|
LOG_ERROR("Reserve at least 0x%x physical target working area",nand->page_size + 0x200);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (target->working_area_phys%4){
|
||||||
|
LOG_ERROR("Reserve the physical target working area at word boundary");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_ERROR("no working area specified, can't read LPC internal flash");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
target_mem_base = target->working_area_phys;
|
||||||
|
|
||||||
|
|
||||||
|
if (nand->page_size == 2048)
|
||||||
|
{
|
||||||
|
page_buffer = malloc(2048);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
page_buffer = malloc(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
ecc_flash_buffer = malloc(64);
|
||||||
|
|
||||||
|
/* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA write to SLC, WIDTH = bus_width) */
|
||||||
|
target_write_u32(target, 0x20020014, 0x3c);
|
||||||
|
|
||||||
|
if( data && !oob){
|
||||||
|
/* set DMA LLI-s in target memory and in DMA*/
|
||||||
|
for(i=0;i<nand->page_size/0x100;i++){
|
||||||
|
|
||||||
|
int tmp;
|
||||||
|
/* -------LLI for 256 byte block---------*/
|
||||||
|
/* DMACC0SrcAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base+0+i*32,target_mem_base+DATA_OFFS+i*256 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000100,target_mem_base+DATA_OFFS );
|
||||||
|
/* DMACCxDestAddr = SLC_DMA_DATA */
|
||||||
|
target_write_u32(target,target_mem_base+4+i*32,0x20020038 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000104,0x20020038 );
|
||||||
|
/* DMACCxLLI = next element */
|
||||||
|
tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc;
|
||||||
|
target_write_u32(target,target_mem_base+8+i*32, tmp );
|
||||||
|
if(i==0) target_write_u32(target,0x31000108, tmp );
|
||||||
|
/* DMACCxControl = TransferSize =64, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 1,
|
||||||
|
Destination increment = 0, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+12+i*32,0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31);
|
||||||
|
if(i==0) target_write_u32(target,0x3100010c,0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31);
|
||||||
|
|
||||||
|
/* -------LLI for 3 byte ECC---------*/
|
||||||
|
/* DMACC0SrcAddr = SLC_ECC*/
|
||||||
|
target_write_u32(target,target_mem_base+16+i*32,0x20020034 );
|
||||||
|
/* DMACCxDestAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base+20+i*32,target_mem_base+SPARE_OFFS+8+16*(i>>1)+(i%2)*4 );
|
||||||
|
/* DMACCxLLI = next element */
|
||||||
|
tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc;
|
||||||
|
target_write_u32(target,target_mem_base+24+i*32, tmp );
|
||||||
|
/* DMACCxControl = TransferSize =1, Source burst size =4, Destination burst size = 4, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0,
|
||||||
|
Destination increment = 1, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+28+i*32,0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27| 0<<31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (data && oob){
|
||||||
|
/* -------LLI for 512 or 2048 bytes page---------*/
|
||||||
|
/* DMACC0SrcAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base,target_mem_base+DATA_OFFS );
|
||||||
|
target_write_u32(target,0x31000100,target_mem_base+DATA_OFFS );
|
||||||
|
/* DMACCxDestAddr = SLC_DMA_DATA */
|
||||||
|
target_write_u32(target,target_mem_base+4,0x20020038 );
|
||||||
|
target_write_u32(target,0x31000104,0x20020038 );
|
||||||
|
/* DMACCxLLI = next element */
|
||||||
|
target_write_u32(target,target_mem_base+8, (target_mem_base+32)&0xfffffffc );
|
||||||
|
target_write_u32(target,0x31000108, (target_mem_base+32)&0xfffffffc );
|
||||||
|
/* DMACCxControl = TransferSize =512 or 128, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 1,
|
||||||
|
Destination increment = 0, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+12,(nand->page_size==2048?512:128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31);
|
||||||
|
target_write_u32(target,0x3100010c,(nand->page_size==2048?512:128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31);
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
else if (!data && oob){
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------LLI for spare area---------*/
|
||||||
|
/* DMACC0SrcAddr = SRAM*/
|
||||||
|
target_write_u32(target,target_mem_base+0+i*32,target_mem_base+SPARE_OFFS );
|
||||||
|
if(i==0) target_write_u32(target,0x31000100,target_mem_base+SPARE_OFFS );
|
||||||
|
/* DMACCxDestAddr = SLC_DMA_DATA */
|
||||||
|
target_write_u32(target,target_mem_base+4+i*32,0x20020038 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000104,0x20020038 );
|
||||||
|
/* DMACCxLLI = next element = NULL */
|
||||||
|
target_write_u32(target,target_mem_base+8+i*32, 0 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000108,0 );
|
||||||
|
/* DMACCxControl = TransferSize =16 for large page or 4 for small page, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 1,
|
||||||
|
Destination increment = 0, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+12+i*32, (nand->page_size==2048?0x10:0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31);
|
||||||
|
if(i==0) target_write_u32(target,0x3100010c,(nand->page_size==2048?0x10:0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27| 0<<31 );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
memset(ecc_flash_buffer, 0xff, 64);
|
||||||
|
if( oob ){
|
||||||
|
memcpy(ecc_flash_buffer,oob, oob_size);
|
||||||
|
}
|
||||||
|
target_write_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer);
|
||||||
|
|
||||||
|
if (data){
|
||||||
|
memset(page_buffer, 0xff, nand->page_size == 2048?2048:512);
|
||||||
|
memcpy(page_buffer,data, data_size);
|
||||||
|
target_write_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048?512:128, page_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(page_buffer);
|
||||||
|
free(ecc_flash_buffer);
|
||||||
|
|
||||||
|
/* Enable DMA after channel set up !
|
||||||
|
LLI only works when DMA is the flow controller!
|
||||||
|
*/
|
||||||
|
/* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), FlowCntrl = 2 (Pher -> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/
|
||||||
|
target_write_u32(target,0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* SLC_CTRL = 3 (START DMA), ECC_CLEAR */
|
||||||
|
target_write_u32(target, 0x20020010, 0x3);
|
||||||
|
|
||||||
|
/* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/
|
||||||
|
target_write_u32(target, 0x20020028, 2);
|
||||||
|
|
||||||
|
/* SLC_TC */
|
||||||
|
if (!data && oob)
|
||||||
|
target_write_u32(target, 0x20020030, (nand->page_size==2048?0x10:0x04));
|
||||||
|
else
|
||||||
|
target_write_u32(target, 0x20020030, (nand->page_size==2048?0x840:0x210));
|
||||||
|
|
||||||
|
nand_write_finish(nand);
|
||||||
|
|
||||||
|
|
||||||
|
if (!lpc3180_tc_ready(nand, 1000))
|
||||||
|
{
|
||||||
|
LOG_ERROR("timeout while waiting for completion of DMA");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_free_working_area(target,pworking_area);
|
||||||
|
|
||||||
|
LOG_INFO("Page = 0x%" PRIx32 " was written.",page);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -615,7 +824,8 @@ static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *
|
|||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
uint8_t *page_buffer;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -630,7 +840,6 @@ static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *d
|
|||||||
}
|
}
|
||||||
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||||
{
|
{
|
||||||
uint8_t *page_buffer;
|
|
||||||
uint8_t *oob_buffer;
|
uint8_t *oob_buffer;
|
||||||
uint32_t page_bytes_done = 0;
|
uint32_t page_bytes_done = 0;
|
||||||
uint32_t oob_bytes_done = 0;
|
uint32_t oob_bytes_done = 0;
|
||||||
@@ -753,6 +962,174 @@ static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *d
|
|||||||
}
|
}
|
||||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Read both SLC NAND flash page main area and spare area.
|
||||||
|
* Small page -
|
||||||
|
* ------------------------------------------
|
||||||
|
* | 512 bytes main | 16 bytes spare |
|
||||||
|
* ------------------------------------------
|
||||||
|
* Large page -
|
||||||
|
* ------------------------------------------
|
||||||
|
* | 2048 bytes main | 64 bytes spare |
|
||||||
|
* ------------------------------------------
|
||||||
|
* If DMA & ECC enabled, then the ECC generated for the 1st 256-byte
|
||||||
|
* data is compared with the 3rd word of the spare area. The ECC
|
||||||
|
* generated for the 2nd 256-byte data is compared with the 4th word
|
||||||
|
* of the spare area. The ECC generated for the 3rd 256-byte data is
|
||||||
|
* compared with the 7th word of the spare area. The ECC generated
|
||||||
|
* for the 4th 256-byte data is compared with the 8th word of the
|
||||||
|
* spare area and so on.
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
int retval,i,target_mem_base;
|
||||||
|
uint8_t *ecc_hw_buffer;
|
||||||
|
uint8_t *ecc_flash_buffer;
|
||||||
|
struct working_area *pworking_area;
|
||||||
|
|
||||||
|
if(lpc3180_info->is_bulk){
|
||||||
|
|
||||||
|
/* read always the data and also oob areas*/
|
||||||
|
|
||||||
|
retval = nand_page_command(nand, page, NAND_CMD_READ0, 0);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* allocate a working area */
|
||||||
|
if (target->working_area_size < (uint32_t) nand->page_size + 0x200){
|
||||||
|
LOG_ERROR("Reserve at least 0x%x physical target working area",nand->page_size + 0x200);
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (target->working_area_phys%4){
|
||||||
|
LOG_ERROR("Reserve the physical target working area at word boundary");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_ERROR("no working area specified, can't read LPC internal flash");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
target_mem_base = target->working_area_phys;
|
||||||
|
|
||||||
|
if (nand->page_size == 2048)
|
||||||
|
{
|
||||||
|
page_buffer = malloc(2048);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
page_buffer = malloc(512);
|
||||||
|
}
|
||||||
|
|
||||||
|
ecc_hw_buffer = malloc(32);
|
||||||
|
ecc_flash_buffer = malloc(64);
|
||||||
|
|
||||||
|
/* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width) */
|
||||||
|
target_write_u32(target, 0x20020014, 0x3e);
|
||||||
|
|
||||||
|
/* set DMA LLI-s in target memory and in DMA*/
|
||||||
|
for(i=0;i<nand->page_size/0x100;i++){
|
||||||
|
int tmp;
|
||||||
|
/* -------LLI for 256 byte block---------*/
|
||||||
|
/* DMACC0SrcAddr = SLC_DMA_DATA*/
|
||||||
|
target_write_u32(target,target_mem_base+0+i*32,0x20020038 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000100,0x20020038 );
|
||||||
|
/* DMACCxDestAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base+4+i*32,target_mem_base+DATA_OFFS+i*256 );
|
||||||
|
if(i==0) target_write_u32(target,0x31000104,target_mem_base+DATA_OFFS );
|
||||||
|
/* DMACCxLLI = next element */
|
||||||
|
tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc;
|
||||||
|
target_write_u32(target,target_mem_base+8+i*32, tmp );
|
||||||
|
if(i==0) target_write_u32(target,0x31000108, tmp );
|
||||||
|
/* DMACCxControl = TransferSize =64, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0,
|
||||||
|
Destination increment = 1, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+12+i*32,0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27| 0<<31);
|
||||||
|
if(i==0) target_write_u32(target,0x3100010c,0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27| 0<<31);
|
||||||
|
|
||||||
|
/* -------LLI for 3 byte ECC---------*/
|
||||||
|
/* DMACC0SrcAddr = SLC_ECC*/
|
||||||
|
target_write_u32(target,target_mem_base+16+i*32,0x20020034 );
|
||||||
|
/* DMACCxDestAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base+20+i*32,target_mem_base+ECC_OFFS+i*4 );
|
||||||
|
/* DMACCxLLI = next element */
|
||||||
|
tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc;
|
||||||
|
target_write_u32(target,target_mem_base+24+i*32, tmp );
|
||||||
|
/* DMACCxControl = TransferSize =1, Source burst size =4, Destination burst size = 4, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0,
|
||||||
|
Destination increment = 1, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+28+i*32,0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27| 0<<31);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------LLI for spare area---------*/
|
||||||
|
/* DMACC0SrcAddr = SLC_DMA_DATA*/
|
||||||
|
target_write_u32(target,target_mem_base+0+i*32,0x20020038 );
|
||||||
|
/* DMACCxDestAddr = SRAM */
|
||||||
|
target_write_u32(target,target_mem_base+4+i*32,target_mem_base+SPARE_OFFS );
|
||||||
|
/* DMACCxLLI = next element = NULL */
|
||||||
|
target_write_u32(target,target_mem_base+8+i*32, 0 );
|
||||||
|
/* DMACCxControl = TransferSize =16 for large page or 4 for small page, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit,
|
||||||
|
Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0,
|
||||||
|
Destination increment = 1, Terminal count interrupt enable bit = 0*/
|
||||||
|
target_write_u32(target,target_mem_base+12+i*32, (nand->page_size==2048?0x10:0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27| 0<<31);
|
||||||
|
|
||||||
|
/* Enable DMA after channel set up !
|
||||||
|
LLI only works when DMA is the flow controller!
|
||||||
|
*/
|
||||||
|
/* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), FlowCntrl = 2 (Pher-> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/
|
||||||
|
target_write_u32(target,0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18);
|
||||||
|
|
||||||
|
|
||||||
|
/* SLC_CTRL = 3 (START DMA), ECC_CLEAR */
|
||||||
|
target_write_u32(target, 0x20020010, 0x3);
|
||||||
|
|
||||||
|
/* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/
|
||||||
|
target_write_u32(target, 0x20020028, 2);
|
||||||
|
|
||||||
|
/* SLC_TC */
|
||||||
|
target_write_u32(target, 0x20020030, (nand->page_size==2048?0x840:0x210));
|
||||||
|
|
||||||
|
if (!lpc3180_tc_ready(nand, 1000))
|
||||||
|
{
|
||||||
|
LOG_ERROR("timeout while waiting for completion of DMA");
|
||||||
|
free(page_buffer);
|
||||||
|
free(ecc_hw_buffer);
|
||||||
|
free(ecc_flash_buffer);
|
||||||
|
target_free_working_area(target,pworking_area);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data){
|
||||||
|
target_read_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048?512:128, page_buffer);
|
||||||
|
memcpy(data, page_buffer, data_size);
|
||||||
|
|
||||||
|
LOG_INFO("Page = 0x%" PRIx32 " was read.",page);
|
||||||
|
|
||||||
|
/* check hw generated ECC for each 256 bytes block with the saved ECC in flash spare area*/
|
||||||
|
int idx = nand->page_size/0x200 ;
|
||||||
|
target_read_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer);
|
||||||
|
target_read_memory(target, target_mem_base+ECC_OFFS, 4, 8, ecc_hw_buffer);
|
||||||
|
for(i=0;i<idx;i++){
|
||||||
|
if( (0x00ffffff&*(uint32_t *)(void *)(ecc_hw_buffer+i*8)) != (0x00ffffff&*(uint32_t *)(void *)(ecc_flash_buffer+8+i*16)) )
|
||||||
|
LOG_WARNING("ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32,i*2+1,page);
|
||||||
|
if( (0x00ffffff&*(uint32_t *)(void *)(ecc_hw_buffer+4+i*8)) != (0x00ffffff&*(uint32_t *)(void *)(ecc_flash_buffer+12+i*16)) )
|
||||||
|
LOG_WARNING("ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32,i*2+2,page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oob)
|
||||||
|
memcpy(oob, ecc_flash_buffer, oob_size);
|
||||||
|
|
||||||
|
free(page_buffer);
|
||||||
|
free(ecc_hw_buffer);
|
||||||
|
free(ecc_flash_buffer);
|
||||||
|
|
||||||
|
target_free_working_area(target,pworking_area);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
|
return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,7 +1139,7 @@ static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *d
|
|||||||
static int lpc3180_controller_ready(struct nand_device *nand, int timeout)
|
static int lpc3180_controller_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -810,7 +1187,7 @@ static int lpc3180_controller_ready(struct nand_device *nand, int timeout)
|
|||||||
static int lpc3180_nand_ready(struct nand_device *nand, int timeout)
|
static int lpc3180_nand_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
struct target *target = lpc3180_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -855,6 +1232,42 @@ static int lpc3180_nand_ready(struct nand_device *nand, int timeout)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lpc3180_tc_ready(struct nand_device *nand, int timeout)
|
||||||
|
{
|
||||||
|
struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("lpc3180_tc_ready count start=%d",
|
||||||
|
timeout);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||||
|
{
|
||||||
|
uint32_t status = 0x0;
|
||||||
|
/* Read SLC_INT_STAT and check INT_TC_STAT bit */
|
||||||
|
target_read_u32(target, 0x2002001c, &status);
|
||||||
|
|
||||||
|
if (status & 2){
|
||||||
|
LOG_DEBUG("lpc3180_tc_ready count=%d",
|
||||||
|
timeout);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alive_sleep(1);
|
||||||
|
} while (timeout-- > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_lpc3180_select_command)
|
COMMAND_HANDLER(handle_lpc3180_select_command)
|
||||||
{
|
{
|
||||||
struct lpc3180_nand_controller *lpc3180_info = NULL;
|
struct lpc3180_nand_controller *lpc3180_info = NULL;
|
||||||
@@ -863,7 +1276,7 @@ COMMAND_HANDLER(handle_lpc3180_select_command)
|
|||||||
"no", "mlc", "slc"
|
"no", "mlc", "slc"
|
||||||
};
|
};
|
||||||
|
|
||||||
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
|
if ((CMD_ARGC < 1) || (CMD_ARGC > 3))
|
||||||
{
|
{
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
@@ -879,7 +1292,7 @@ COMMAND_HANDLER(handle_lpc3180_select_command)
|
|||||||
|
|
||||||
lpc3180_info = nand->controller_priv;
|
lpc3180_info = nand->controller_priv;
|
||||||
|
|
||||||
if (CMD_ARGC == 2)
|
if (CMD_ARGC >= 2)
|
||||||
{
|
{
|
||||||
if (strcmp(CMD_ARGV[1], "mlc") == 0)
|
if (strcmp(CMD_ARGV[1], "mlc") == 0)
|
||||||
{
|
{
|
||||||
@@ -888,6 +1301,12 @@ COMMAND_HANDLER(handle_lpc3180_select_command)
|
|||||||
else if (strcmp(CMD_ARGV[1], "slc") == 0)
|
else if (strcmp(CMD_ARGV[1], "slc") == 0)
|
||||||
{
|
{
|
||||||
lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
|
lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
|
||||||
|
if (CMD_ARGC == 3 && strcmp(CMD_ARGV[2], "bulk") == 0){
|
||||||
|
lpc3180_info->is_bulk = 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
lpc3180_info->is_bulk = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -895,7 +1314,12 @@ COMMAND_HANDLER(handle_lpc3180_select_command)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||||
command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]);
|
command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]);
|
||||||
|
else{
|
||||||
|
command_print(CMD_CTX, lpc3180_info->is_bulk?"%s controller selected bulk mode is avaliable":"%s controller selected bulk mode is not avaliable", selected[lpc3180_info->selected_controller]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -905,8 +1329,8 @@ static const struct command_registration lpc3180_exec_command_handlers[] = {
|
|||||||
.name = "select",
|
.name = "select",
|
||||||
.handler = handle_lpc3180_select_command,
|
.handler = handle_lpc3180_select_command,
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.help = "select MLC or SLC controller (default is MLC)",
|
.help = "select MLC or SLC controller (default is MLC), SLC can be set to bulk mode",
|
||||||
.usage = "bank_id ['mlc'|'slc']",
|
.usage = "bank_id ['mlc'|'slc' ['bulk'] ]",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
@@ -932,6 +1356,5 @@ struct nand_flash_controller lpc3180_nand_controller = {
|
|||||||
.read_data = lpc3180_read_data,
|
.read_data = lpc3180_read_data,
|
||||||
.write_page = lpc3180_write_page,
|
.write_page = lpc3180_write_page,
|
||||||
.read_page = lpc3180_read_page,
|
.read_page = lpc3180_read_page,
|
||||||
.controller_ready = lpc3180_controller_ready,
|
|
||||||
.nand_ready = lpc3180_nand_ready,
|
.nand_ready = lpc3180_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ enum lpc3180_selected_controller
|
|||||||
|
|
||||||
struct lpc3180_nand_controller
|
struct lpc3180_nand_controller
|
||||||
{
|
{
|
||||||
struct target *target;
|
|
||||||
int osc_freq;
|
int osc_freq;
|
||||||
enum lpc3180_selected_controller selected_controller;
|
enum lpc3180_selected_controller selected_controller;
|
||||||
|
int is_bulk;
|
||||||
int sw_write_protection;
|
int sw_write_protection;
|
||||||
uint32_t sw_wp_lower_bound;
|
uint32_t sw_wp_lower_bound;
|
||||||
uint32_t sw_wp_upper_bound;
|
uint32_t sw_wp_upper_bound;
|
||||||
|
|||||||
1828
src/flash/nand/lpc32xx.c
Normal file
1828
src/flash/nand/lpc32xx.c
Normal file
File diff suppressed because it is too large
Load Diff
39
src/flash/nand/lpc32xx.h
Normal file
39
src/flash/nand/lpc32xx.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2007 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* 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 LPC32xx_NAND_CONTROLLER_H
|
||||||
|
#define LPC32xx_NAND_CONTROLLER_H
|
||||||
|
|
||||||
|
enum lpc32xx_selected_controller
|
||||||
|
{
|
||||||
|
LPC32xx_NO_CONTROLLER,
|
||||||
|
LPC32xx_MLC_CONTROLLER,
|
||||||
|
LPC32xx_SLC_CONTROLLER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lpc32xx_nand_controller
|
||||||
|
{
|
||||||
|
int osc_freq;
|
||||||
|
enum lpc32xx_selected_controller selected_controller;
|
||||||
|
int sw_write_protection;
|
||||||
|
uint32_t sw_wp_lower_bound;
|
||||||
|
uint32_t sw_wp_upper_bound;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*LPC32xx_NAND_CONTROLLER_H */
|
||||||
761
src/flash/nand/mx2.c
Normal file
761
src/flash/nand/mx2.c
Normal file
@@ -0,0 +1,761 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2009 by Alexei Babich *
|
||||||
|
* Rezonans plc., Chelyabinsk, Russia *
|
||||||
|
* impatt@mail.ru *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2010 by Gaetan CARLIER *
|
||||||
|
* Trump s.a., Belgium *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Freescale iMX2* OpenOCD NAND Flash controller support.
|
||||||
|
* based on Freescale iMX3* OpenOCD NAND Flash controller support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @imx27
|
||||||
|
* tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #",
|
||||||
|
* "nand write # file 0", "nand verify"
|
||||||
|
*
|
||||||
|
* get_next_halfword_from_sram_buffer() not tested
|
||||||
|
* !! all function only tested with 2k page nand device; imx27_write_page
|
||||||
|
* writes the 4 MAIN_BUFFER's and is not compatible with < 2k page
|
||||||
|
* !! oob must be be used due to NFS bug
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include "mx2.h"
|
||||||
|
#include <target/target.h>
|
||||||
|
|
||||||
|
/* This permits to print (in LOG_INFO) how much bytes
|
||||||
|
* has been written after a page read or write.
|
||||||
|
* This is useful when OpenOCD is used with a graphical
|
||||||
|
* front-end to estimate progression of the global read/write
|
||||||
|
*/
|
||||||
|
#undef _MX2_PRINT_STAT
|
||||||
|
//#define _MX2_PRINT_STAT
|
||||||
|
|
||||||
|
static const char target_not_halted_err_msg[] =
|
||||||
|
"target must be halted to use mx2 NAND flash controller";
|
||||||
|
static const char data_block_size_err_msg[] =
|
||||||
|
"minimal granularity is one half-word, %" PRId32 " is incorrect";
|
||||||
|
static const char sram_buffer_bounds_err_msg[] =
|
||||||
|
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
|
||||||
|
static const char get_status_register_err_msg[] = "can't get NAND status";
|
||||||
|
static uint32_t in_sram_address;
|
||||||
|
static unsigned char sign_of_sequental_byte_read;
|
||||||
|
|
||||||
|
static int initialize_nf_controller(struct nand_device *nand);
|
||||||
|
static int get_next_byte_from_sram_buffer(struct target * target, uint8_t * value);
|
||||||
|
static int get_next_halfword_from_sram_buffer(struct target * target,
|
||||||
|
uint16_t * value);
|
||||||
|
static int poll_for_complete_op(struct target * target, const char *text);
|
||||||
|
static int validate_target_state(struct nand_device *nand);
|
||||||
|
static int do_data_output(struct nand_device *nand);
|
||||||
|
|
||||||
|
static int imx27_command(struct nand_device *nand, uint8_t command);
|
||||||
|
static int imx27_address(struct nand_device *nand, uint8_t address);
|
||||||
|
|
||||||
|
NAND_DEVICE_COMMAND_HANDLER(imx27_nand_device_command)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info;
|
||||||
|
int hwecc_needed;
|
||||||
|
int x;
|
||||||
|
mx2_nf_info = malloc(sizeof(struct mx2_nf_controller));
|
||||||
|
if (mx2_nf_info == NULL) {
|
||||||
|
LOG_ERROR("no memory for nand controller");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand->controller_priv = mx2_nf_info;
|
||||||
|
if (CMD_ARGC < 3) {
|
||||||
|
LOG_ERROR("use \"nand device imx27 target noecc|hwecc\"");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* check hwecc requirements
|
||||||
|
*/
|
||||||
|
|
||||||
|
hwecc_needed = strcmp(CMD_ARGV[2], "hwecc");
|
||||||
|
if (hwecc_needed == 0)
|
||||||
|
mx2_nf_info->flags.hw_ecc_enabled = 1;
|
||||||
|
else
|
||||||
|
mx2_nf_info->flags.hw_ecc_enabled = 0;
|
||||||
|
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_NONE;
|
||||||
|
mx2_nf_info->flags.target_little_endian =
|
||||||
|
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
|
||||||
|
/*
|
||||||
|
* testing host endianness
|
||||||
|
*/
|
||||||
|
x = 1;
|
||||||
|
if (*(char *) &x == 1)
|
||||||
|
mx2_nf_info->flags.host_little_endian = 1;
|
||||||
|
else
|
||||||
|
mx2_nf_info->flags.host_little_endian = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_init(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
int validate_target_result;
|
||||||
|
uint16_t buffsize_register_content;
|
||||||
|
uint32_t pcsr_register_content;
|
||||||
|
int retval;
|
||||||
|
uint16_t nand_status_content;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
target_read_u16(target, MX2_NF_BUFSIZ, &buffsize_register_content);
|
||||||
|
mx2_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
|
||||||
|
|
||||||
|
target_read_u32(target, MX2_FMCR, &pcsr_register_content);
|
||||||
|
if (!nand->bus_width) {
|
||||||
|
/* bus_width not yet defined. Read it from MX2_FMCR */
|
||||||
|
nand->bus_width =
|
||||||
|
(pcsr_register_content & MX2_FMCR_NF_16BIT_SEL) ? 16 : 8;
|
||||||
|
} else {
|
||||||
|
/* bus_width forced in soft. Sync it to MX2_FMCR */
|
||||||
|
pcsr_register_content |=
|
||||||
|
((nand->bus_width == 16) ? MX2_FMCR_NF_16BIT_SEL : 0x00000000);
|
||||||
|
target_write_u32(target, MX2_FMCR, pcsr_register_content);
|
||||||
|
}
|
||||||
|
if (nand->bus_width == 16)
|
||||||
|
LOG_DEBUG("MX2_NF : bus is 16-bit width");
|
||||||
|
else
|
||||||
|
LOG_DEBUG("MX2_NF : bus is 8-bit width");
|
||||||
|
|
||||||
|
if (!nand->page_size) {
|
||||||
|
nand->page_size =
|
||||||
|
(pcsr_register_content & MX2_FMCR_NF_FMS) ? 2048 : 512;
|
||||||
|
} else {
|
||||||
|
pcsr_register_content |=
|
||||||
|
((nand->page_size == 2048) ? MX2_FMCR_NF_FMS : 0x00000000);
|
||||||
|
target_write_u32(target, MX2_FMCR, pcsr_register_content);
|
||||||
|
}
|
||||||
|
if (mx2_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
|
||||||
|
LOG_ERROR("NAND controller have only 1 kb SRAM, so "
|
||||||
|
"pagesize 2048 is incompatible with it");
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("MX2_NF : NAND controller can handle pagesize of 2048");
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize_nf_controller(nand);
|
||||||
|
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_STATUS);
|
||||||
|
retval |= imx27_address(nand, 0x00);
|
||||||
|
retval |= do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR(get_status_register_err_msg);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
target_read_u16(target, MX2_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
|
if (!(nand_status_content & 0x0080)) {
|
||||||
|
LOG_INFO("NAND read-only");
|
||||||
|
mx2_nf_info->flags.nand_readonly = 1;
|
||||||
|
} else {
|
||||||
|
mx2_nf_info->flags.nand_readonly = 0;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_read_data(struct nand_device *nand, void *data)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
int try_data_output_from_nand_chip;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get data from nand chip
|
||||||
|
*/
|
||||||
|
try_data_output_from_nand_chip = do_data_output(nand);
|
||||||
|
if (try_data_output_from_nand_chip != ERROR_OK) {
|
||||||
|
LOG_ERROR("imx27_read_data : read data failed : '%x'",
|
||||||
|
try_data_output_from_nand_chip);
|
||||||
|
return try_data_output_from_nand_chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nand->bus_width == 16)
|
||||||
|
get_next_halfword_from_sram_buffer(target, data);
|
||||||
|
else
|
||||||
|
get_next_byte_from_sram_buffer(target, data);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_write_data(struct nand_device *nand, uint16_t data)
|
||||||
|
{
|
||||||
|
LOG_ERROR("write_data() not implemented");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_reset(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
int validate_target_result;
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
initialize_nf_controller(nand);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_command(struct nand_device *nand, uint8_t command)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
int poll_result;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
switch(command) {
|
||||||
|
case NAND_CMD_READOOB:
|
||||||
|
command = NAND_CMD_READ0;
|
||||||
|
/* set read point for data_read() and read_block_data() to
|
||||||
|
* spare area in SRAM buffer
|
||||||
|
*/
|
||||||
|
in_sram_address = MX2_NF_SPARE_BUFFER0;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_READ1:
|
||||||
|
command = NAND_CMD_READ0;
|
||||||
|
/*
|
||||||
|
* offset == one half of page size
|
||||||
|
*/
|
||||||
|
in_sram_address =
|
||||||
|
MX2_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_FCMD, command);
|
||||||
|
/*
|
||||||
|
* start command input operation (set MX2_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FCI);
|
||||||
|
poll_result = poll_for_complete_op(target, "command");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
/*
|
||||||
|
* reset cursor to begin of the buffer
|
||||||
|
*/
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
/* Handle special read command and adjust NF_CFG2(FDO) */
|
||||||
|
switch(command) {
|
||||||
|
case NAND_CMD_READID:
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDID;
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_STATUS:
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDSTATUS;
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
target_write_u16 (target, MX2_NF_BUFADDR, 0);
|
||||||
|
in_sram_address = 0;
|
||||||
|
break;
|
||||||
|
case NAND_CMD_READ0:
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ohter command use the default 'One page data out' FDO */
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_PAGE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_address(struct nand_device *nand, uint8_t address)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
int poll_result;
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_FADDR, address);
|
||||||
|
/*
|
||||||
|
* start address input operation (set MX2_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FAI);
|
||||||
|
poll_result = poll_for_complete_op(target, "address");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_nand_ready(struct nand_device *nand, int tout)
|
||||||
|
{
|
||||||
|
uint16_t poll_complete_status;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int validate_target_result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
validate_target_result = validate_target_state(nand);
|
||||||
|
if (validate_target_result != ERROR_OK)
|
||||||
|
return validate_target_result;
|
||||||
|
|
||||||
|
do {
|
||||||
|
target_read_u16(target, MX2_NF_CFG2, &poll_complete_status);
|
||||||
|
if (poll_complete_status & MX2_NF_BIT_OP_DONE)
|
||||||
|
return tout;
|
||||||
|
|
||||||
|
alive_sleep(1);
|
||||||
|
}
|
||||||
|
while (tout-- > 0);
|
||||||
|
return tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_write_page(struct nand_device *nand, uint32_t page,
|
||||||
|
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||||
|
uint32_t oob_size)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int retval;
|
||||||
|
uint16_t nand_status_content;
|
||||||
|
uint16_t swap1, swap2, new_swap1;
|
||||||
|
int poll_result;
|
||||||
|
if (data_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (oob_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (!data) {
|
||||||
|
LOG_ERROR("nothing to program");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
retval = validate_target_state(nand);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_SEQIN);
|
||||||
|
retval |= imx27_address(nand, 0); //col
|
||||||
|
retval |= imx27_address(nand, 0); //col
|
||||||
|
retval |= imx27_address(nand, page & 0xff); //page address
|
||||||
|
retval |= imx27_address(nand, (page >> 8) & 0xff); //page address
|
||||||
|
retval |= imx27_address(nand, (page >> 16) & 0xff); //page address
|
||||||
|
|
||||||
|
target_write_buffer(target, MX2_NF_MAIN_BUFFER0, data_size, data);
|
||||||
|
if (oob) {
|
||||||
|
if (mx2_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
/*
|
||||||
|
* part of spare block will be overrided by hardware
|
||||||
|
* ECC generator
|
||||||
|
*/
|
||||||
|
LOG_DEBUG("part of spare block will be overrided "
|
||||||
|
"by hardware ECC generator");
|
||||||
|
}
|
||||||
|
target_write_buffer(target, MX2_NF_SPARE_BUFFER0, oob_size,
|
||||||
|
oob);
|
||||||
|
}
|
||||||
|
//BI-swap - work-around of imx27 NFC for NAND device with page == 2kb
|
||||||
|
target_read_u16(target, MX2_NF_MAIN_BUFFER3 + 464, &swap1);
|
||||||
|
if (oob) {
|
||||||
|
LOG_ERROR("Due to NFC Bug, oob is not correctly implemented "
|
||||||
|
"in mx2 driver");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
//target_read_u16 (target, MX2_NF_SPARE_BUFFER3 + 4, &swap2);
|
||||||
|
swap2 = 0xffff; //Spare buffer unused forced to 0xffff
|
||||||
|
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
||||||
|
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_MAIN_BUFFER3 + 464, new_swap1);
|
||||||
|
target_write_u16(target, MX2_NF_SPARE_BUFFER3 + 4, swap2);
|
||||||
|
/*
|
||||||
|
* start data input operation (set MX2_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 0);
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
||||||
|
poll_result = poll_for_complete_op(target, "data input");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 1);
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
||||||
|
poll_result = poll_for_complete_op(target, "data input");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 2);
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
||||||
|
poll_result = poll_for_complete_op(target, "data input");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 3);
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_OP_FDI);
|
||||||
|
poll_result = poll_for_complete_op(target, "data input");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_PAGEPROG);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check status register
|
||||||
|
*/
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_STATUS);
|
||||||
|
target_write_u16 (target, MX2_NF_BUFADDR, 0);
|
||||||
|
mx2_nf_info->optype = MX2_NF_DATAOUT_NANDSTATUS;
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
retval |= do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR (get_status_register_err_msg);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
target_read_u16 (target, MX2_NF_MAIN_BUFFER0, &nand_status_content);
|
||||||
|
if (nand_status_content & 0x0001) {
|
||||||
|
/*
|
||||||
|
* page not correctly written
|
||||||
|
*/
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
#ifdef _MX2_PRINT_STAT
|
||||||
|
LOG_INFO("%d bytes newly written", data_size);
|
||||||
|
#endif
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx27_read_page(struct nand_device *nand, uint32_t page,
|
||||||
|
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||||
|
uint32_t oob_size)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int retval;
|
||||||
|
uint16_t swap1, swap2, new_swap1;
|
||||||
|
if (data_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, data_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
if (oob_size % 2) {
|
||||||
|
LOG_ERROR(data_block_size_err_msg, oob_size);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* validate target state
|
||||||
|
*/
|
||||||
|
retval = validate_target_state(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
/* Reset address_cycles before imx27_command ?? */
|
||||||
|
retval = ERROR_OK;
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_READ0);
|
||||||
|
|
||||||
|
retval |= imx27_address(nand, 0); //col
|
||||||
|
retval |= imx27_address(nand, 0); //col
|
||||||
|
retval |= imx27_address(nand, page & 0xff); //page address
|
||||||
|
retval |= imx27_address(nand, (page >> 8) & 0xff); //page address
|
||||||
|
retval |= imx27_address(nand, (page >> 16) & 0xff); //page address
|
||||||
|
retval |= imx27_command(nand, NAND_CMD_READSTART);
|
||||||
|
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 0);
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
retval = do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("MX2_NF : Error reading page 0");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
//Test nand page size to know how much MAIN_BUFFER must be written
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 1);
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
retval = do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("MX2_NF : Error reading page 1");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 2);
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
retval = do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("MX2_NF : Error reading page 2");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 3);
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_DATAOUT;
|
||||||
|
retval = do_data_output(nand);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("MX2_NF : Error reading page 3");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
//BI-swap - work-around of imx27 NFC for NAND device with page == 2k
|
||||||
|
target_read_u16(target, MX2_NF_MAIN_BUFFER3 + 464, &swap1);
|
||||||
|
target_read_u16(target, MX2_NF_SPARE_BUFFER3 + 4, &swap2);
|
||||||
|
new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
|
||||||
|
swap2 = (swap1 << 8) | (swap2 & 0xFF);
|
||||||
|
target_write_u16(target, MX2_NF_MAIN_BUFFER3 + 464, new_swap1);
|
||||||
|
target_write_u16(target, MX2_NF_SPARE_BUFFER3 + 4, swap2);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
target_read_buffer(target, MX2_NF_MAIN_BUFFER0, data_size, data);
|
||||||
|
if (oob)
|
||||||
|
target_read_buffer(target, MX2_NF_SPARE_BUFFER0, oob_size,
|
||||||
|
oob);
|
||||||
|
#ifdef _MX2_PRINT_STAT
|
||||||
|
if (data_size > 0) {
|
||||||
|
/* When Operation Status is read (when page is erased),
|
||||||
|
* this function is used but data_size is null.
|
||||||
|
*/
|
||||||
|
LOG_INFO("%d bytes newly read", data_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int initialize_nf_controller(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint16_t work_mode;
|
||||||
|
uint16_t temp;
|
||||||
|
/*
|
||||||
|
* resets NAND flash controller in zero time ? I dont know.
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_CFG1, MX2_NF_BIT_RESET_EN);
|
||||||
|
work_mode = MX2_NF_BIT_INT_DIS; /* disable interrupt */
|
||||||
|
if (target->endianness == TARGET_BIG_ENDIAN) {
|
||||||
|
LOG_DEBUG("MX2_NF : work in Big Endian mode");
|
||||||
|
work_mode |= MX2_NF_BIT_BE_EN;
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("MX2_NF : work in Little Endian mode");
|
||||||
|
}
|
||||||
|
if (mx2_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
LOG_DEBUG("MX2_NF : work with ECC mode");
|
||||||
|
work_mode |= MX2_NF_BIT_ECC_EN;
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("MX2_NF : work without ECC mode");
|
||||||
|
}
|
||||||
|
target_write_u16(target, MX2_NF_CFG1, work_mode);
|
||||||
|
/*
|
||||||
|
* unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_BUFCFG, 2);
|
||||||
|
target_read_u16(target, MX2_NF_FWP, &temp);
|
||||||
|
if ((temp & 0x0007) == 1) {
|
||||||
|
LOG_ERROR("NAND flash is tight-locked, reset needed");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unlock NAND flash for write
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_FWP, 4);
|
||||||
|
target_write_u16(target, MX2_NF_LOCKSTART, 0x0000);
|
||||||
|
target_write_u16(target, MX2_NF_LOCKEND, 0xFFFF);
|
||||||
|
/*
|
||||||
|
* 0x0000 means that first SRAM buffer @0xD800_0000 will be used
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_BUFADDR, 0x0000);
|
||||||
|
/*
|
||||||
|
* address of SRAM buffer
|
||||||
|
*/
|
||||||
|
in_sram_address = MX2_NF_MAIN_BUFFER0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_byte_from_sram_buffer(struct target * target, uint8_t * value)
|
||||||
|
{
|
||||||
|
static uint8_t even_byte = 0;
|
||||||
|
uint16_t temp;
|
||||||
|
/*
|
||||||
|
* host-big_endian ??
|
||||||
|
*/
|
||||||
|
if (sign_of_sequental_byte_read == 0)
|
||||||
|
even_byte = 0;
|
||||||
|
|
||||||
|
if (in_sram_address > MX2_NF_LAST_BUFFER_ADDR) {
|
||||||
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
|
*value = 0;
|
||||||
|
sign_of_sequental_byte_read = 0;
|
||||||
|
even_byte = 0;
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
} else {
|
||||||
|
target_read_u16(target, in_sram_address, &temp);
|
||||||
|
if (even_byte) {
|
||||||
|
*value = temp >> 8;
|
||||||
|
even_byte = 0;
|
||||||
|
in_sram_address += 2;
|
||||||
|
} else {
|
||||||
|
*value = temp & 0xff;
|
||||||
|
even_byte = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sign_of_sequental_byte_read = 1;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_halfword_from_sram_buffer(struct target * target,
|
||||||
|
uint16_t * value)
|
||||||
|
{
|
||||||
|
if (in_sram_address > MX2_NF_LAST_BUFFER_ADDR) {
|
||||||
|
LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
|
||||||
|
*value = 0;
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
} else {
|
||||||
|
target_read_u16(target, in_sram_address, value);
|
||||||
|
in_sram_address += 2;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int poll_for_complete_op(struct target * target, const char *text)
|
||||||
|
{
|
||||||
|
uint16_t poll_complete_status;
|
||||||
|
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) {
|
||||||
|
target_read_u16(target, MX2_NF_CFG2, &poll_complete_status);
|
||||||
|
if (poll_complete_status & MX2_NF_BIT_OP_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
usleep(10);
|
||||||
|
}
|
||||||
|
if (!(poll_complete_status & MX2_NF_BIT_OP_DONE)) {
|
||||||
|
LOG_ERROR("%s sending timeout", text);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int validate_target_state(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR(target_not_halted_err_msg);
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mx2_nf_info->flags.target_little_endian !=
|
||||||
|
(target->endianness == TARGET_LITTLE_ENDIAN)) {
|
||||||
|
/*
|
||||||
|
* endianness changed after NAND controller probed
|
||||||
|
*/
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_data_output(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct mx2_nf_controller *mx2_nf_info = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int poll_result;
|
||||||
|
uint16_t ecc_status;
|
||||||
|
switch(mx2_nf_info->fin) {
|
||||||
|
case MX2_NF_FIN_DATAOUT:
|
||||||
|
/*
|
||||||
|
* start data output operation (set MX2_NF_BIT_OP_DONE==0)
|
||||||
|
*/
|
||||||
|
target_write_u16(target, MX2_NF_CFG2, MX2_NF_BIT_DATAOUT_TYPE(mx2_nf_info->optype));
|
||||||
|
poll_result = poll_for_complete_op(target, "data output");
|
||||||
|
if (poll_result != ERROR_OK)
|
||||||
|
return poll_result;
|
||||||
|
|
||||||
|
mx2_nf_info->fin = MX2_NF_FIN_NONE;
|
||||||
|
/*
|
||||||
|
* ECC stuff
|
||||||
|
*/
|
||||||
|
if ((mx2_nf_info->optype == MX2_NF_DATAOUT_PAGE) && mx2_nf_info->flags.hw_ecc_enabled) {
|
||||||
|
target_read_u16(target, MX2_NF_ECCSTATUS, &ecc_status);
|
||||||
|
switch(ecc_status & 0x000c) {
|
||||||
|
case 1 << 2:
|
||||||
|
LOG_INFO("main area readed with 1 (correctable) error");
|
||||||
|
break;
|
||||||
|
case 2 << 2:
|
||||||
|
LOG_INFO("main area readed with more than 1 (incorrectable) error");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch(ecc_status & 0x0003) {
|
||||||
|
case 1:
|
||||||
|
LOG_INFO("spare area readed with 1 (correctable) error");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
LOG_INFO("main area readed with more than 1 (incorrectable) error");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MX2_NF_FIN_NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nand_flash_controller imx27_nand_flash_controller = {
|
||||||
|
.name = "imx27",
|
||||||
|
.nand_device_command = &imx27_nand_device_command,
|
||||||
|
.init = &imx27_init,
|
||||||
|
.reset = &imx27_reset,
|
||||||
|
.command = &imx27_command,
|
||||||
|
.address = &imx27_address,
|
||||||
|
.write_data = &imx27_write_data,
|
||||||
|
.read_data = &imx27_read_data,
|
||||||
|
.write_page = &imx27_write_page,
|
||||||
|
.read_page = &imx27_read_page,
|
||||||
|
.nand_ready = &imx27_nand_ready,
|
||||||
|
};
|
||||||
119
src/flash/nand/mx2.h
Normal file
119
src/flash/nand/mx2.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2009 by Alexei Babich *
|
||||||
|
* Rezonans plc., Chelyabinsk, Russia *
|
||||||
|
* impatt@mail.ru *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Freescale iMX2* OpenOCD NAND Flash controller support.
|
||||||
|
* based on Freescale iMX3* OpenOCD NAND Flash controller support.
|
||||||
|
*
|
||||||
|
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MX2_NF_BASE_ADDR 0xd8000000
|
||||||
|
#define MX2_NF_BUFSIZ (MX2_NF_BASE_ADDR + 0xe00)
|
||||||
|
#define MX2_NF_BUFADDR (MX2_NF_BASE_ADDR + 0xe04)
|
||||||
|
#define MX2_NF_FADDR (MX2_NF_BASE_ADDR + 0xe06)
|
||||||
|
#define MX2_NF_FCMD (MX2_NF_BASE_ADDR + 0xe08)
|
||||||
|
#define MX2_NF_BUFCFG (MX2_NF_BASE_ADDR + 0xe0a)
|
||||||
|
#define MX2_NF_ECCSTATUS (MX2_NF_BASE_ADDR + 0xe0c)
|
||||||
|
#define MX2_NF_ECCMAINPOS (MX2_NF_BASE_ADDR + 0xe0e)
|
||||||
|
#define MX2_NF_ECCSPAREPOS (MX2_NF_BASE_ADDR + 0xe10)
|
||||||
|
#define MX2_NF_FWP (MX2_NF_BASE_ADDR + 0xe12)
|
||||||
|
#define MX2_NF_LOCKSTART (MX2_NF_BASE_ADDR + 0xe14)
|
||||||
|
#define MX2_NF_LOCKEND (MX2_NF_BASE_ADDR + 0xe16)
|
||||||
|
#define MX2_NF_FWPSTATUS (MX2_NF_BASE_ADDR + 0xe18)
|
||||||
|
/*
|
||||||
|
* all bits not marked as self-clearing bit
|
||||||
|
*/
|
||||||
|
#define MX2_NF_CFG1 (MX2_NF_BASE_ADDR + 0xe1a)
|
||||||
|
#define MX2_NF_CFG2 (MX2_NF_BASE_ADDR + 0xe1c)
|
||||||
|
|
||||||
|
#define MX2_NF_MAIN_BUFFER0 (MX2_NF_BASE_ADDR + 0x0000)
|
||||||
|
#define MX2_NF_MAIN_BUFFER1 (MX2_NF_BASE_ADDR + 0x0200)
|
||||||
|
#define MX2_NF_MAIN_BUFFER2 (MX2_NF_BASE_ADDR + 0x0400)
|
||||||
|
#define MX2_NF_MAIN_BUFFER3 (MX2_NF_BASE_ADDR + 0x0600)
|
||||||
|
#define MX2_NF_SPARE_BUFFER0 (MX2_NF_BASE_ADDR + 0x0800)
|
||||||
|
#define MX2_NF_SPARE_BUFFER1 (MX2_NF_BASE_ADDR + 0x0810)
|
||||||
|
#define MX2_NF_SPARE_BUFFER2 (MX2_NF_BASE_ADDR + 0x0820)
|
||||||
|
#define MX2_NF_SPARE_BUFFER3 (MX2_NF_BASE_ADDR + 0x0830)
|
||||||
|
#define MX2_NF_MAIN_BUFFER_LEN 512
|
||||||
|
#define MX2_NF_SPARE_BUFFER_LEN 16
|
||||||
|
#define MX2_NF_LAST_BUFFER_ADDR ((MX2_NF_SPARE_BUFFER3) + MX2_NF_SPARE_BUFFER_LEN - 2)
|
||||||
|
|
||||||
|
/* bits in MX2_NF_CFG1 register */
|
||||||
|
#define MX2_NF_BIT_SPARE_ONLY_EN (1<<2)
|
||||||
|
#define MX2_NF_BIT_ECC_EN (1<<3)
|
||||||
|
#define MX2_NF_BIT_INT_DIS (1<<4)
|
||||||
|
#define MX2_NF_BIT_BE_EN (1<<5)
|
||||||
|
#define MX2_NF_BIT_RESET_EN (1<<6)
|
||||||
|
#define MX2_NF_BIT_FORCE_CE (1<<7)
|
||||||
|
|
||||||
|
/* bits in MX2_NF_CFG2 register */
|
||||||
|
|
||||||
|
/*Flash Command Input*/
|
||||||
|
#define MX2_NF_BIT_OP_FCI (1<<0)
|
||||||
|
/*
|
||||||
|
* Flash Address Input
|
||||||
|
*/
|
||||||
|
#define MX2_NF_BIT_OP_FAI (1<<1)
|
||||||
|
/*
|
||||||
|
* Flash Data Input
|
||||||
|
*/
|
||||||
|
#define MX2_NF_BIT_OP_FDI (1<<2)
|
||||||
|
|
||||||
|
/* see "enum mx_dataout_type" below */
|
||||||
|
#define MX2_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
||||||
|
#define MX2_NF_BIT_OP_DONE (1<<15)
|
||||||
|
|
||||||
|
#define MX2_CCM_CGR2 0x53f80028
|
||||||
|
#define MX2_GPR 0x43fac008
|
||||||
|
//#define MX2_PCSR 0x53f8000c
|
||||||
|
#define MX2_FMCR 0x10027814
|
||||||
|
#define MX2_FMCR_NF_16BIT_SEL (1<<4)
|
||||||
|
#define MX2_FMCR_NF_FMS (1<<5)
|
||||||
|
|
||||||
|
enum mx_dataout_type
|
||||||
|
{
|
||||||
|
MX2_NF_DATAOUT_PAGE = 1,
|
||||||
|
MX2_NF_DATAOUT_NANDID = 2,
|
||||||
|
MX2_NF_DATAOUT_NANDSTATUS = 4,
|
||||||
|
};
|
||||||
|
enum mx_nf_finalize_action
|
||||||
|
{
|
||||||
|
MX2_NF_FIN_NONE,
|
||||||
|
MX2_NF_FIN_DATAOUT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mx2_nf_flags
|
||||||
|
{
|
||||||
|
unsigned host_little_endian:1;
|
||||||
|
unsigned target_little_endian:1;
|
||||||
|
unsigned nand_readonly:1;
|
||||||
|
unsigned one_kb_sram:1;
|
||||||
|
unsigned hw_ecc_enabled:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mx2_nf_controller
|
||||||
|
{
|
||||||
|
enum mx_dataout_type optype;
|
||||||
|
enum mx_nf_finalize_action fin;
|
||||||
|
struct mx2_nf_flags flags;
|
||||||
|
};
|
||||||
@@ -47,7 +47,7 @@ static const char sram_buffer_bounds_err_msg[] =
|
|||||||
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
|
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
|
||||||
static const char get_status_register_err_msg[] = "can't get NAND status";
|
static const char get_status_register_err_msg[] = "can't get NAND status";
|
||||||
static uint32_t in_sram_address;
|
static uint32_t in_sram_address;
|
||||||
unsigned char sign_of_sequental_byte_read;
|
static unsigned char sign_of_sequental_byte_read;
|
||||||
|
|
||||||
static int test_iomux_settings (struct target * target, uint32_t value,
|
static int test_iomux_settings (struct target * target, uint32_t value,
|
||||||
uint32_t mask, const char *text);
|
uint32_t mask, const char *text);
|
||||||
@@ -61,7 +61,6 @@ static int do_data_output (struct nand_device *nand);
|
|||||||
|
|
||||||
static int imx31_command (struct nand_device *nand, uint8_t command);
|
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_address (struct nand_device *nand, uint8_t address);
|
||||||
static int imx31_controller_ready (struct nand_device *nand, int tout);
|
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
||||||
{
|
{
|
||||||
@@ -75,12 +74,6 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
|
|
||||||
nand->controller_priv = mx3_nf_info;
|
nand->controller_priv = mx3_nf_info;
|
||||||
|
|
||||||
mx3_nf_info->target = get_target (CMD_ARGV[1]);
|
|
||||||
if (mx3_nf_info->target == NULL)
|
|
||||||
{
|
|
||||||
LOG_ERROR ("target '%s' not defined", CMD_ARGV[1]);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (CMD_ARGC < 3)
|
if (CMD_ARGC < 3)
|
||||||
{
|
{
|
||||||
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
|
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
|
||||||
@@ -105,9 +98,9 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
||||||
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
||||||
mx3_nf_info->flags.target_little_endian =
|
mx3_nf_info->flags.target_little_endian =
|
||||||
(mx3_nf_info->target->endianness == TARGET_LITTLE_ENDIAN);
|
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
|
||||||
/*
|
/*
|
||||||
* testing host endianess
|
* testing host endianness
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int x = 1;
|
int x = 1;
|
||||||
@@ -126,7 +119,7 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
|
|||||||
static int imx31_init (struct nand_device *nand)
|
static int imx31_init (struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -268,8 +261,7 @@ static int imx31_init (struct nand_device *nand)
|
|||||||
|
|
||||||
static int imx31_read_data (struct nand_device *nand, void *data)
|
static int imx31_read_data (struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = mx3_nf_info->target;
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* validate target state
|
* validate target state
|
||||||
@@ -312,11 +304,6 @@ static int imx31_write_data (struct nand_device *nand, uint16_t data)
|
|||||||
return ERROR_NAND_OPERATION_FAILED;
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx31_nand_ready (struct nand_device *nand, int timeout)
|
|
||||||
{
|
|
||||||
return imx31_controller_ready (nand, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int imx31_reset (struct nand_device *nand)
|
static int imx31_reset (struct nand_device *nand)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -335,7 +322,7 @@ static int imx31_reset (struct nand_device *nand)
|
|||||||
static int imx31_command (struct nand_device *nand, uint8_t command)
|
static int imx31_command (struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* validate target state
|
* validate target state
|
||||||
@@ -408,8 +395,7 @@ 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_address (struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = mx3_nf_info->target;
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* validate target state
|
* validate target state
|
||||||
@@ -438,11 +424,10 @@ static int imx31_address (struct nand_device *nand, uint8_t address)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx31_controller_ready (struct nand_device *nand, int tout)
|
static int imx31_nand_ready (struct nand_device *nand, int tout)
|
||||||
{
|
{
|
||||||
uint16_t poll_complete_status;
|
uint16_t poll_complete_status;
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = mx3_nf_info->target;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -474,7 +459,7 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
|
|||||||
uint32_t oob_size)
|
uint32_t oob_size)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (data_size % 2)
|
if (data_size % 2)
|
||||||
{
|
{
|
||||||
@@ -580,8 +565,7 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
|
|||||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||||
uint32_t oob_size)
|
uint32_t oob_size)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = mx3_nf_info->target;
|
|
||||||
|
|
||||||
if (data_size % 2)
|
if (data_size % 2)
|
||||||
{
|
{
|
||||||
@@ -656,7 +640,7 @@ static int test_iomux_settings (struct target * target, uint32_t address,
|
|||||||
static int initialize_nf_controller (struct nand_device *nand)
|
static int initialize_nf_controller (struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
/*
|
/*
|
||||||
* resets NAND flash controller in zero time ? I dont know.
|
* resets NAND flash controller in zero time ? I dont know.
|
||||||
*/
|
*/
|
||||||
@@ -784,7 +768,7 @@ static int poll_for_complete_op (struct target * target, const char *text)
|
|||||||
static int validate_target_state (struct nand_device *nand)
|
static int validate_target_state (struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED)
|
if (target->state != TARGET_HALTED)
|
||||||
{
|
{
|
||||||
@@ -806,7 +790,7 @@ static int validate_target_state (struct nand_device *nand)
|
|||||||
static int do_data_output (struct nand_device *nand)
|
static int do_data_output (struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
|
||||||
struct target *target = mx3_nf_info->target;
|
struct target *target = nand->target;
|
||||||
switch (mx3_nf_info->fin)
|
switch (mx3_nf_info->fin)
|
||||||
{
|
{
|
||||||
case MX3_NF_FIN_DATAOUT:
|
case MX3_NF_FIN_DATAOUT:
|
||||||
@@ -876,6 +860,5 @@ struct nand_flash_controller imx31_nand_flash_controller = {
|
|||||||
.read_data = &imx31_read_data,
|
.read_data = &imx31_read_data,
|
||||||
.write_page = &imx31_write_page,
|
.write_page = &imx31_write_page,
|
||||||
.read_page = &imx31_read_page,
|
.read_page = &imx31_read_page,
|
||||||
.controller_ready = &imx31_controller_ready,
|
|
||||||
.nand_ready = &imx31_nand_ready,
|
.nand_ready = &imx31_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ struct mx3_nf_flags
|
|||||||
|
|
||||||
struct mx3_nf_controller
|
struct mx3_nf_controller
|
||||||
{
|
{
|
||||||
struct target *target;
|
|
||||||
enum mx_dataout_type optype;
|
enum mx_dataout_type optype;
|
||||||
enum mx_nf_finalize_action fin;
|
enum mx_nf_finalize_action fin;
|
||||||
struct mx3_nf_flags flags;
|
struct mx3_nf_flags flags;
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ static int nonce_nand_reset(struct nand_device *nand)
|
|||||||
return nonce_nand_command(nand, NAND_CMD_RESET);
|
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)
|
NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command)
|
||||||
{
|
{
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -79,5 +74,4 @@ struct nand_flash_controller nonce_nand_controller =
|
|||||||
.read_data = &nonce_nand_read,
|
.read_data = &nonce_nand_read,
|
||||||
.write_data = &nonce_nand_write,
|
.write_data = &nonce_nand_write,
|
||||||
.write_block_data = &nonce_nand_fast_block_write,
|
.write_block_data = &nonce_nand_fast_block_write,
|
||||||
.controller_ready = &nonce_nand_controller_ready,
|
|
||||||
};
|
};
|
||||||
|
|||||||
226
src/flash/nand/nuc910.c
Normal file
226
src/flash/nand/nuc910.c
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NAND controller interface for Nuvoton NUC910
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include "nuc910.h"
|
||||||
|
#include "arm_io.h"
|
||||||
|
#include <target/arm.h>
|
||||||
|
|
||||||
|
struct nuc910_nand_controller
|
||||||
|
{
|
||||||
|
struct arm_nand_data io;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int validate_target_state(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_NAND_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_command(struct nand_device *nand, uint8_t command)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
target_write_u8(target, NUC910_SMCMD, command);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_address(struct nand_device *nand, uint8_t address)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA));
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_read(struct nand_device *nand, void *data)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
target_read_u8(target, NUC910_SMDATA, data);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_write(struct nand_device *nand, uint16_t data)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
target_write_u8(target, NUC910_SMDATA, data);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_read_block_data(struct nand_device *nand,
|
||||||
|
uint8_t *data, int data_size)
|
||||||
|
{
|
||||||
|
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
nuc910_nand->io.chunk_size = nand->page_size;
|
||||||
|
|
||||||
|
/* try the fast way first */
|
||||||
|
result = arm_nandread(&nuc910_nand->io, data, data_size);
|
||||||
|
if (result != ERROR_NAND_NO_BUFFER)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* else do it slowly */
|
||||||
|
while (data_size--)
|
||||||
|
nuc910_nand_read(nand, data++);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_write_block_data(struct nand_device *nand,
|
||||||
|
uint8_t *data, int data_size)
|
||||||
|
{
|
||||||
|
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
nuc910_nand->io.chunk_size = nand->page_size;
|
||||||
|
|
||||||
|
/* try the fast way first */
|
||||||
|
result = arm_nandwrite(&nuc910_nand->io, data, data_size);
|
||||||
|
if (result != ERROR_NAND_NO_BUFFER)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* else do it slowly */
|
||||||
|
while (data_size--)
|
||||||
|
nuc910_nand_write(nand, *data++);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_reset(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
return nuc910_nand_command(nand, NAND_CMD_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_ready(struct nand_device *nand, int timeout)
|
||||||
|
{
|
||||||
|
struct target *target = nand->target;
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
do {
|
||||||
|
target_read_u32(target, NUC910_SMISR, &status);
|
||||||
|
if (status & NUC910_SMISR_RB_) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
alive_sleep(1);
|
||||||
|
} while (timeout-- > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command)
|
||||||
|
{
|
||||||
|
struct nuc910_nand_controller *nuc910_nand;
|
||||||
|
|
||||||
|
nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller));
|
||||||
|
if (!nuc910_nand) {
|
||||||
|
LOG_ERROR("no memory for nand controller");
|
||||||
|
return ERROR_NAND_DEVICE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand->controller_priv = nuc910_nand;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nuc910_nand_init(struct nand_device *nand)
|
||||||
|
{
|
||||||
|
struct nuc910_nand_controller *nuc910_nand = nand->controller_priv;
|
||||||
|
struct target *target = nand->target;
|
||||||
|
int bus_width = nand->bus_width ? : 8;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result = validate_target_state(nand)) != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* nuc910 only supports 8bit */
|
||||||
|
if (bus_width != 8)
|
||||||
|
{
|
||||||
|
LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width);
|
||||||
|
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inform calling code about selected bus width */
|
||||||
|
nand->bus_width = bus_width;
|
||||||
|
|
||||||
|
nuc910_nand->io.target = target;
|
||||||
|
nuc910_nand->io.data = NUC910_SMDATA;
|
||||||
|
nuc910_nand->io.op = ARM_NAND_NONE;
|
||||||
|
|
||||||
|
/* configure nand controller */
|
||||||
|
target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN);
|
||||||
|
target_write_u32(target, NUC910_SMCSR, 0x010000a8); /* 2048 page size */
|
||||||
|
target_write_u32(target, NUC910_SMTCR, 0x00010204);
|
||||||
|
target_write_u32(target, NUC910_SMIER, 0x00000000);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nand_flash_controller nuc910_nand_controller =
|
||||||
|
{
|
||||||
|
.name = "nuc910",
|
||||||
|
.command = nuc910_nand_command,
|
||||||
|
.address = nuc910_nand_address,
|
||||||
|
.read_data = nuc910_nand_read,
|
||||||
|
.write_data = nuc910_nand_write,
|
||||||
|
.write_block_data = nuc910_nand_write_block_data,
|
||||||
|
.read_block_data = nuc910_nand_read_block_data,
|
||||||
|
.nand_ready = nuc910_nand_ready,
|
||||||
|
.reset = nuc910_nand_reset,
|
||||||
|
.nand_device_command = nuc910_nand_device_command,
|
||||||
|
.init = nuc910_nand_init,
|
||||||
|
};
|
||||||
60
src/flash/nand/nuc910.h
Normal file
60
src/flash/nand/nuc910.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2010 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NAND controller interface for Nuvoton NUC910
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NUC910_H
|
||||||
|
#define NUC910_H
|
||||||
|
|
||||||
|
#define NUC910_FMICSR 0xB000D000
|
||||||
|
#define NUC910_SMCSR 0xB000D0A0
|
||||||
|
#define NUC910_SMTCR 0xB000D0A4
|
||||||
|
#define NUC910_SMIER 0xB000D0A8
|
||||||
|
#define NUC910_SMISR 0xB000D0AC
|
||||||
|
#define NUC910_SMCMD 0xB000D0B0
|
||||||
|
#define NUC910_SMADDR 0xB000D0B4
|
||||||
|
#define NUC910_SMDATA 0xB000D0B8
|
||||||
|
|
||||||
|
#define NUC910_SMECC0 0xB000D0BC
|
||||||
|
#define NUC910_SMECC1 0xB000D0C0
|
||||||
|
#define NUC910_SMECC2 0xB000D0C4
|
||||||
|
#define NUC910_SMECC3 0xB000D0C8
|
||||||
|
#define NUC910_ECC4ST 0xB000D114
|
||||||
|
|
||||||
|
/* Global Control and Status Register (FMICSR) */
|
||||||
|
#define NUC910_FMICSR_SM_EN (1<<3)
|
||||||
|
|
||||||
|
/* NAND Flash Address Port Register (SMADDR) */
|
||||||
|
#define NUC910_SMADDR_EOA (1<<31)
|
||||||
|
|
||||||
|
/* NAND Flash Control and Status Register (SMCSR) */
|
||||||
|
#define NUC910_SMCSR_PSIZE (1<<3)
|
||||||
|
#define NUC910_SMCSR_DBW (1<<4)
|
||||||
|
|
||||||
|
/* NAND Flash Interrupt Status Register (SMISR) */
|
||||||
|
#define NUC910_SMISR_ECC_IF (1<<2)
|
||||||
|
#define NUC910_SMISR_RB_ (1<<18)
|
||||||
|
|
||||||
|
/* ECC4 Correction Status (ECC4ST) */
|
||||||
|
|
||||||
|
#endif /* NUC910_H */
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
struct orion_nand_controller
|
struct orion_nand_controller
|
||||||
{
|
{
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
struct arm_nand_data io;
|
struct arm_nand_data io;
|
||||||
|
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
@@ -53,7 +51,7 @@ struct orion_nand_controller
|
|||||||
static int orion_nand_command(struct nand_device *nand, uint8_t command)
|
static int orion_nand_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct orion_nand_controller *hw = nand->controller_priv;
|
struct orion_nand_controller *hw = nand->controller_priv;
|
||||||
struct target *target = hw->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
CHECK_HALTED;
|
CHECK_HALTED;
|
||||||
target_write_u8(target, hw->cmd, command);
|
target_write_u8(target, hw->cmd, command);
|
||||||
@@ -63,7 +61,7 @@ static int orion_nand_command(struct nand_device *nand, uint8_t command)
|
|||||||
static int orion_nand_address(struct nand_device *nand, uint8_t address)
|
static int orion_nand_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct orion_nand_controller *hw = nand->controller_priv;
|
struct orion_nand_controller *hw = nand->controller_priv;
|
||||||
struct target *target = hw->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
CHECK_HALTED;
|
CHECK_HALTED;
|
||||||
target_write_u8(target, hw->addr, address);
|
target_write_u8(target, hw->addr, address);
|
||||||
@@ -73,7 +71,7 @@ static int orion_nand_address(struct nand_device *nand, uint8_t address)
|
|||||||
static int orion_nand_read(struct nand_device *nand, void *data)
|
static int orion_nand_read(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct orion_nand_controller *hw = nand->controller_priv;
|
struct orion_nand_controller *hw = nand->controller_priv;
|
||||||
struct target *target = hw->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
CHECK_HALTED;
|
CHECK_HALTED;
|
||||||
target_read_u8(target, hw->data, data);
|
target_read_u8(target, hw->data, data);
|
||||||
@@ -83,7 +81,7 @@ static int orion_nand_read(struct nand_device *nand, void *data)
|
|||||||
static int orion_nand_write(struct nand_device *nand, uint16_t data)
|
static int orion_nand_write(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct orion_nand_controller *hw = nand->controller_priv;
|
struct orion_nand_controller *hw = nand->controller_priv;
|
||||||
struct target *target = hw->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
CHECK_HALTED;
|
CHECK_HALTED;
|
||||||
target_write_u8(target, hw->data, data);
|
target_write_u8(target, hw->data, data);
|
||||||
@@ -116,11 +114,6 @@ static int orion_nand_reset(struct nand_device *nand)
|
|||||||
return orion_nand_command(nand, NAND_CMD_RESET);
|
return orion_nand_command(nand, NAND_CMD_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int orion_nand_controller_ready(struct nand_device *nand, int timeout)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
||||||
{
|
{
|
||||||
struct orion_nand_controller *hw;
|
struct orion_nand_controller *hw;
|
||||||
@@ -128,23 +121,17 @@ NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
|||||||
uint8_t ale, cle;
|
uint8_t ale, cle;
|
||||||
|
|
||||||
if (CMD_ARGC != 3) {
|
if (CMD_ARGC != 3) {
|
||||||
LOG_ERROR("arguments must be: <target_id> <NAND_address>\n");
|
LOG_ERROR("arguments must be: <target_id> <NAND_address>");
|
||||||
return ERROR_NAND_DEVICE_INVALID;
|
return ERROR_NAND_DEVICE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
hw = calloc(1, sizeof(*hw));
|
hw = calloc(1, sizeof(*hw));
|
||||||
if (!hw) {
|
if (!hw) {
|
||||||
LOG_ERROR("no memory for nand controller\n");
|
LOG_ERROR("no memory for nand controller");
|
||||||
return ERROR_NAND_DEVICE_INVALID;
|
return ERROR_NAND_DEVICE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
nand->controller_priv = hw;
|
nand->controller_priv = hw;
|
||||||
hw->target = get_target(CMD_ARGV[1]);
|
|
||||||
if (!hw->target) {
|
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
|
||||||
free(hw);
|
|
||||||
return ERROR_NAND_DEVICE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base);
|
||||||
cle = 0;
|
cle = 0;
|
||||||
@@ -154,7 +141,7 @@ NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command)
|
|||||||
hw->cmd = base + (1 << cle);
|
hw->cmd = base + (1 << cle);
|
||||||
hw->addr = base + (1 << ale);
|
hw->addr = base + (1 << ale);
|
||||||
|
|
||||||
hw->io.target = hw->target;
|
hw->io.target = nand->target;
|
||||||
hw->io.data = hw->data;
|
hw->io.data = hw->data;
|
||||||
hw->io.op = ARM_NAND_NONE;
|
hw->io.op = ARM_NAND_NONE;
|
||||||
|
|
||||||
@@ -175,7 +162,6 @@ struct nand_flash_controller orion_nand_controller =
|
|||||||
.write_data = orion_nand_write,
|
.write_data = orion_nand_write,
|
||||||
.write_block_data = orion_nand_fast_block_write,
|
.write_block_data = orion_nand_fast_block_write,
|
||||||
.reset = orion_nand_reset,
|
.reset = orion_nand_reset,
|
||||||
.controller_ready = orion_nand_controller_ready,
|
|
||||||
.nand_device_command = orion_nand_device_command,
|
.nand_device_command = orion_nand_device_command,
|
||||||
.init = orion_nand_init,
|
.init = orion_nand_init,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command)
|
|||||||
|
|
||||||
static int s3c2410_init(struct nand_device *nand)
|
static int s3c2410_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
target_write_u32(target, S3C2410_NFCONF,
|
target_write_u32(target, S3C2410_NFCONF,
|
||||||
S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) |
|
S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) |
|
||||||
@@ -58,8 +57,7 @@ static int s3c2410_init(struct nand_device *nand)
|
|||||||
|
|
||||||
static int s3c2410_write_data(struct nand_device *nand, uint16_t data)
|
static int s3c2410_write_data(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -72,8 +70,7 @@ static int s3c2410_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
|
|
||||||
static int s3c2410_read_data(struct nand_device *nand, void *data)
|
static int s3c2410_read_data(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -86,8 +83,7 @@ static int s3c2410_read_data(struct nand_device *nand, void *data)
|
|||||||
|
|
||||||
static int s3c2410_nand_ready(struct nand_device *nand, int timeout)
|
static int s3c2410_nand_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
@@ -118,6 +114,5 @@ struct nand_flash_controller s3c2410_nand_controller = {
|
|||||||
.read_data = &s3c2410_read_data,
|
.read_data = &s3c2410_read_data,
|
||||||
.write_page = s3c24xx_write_page,
|
.write_page = s3c24xx_write_page,
|
||||||
.read_page = s3c24xx_read_page,
|
.read_page = s3c24xx_read_page,
|
||||||
.controller_ready = &s3c24xx_controller_ready,
|
|
||||||
.nand_ready = &s3c2410_nand_ready,
|
.nand_ready = &s3c2410_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command)
|
|||||||
|
|
||||||
static int s3c2412_init(struct nand_device *nand)
|
static int s3c2412_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
target_write_u32(target, S3C2410_NFCONF,
|
target_write_u32(target, S3C2410_NFCONF,
|
||||||
S3C2440_NFCONF_TACLS(3) |
|
S3C2440_NFCONF_TACLS(3) |
|
||||||
@@ -74,6 +73,5 @@ struct nand_flash_controller s3c2412_nand_controller = {
|
|||||||
.read_page = s3c24xx_read_page,
|
.read_page = s3c24xx_read_page,
|
||||||
.write_block_data = &s3c2440_write_block_data,
|
.write_block_data = &s3c2440_write_block_data,
|
||||||
.read_block_data = &s3c2440_read_block_data,
|
.read_block_data = &s3c2440_read_block_data,
|
||||||
.controller_ready = &s3c24xx_controller_ready,
|
|
||||||
.nand_ready = &s3c2440_nand_ready,
|
.nand_ready = &s3c2440_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command)
|
|||||||
|
|
||||||
static int s3c2440_init(struct nand_device *nand)
|
static int s3c2440_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
target_write_u32(target, S3C2410_NFCONF,
|
target_write_u32(target, S3C2410_NFCONF,
|
||||||
S3C2440_NFCONF_TACLS(3) |
|
S3C2440_NFCONF_TACLS(3) |
|
||||||
@@ -64,7 +63,7 @@ static int s3c2440_init(struct nand_device *nand)
|
|||||||
int s3c2440_nand_ready(struct nand_device *nand, int timeout)
|
int s3c2440_nand_ready(struct nand_device *nand, int timeout)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
@@ -90,11 +89,11 @@ int s3c2440_nand_ready(struct nand_device *nand, int timeout)
|
|||||||
int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size)
|
int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nfdata = s3c24xx_info->data;
|
uint32_t nfdata = s3c24xx_info->data;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, nand, data, data_size);
|
LOG_INFO("%s: reading data: %p, %p, %d", __func__, nand, data, data_size);
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -126,7 +125,7 @@ int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_si
|
|||||||
int s3c2440_write_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)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
uint32_t nfdata = s3c24xx_info->data;
|
uint32_t nfdata = s3c24xx_info->data;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
@@ -166,6 +165,5 @@ struct nand_flash_controller s3c2440_nand_controller = {
|
|||||||
.read_page = s3c24xx_read_page,
|
.read_page = s3c24xx_read_page,
|
||||||
.write_block_data = &s3c2440_write_block_data,
|
.write_block_data = &s3c2440_write_block_data,
|
||||||
.read_block_data = &s3c2440_read_block_data,
|
.read_block_data = &s3c2440_read_block_data,
|
||||||
.controller_ready = &s3c24xx_controller_ready,
|
|
||||||
.nand_ready = &s3c2440_nand_ready,
|
.nand_ready = &s3c2440_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command)
|
|||||||
|
|
||||||
static int s3c2443_init(struct nand_device *nand)
|
static int s3c2443_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
target_write_u32(target, S3C2410_NFCONF,
|
target_write_u32(target, S3C2410_NFCONF,
|
||||||
S3C2440_NFCONF_TACLS(3) |
|
S3C2440_NFCONF_TACLS(3) |
|
||||||
@@ -75,6 +74,5 @@ struct nand_flash_controller s3c2443_nand_controller = {
|
|||||||
.read_page = s3c24xx_read_page,
|
.read_page = s3c24xx_read_page,
|
||||||
.write_block_data = &s3c2440_write_block_data,
|
.write_block_data = &s3c2440_write_block_data,
|
||||||
.read_block_data = &s3c2440_read_block_data,
|
.read_block_data = &s3c2440_read_block_data,
|
||||||
.controller_ready = &s3c24xx_controller_ready,
|
|
||||||
.nand_ready = &s3c2440_nand_ready,
|
.nand_ready = &s3c2440_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,18 +38,11 @@ S3C24XX_DEVICE_COMMAND()
|
|||||||
struct s3c24xx_nand_controller *s3c24xx_info;
|
struct s3c24xx_nand_controller *s3c24xx_info;
|
||||||
s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller));
|
s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller));
|
||||||
if (s3c24xx_info == NULL) {
|
if (s3c24xx_info == NULL) {
|
||||||
LOG_ERROR("no memory for nand controller\n");
|
LOG_ERROR("no memory for nand controller");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
nand->controller_priv = s3c24xx_info;
|
nand->controller_priv = s3c24xx_info;
|
||||||
|
|
||||||
s3c24xx_info->target = get_target(CMD_ARGV[1]);
|
|
||||||
if (s3c24xx_info->target == NULL) {
|
|
||||||
LOG_ERROR("target '%s' not defined", CMD_ARGV[1]);
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
*info = s3c24xx_info;
|
*info = s3c24xx_info;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -58,7 +51,7 @@ S3C24XX_DEVICE_COMMAND()
|
|||||||
int s3c24xx_reset(struct nand_device *nand)
|
int s3c24xx_reset(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -73,7 +66,7 @@ int s3c24xx_reset(struct nand_device *nand)
|
|||||||
int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -88,7 +81,7 @@ int s3c24xx_command(struct nand_device *nand, uint8_t command)
|
|||||||
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -102,7 +95,7 @@ int s3c24xx_address(struct nand_device *nand, uint8_t address)
|
|||||||
int s3c24xx_write_data(struct nand_device *nand, uint16_t data)
|
int s3c24xx_write_data(struct nand_device *nand, uint16_t data)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -116,7 +109,7 @@ int s3c24xx_write_data(struct nand_device *nand, uint16_t data)
|
|||||||
int s3c24xx_read_data(struct nand_device *nand, void *data)
|
int s3c24xx_read_data(struct nand_device *nand, void *data)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
||||||
struct target *target = s3c24xx_info->target;
|
struct target *target = nand->target;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||||
@@ -126,8 +119,3 @@ int s3c24xx_read_data(struct nand_device *nand, void *data)
|
|||||||
target_read_u8(target, s3c24xx_info->data, data);
|
target_read_u8(target, s3c24xx_info->data, data);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int s3c24xx_controller_ready(struct nand_device *nand, int timeout)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
struct s3c24xx_nand_controller
|
struct s3c24xx_nand_controller
|
||||||
{
|
{
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
/* register addresses */
|
/* register addresses */
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
@@ -68,8 +66,6 @@ int s3c24xx_address(struct nand_device *nand, uint8_t address);
|
|||||||
int s3c24xx_write_data(struct nand_device *nand, uint16_t data);
|
int s3c24xx_write_data(struct nand_device *nand, uint16_t data);
|
||||||
int s3c24xx_read_data(struct nand_device *nand, void *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_write_page NULL
|
||||||
#define s3c24xx_read_page NULL
|
#define s3c24xx_read_page NULL
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ NAND_DEVICE_COMMAND_HANDLER(s3c6400_nand_device_command)
|
|||||||
|
|
||||||
static int s3c6400_init(struct nand_device *nand)
|
static int s3c6400_init(struct nand_device *nand)
|
||||||
{
|
{
|
||||||
struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv;
|
struct target *target = nand->target;
|
||||||
struct target *target = s3c24xx_info->target;
|
|
||||||
|
|
||||||
target_write_u32(target, S3C2410_NFCONF,
|
target_write_u32(target, S3C2410_NFCONF,
|
||||||
S3C2440_NFCONF_TACLS(3) |
|
S3C2440_NFCONF_TACLS(3) |
|
||||||
@@ -71,6 +70,5 @@ struct nand_flash_controller s3c6400_nand_controller = {
|
|||||||
.read_page = s3c24xx_read_page,
|
.read_page = s3c24xx_read_page,
|
||||||
.write_block_data = &s3c2440_write_block_data,
|
.write_block_data = &s3c2440_write_block_data,
|
||||||
.read_block_data = &s3c2440_read_block_data,
|
.read_block_data = &s3c2440_read_block_data,
|
||||||
.controller_ready = &s3c24xx_controller_ready,
|
|
||||||
.nand_ready = &s3c2440_nand_ready,
|
.nand_ready = &s3c2440_nand_ready,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include <target/target.h>
|
||||||
|
|
||||||
// to be removed
|
// to be removed
|
||||||
extern struct nand_device *nand_devices;
|
extern struct nand_device *nand_devices;
|
||||||
@@ -147,18 +148,11 @@ COMMAND_HANDLER(handle_nand_probe_command)
|
|||||||
|
|
||||||
if ((retval = nand_probe(p)) == ERROR_OK)
|
if ((retval = nand_probe(p)) == ERROR_OK)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "NAND flash device '%s' found", p->device->name);
|
command_print(CMD_CTX, "NAND flash device '%s (%s)' found",
|
||||||
}
|
p->device->name, p->manufacturer->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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_erase_command)
|
COMMAND_HANDLER(handle_nand_erase_command)
|
||||||
@@ -205,16 +199,8 @@ COMMAND_HANDLER(handle_nand_erase_command)
|
|||||||
offset, offset + length,
|
offset, offset + length,
|
||||||
CMD_ARGV[0], p->device->name);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
||||||
@@ -260,18 +246,8 @@ COMMAND_HANDLER(handle_nand_check_bad_blocks_command)
|
|||||||
command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
|
command_print(CMD_CTX, "checked NAND flash device for bad blocks, "
|
||||||
"use \"nand info\" command to list blocks");
|
"use \"nand info\" command to list blocks");
|
||||||
}
|
}
|
||||||
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_write_command)
|
COMMAND_HANDLER(handle_nand_write_command)
|
||||||
@@ -309,7 +285,7 @@ COMMAND_HANDLER(handle_nand_write_command)
|
|||||||
if (nand_fileio_finish(&s))
|
if (nand_fileio_finish(&s))
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
|
command_print(CMD_CTX, "wrote file %s to NAND flash %s up to "
|
||||||
"offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
|
"offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||||
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench),
|
||||||
duration_kbps(&s.bench, total_bytes));
|
duration_kbps(&s.bench, total_bytes));
|
||||||
}
|
}
|
||||||
@@ -336,13 +312,14 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
|
|
||||||
while (file.size > 0)
|
while (file.size > 0)
|
||||||
{
|
{
|
||||||
int retval = nand_read_page(nand, dev.address / dev.page_size,
|
retval = nand_read_page(nand, dev.address / dev.page_size,
|
||||||
dev.page, dev.page_size, dev.oob, dev.oob_size);
|
dev.page, dev.page_size, dev.oob, dev.oob_size);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
return nand_fileio_cleanup(&file);
|
nand_fileio_cleanup(&file);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytes_read = nand_fileio_read(nand, &file);
|
int bytes_read = nand_fileio_read(nand, &file);
|
||||||
@@ -350,7 +327,8 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
{
|
{
|
||||||
command_print(CMD_CTX, "error while reading file");
|
command_print(CMD_CTX, "error while reading file");
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
return nand_fileio_cleanup(&file);
|
nand_fileio_cleanup(&file);
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
|
if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) ||
|
||||||
@@ -359,7 +337,8 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
command_print(CMD_CTX, "NAND flash contents differ "
|
command_print(CMD_CTX, "NAND flash contents differ "
|
||||||
"at 0x%8.8" PRIx32, dev.address);
|
"at 0x%8.8" PRIx32, dev.address);
|
||||||
nand_fileio_cleanup(&dev);
|
nand_fileio_cleanup(&dev);
|
||||||
return nand_fileio_cleanup(&file);
|
nand_fileio_cleanup(&file);
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.size -= bytes_read;
|
file.size -= bytes_read;
|
||||||
@@ -369,7 +348,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
if (nand_fileio_finish(&file) == ERROR_OK)
|
if (nand_fileio_finish(&file) == ERROR_OK)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "verified file %s in NAND flash %s "
|
command_print(CMD_CTX, "verified file %s in NAND flash %s "
|
||||||
"up to offset 0x%8.8" PRIx32 " in %fs (%0.3f kb/s)",
|
"up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
|
||||||
CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
|
CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench),
|
||||||
duration_kbps(&file.bench, dev.size));
|
duration_kbps(&file.bench, dev.size));
|
||||||
}
|
}
|
||||||
@@ -379,6 +358,7 @@ COMMAND_HANDLER(handle_nand_verify_command)
|
|||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_dump_command)
|
COMMAND_HANDLER(handle_nand_dump_command)
|
||||||
{
|
{
|
||||||
|
int filesize;
|
||||||
struct nand_device *nand = NULL;
|
struct nand_device *nand = NULL;
|
||||||
struct nand_fileio_state s;
|
struct nand_fileio_state s;
|
||||||
int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
|
int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args,
|
||||||
@@ -389,12 +369,13 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
|||||||
while (s.size > 0)
|
while (s.size > 0)
|
||||||
{
|
{
|
||||||
size_t size_written;
|
size_t size_written;
|
||||||
int retval = nand_read_page(nand, s.address / nand->page_size,
|
retval = nand_read_page(nand, s.address / nand->page_size,
|
||||||
s.page, s.page_size, s.oob, s.oob_size);
|
s.page, s.page_size, s.oob, s.oob_size);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "reading NAND flash page failed");
|
command_print(CMD_CTX, "reading NAND flash page failed");
|
||||||
return nand_fileio_cleanup(&s);
|
nand_fileio_cleanup(&s);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != s.page)
|
if (NULL != s.page)
|
||||||
@@ -407,11 +388,15 @@ COMMAND_HANDLER(handle_nand_dump_command)
|
|||||||
s.address += nand->page_size;
|
s.address += nand->page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retval = fileio_size(&s.fileio, &filesize);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
if (nand_fileio_finish(&s) == ERROR_OK)
|
if (nand_fileio_finish(&s) == ERROR_OK)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f kb/s)",
|
command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)",
|
||||||
(long)s.fileio.size, duration_elapsed(&s.bench),
|
(long)filesize, duration_elapsed(&s.bench),
|
||||||
duration_kbps(&s.bench, s.fileio.size));
|
duration_kbps(&s.bench, filesize));
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -512,7 +497,7 @@ static const struct command_registration nand_exec_command_handlers[] = {
|
|||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
int nand_init(struct command_context *cmd_ctx)
|
static int nand_init(struct command_context *cmd_ctx)
|
||||||
{
|
{
|
||||||
if (!nand_devices)
|
if (!nand_devices)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
@@ -536,12 +521,14 @@ COMMAND_HANDLER(handle_nand_init_command)
|
|||||||
LOG_DEBUG("Initializing NAND devices...");
|
LOG_DEBUG("Initializing NAND devices...");
|
||||||
return nand_init(CMD_CTX);
|
return nand_init(CMD_CTX);
|
||||||
}
|
}
|
||||||
int nand_list_walker(struct nand_flash_controller *c, void *x)
|
|
||||||
|
static int nand_list_walker(struct nand_flash_controller *c, void *x)
|
||||||
{
|
{
|
||||||
struct command_context *cmd_ctx = (struct command_context *)x;
|
struct command_context *cmd_ctx = (struct command_context *)x;
|
||||||
command_print(cmd_ctx, " %s", c->name);
|
command_print(cmd_ctx, " %s", c->name);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_list_drivers)
|
COMMAND_HANDLER(handle_nand_list_drivers)
|
||||||
{
|
{
|
||||||
command_print(CMD_CTX, "Available NAND flash controller drivers:");
|
command_print(CMD_CTX, "Available NAND flash controller drivers:");
|
||||||
@@ -551,16 +538,37 @@ COMMAND_HANDLER(handle_nand_list_drivers)
|
|||||||
static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
||||||
struct nand_flash_controller *controller)
|
struct nand_flash_controller *controller)
|
||||||
{
|
{
|
||||||
|
struct nand_device *c;
|
||||||
|
struct target *target;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 2)
|
||||||
|
{
|
||||||
|
LOG_ERROR("missing target");
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
target = get_target(CMD_ARGV[1]);
|
||||||
|
if (!target) {
|
||||||
|
LOG_ERROR("invalid target %s", CMD_ARGV[1]);
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
if (NULL != controller->commands)
|
if (NULL != controller->commands)
|
||||||
{
|
{
|
||||||
int retval = register_commands(CMD_CTX, NULL,
|
retval = register_commands(CMD_CTX, NULL,
|
||||||
controller->commands);
|
controller->commands);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
struct nand_device *c = malloc(sizeof(struct nand_device));
|
c = malloc(sizeof(struct nand_device));
|
||||||
|
if (c == NULL)
|
||||||
|
{
|
||||||
|
LOG_ERROR("End of memory");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
c->name = strdup(bank_name);
|
c->name = strdup(bank_name);
|
||||||
|
c->target = target;
|
||||||
c->controller = controller;
|
c->controller = controller;
|
||||||
c->controller_priv = NULL;
|
c->controller_priv = NULL;
|
||||||
c->manufacturer = NULL;
|
c->manufacturer = NULL;
|
||||||
@@ -571,7 +579,7 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||||||
c->use_raw = 0;
|
c->use_raw = 0;
|
||||||
c->next = NULL;
|
c->next = NULL;
|
||||||
|
|
||||||
int retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
{
|
{
|
||||||
LOG_ERROR("'%s' driver rejected nand flash", controller->name);
|
LOG_ERROR("'%s' driver rejected nand flash", controller->name);
|
||||||
@@ -586,7 +594,7 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_device_command)
|
COMMAND_HANDLER(handle_nand_device_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC < 1)
|
if (CMD_ARGC < 2)
|
||||||
{
|
{
|
||||||
LOG_ERROR("incomplete nand device configuration");
|
LOG_ERROR("incomplete nand device configuration");
|
||||||
return ERROR_FLASH_BANK_INVALID;
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
AM_CPPFLAGS = \
|
include $(top_srcdir)/common.mk
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-I$(top_builddir)/src
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libocdflashnor.la
|
noinst_LTLIBRARIES = libocdflashnor.la
|
||||||
libocdflashnor_la_SOURCES = \
|
libocdflashnor_la_SOURCES = \
|
||||||
@@ -16,6 +14,7 @@ NOR_DRIVERS = \
|
|||||||
avrf.c \
|
avrf.c \
|
||||||
cfi.c \
|
cfi.c \
|
||||||
ecos.c \
|
ecos.c \
|
||||||
|
em357.c \
|
||||||
faux.c \
|
faux.c \
|
||||||
lpc2000.c \
|
lpc2000.c \
|
||||||
lpc288x.c \
|
lpc288x.c \
|
||||||
@@ -23,31 +22,23 @@ NOR_DRIVERS = \
|
|||||||
non_cfi.c \
|
non_cfi.c \
|
||||||
ocl.c \
|
ocl.c \
|
||||||
pic32mx.c \
|
pic32mx.c \
|
||||||
|
stmsmi.c \
|
||||||
stellaris.c \
|
stellaris.c \
|
||||||
stm32x.c \
|
stm32x.c \
|
||||||
|
stm32f2xxx.c \
|
||||||
str7x.c \
|
str7x.c \
|
||||||
str9x.c \
|
str9x.c \
|
||||||
str9xpec.c \
|
str9xpec.c \
|
||||||
tms470.c
|
tms470.c \
|
||||||
|
dsp5680xx_flash.c \
|
||||||
|
virtual.c
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
at91sam7.h \
|
|
||||||
at91sam3.h \
|
|
||||||
avrf.h \
|
|
||||||
core.h \
|
core.h \
|
||||||
cfi.h \
|
cfi.h \
|
||||||
driver.h \
|
driver.h \
|
||||||
imp.h \
|
imp.h \
|
||||||
lpc2000.h \
|
|
||||||
lpc288x.h \
|
|
||||||
non_cfi.h \
|
non_cfi.h \
|
||||||
ocl.h \
|
ocl.h
|
||||||
pic32mx.h \
|
|
||||||
stellaris.h \
|
|
||||||
stm32x.h \
|
|
||||||
str7x.h \
|
|
||||||
str9x.h \
|
|
||||||
str9xpec.h \
|
|
||||||
tms470.h
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||||
|
|||||||
@@ -105,19 +105,19 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
/* mass erase */
|
/* mass erase */
|
||||||
if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
|
if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
|
||||||
LOG_DEBUG("performing mass erase.\n");
|
LOG_DEBUG("performing mass erase.");
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
|
||||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
|
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
|
||||||
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
|
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
|
||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("mass erase failed\n");
|
LOG_ERROR("mass erase failed");
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("mass erase successful.\n");
|
LOG_DEBUG("mass erase successful.");
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else {
|
} else {
|
||||||
unsigned long adr;
|
unsigned long adr;
|
||||||
@@ -132,12 +132,12 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
|
|||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("failed to erase sector at address 0x%08lX\n", adr);
|
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("erased sector at address 0x%08lX\n", adr);
|
LOG_DEBUG("erased sector at address 0x%08lX", adr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
r6 - set to 2, used to write flash command
|
r6 - set to 2, used to write flash command
|
||||||
|
|
||||||
*/
|
*/
|
||||||
uint32_t aduc702x_flash_write_code[] = {
|
static const uint32_t aduc702x_flash_write_code[] = {
|
||||||
//<_start>:
|
//<_start>:
|
||||||
0xe3a05008, // mov r5, #8 ; 0x8
|
0xe3a05008, // mov r5, #8 ; 0x8
|
||||||
0xe5845004, // str r5, [r4, #4]
|
0xe5845004, // str r5, [r4, #4]
|
||||||
@@ -227,7 +227,7 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* memory buffer */
|
/* memory buffer */
|
||||||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
|
||||||
{
|
{
|
||||||
buffer_size /= 2;
|
buffer_size /= 2;
|
||||||
if (buffer_size <= 256)
|
if (buffer_size <= 256)
|
||||||
@@ -330,20 +330,20 @@ static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint3
|
|||||||
|
|
||||||
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
|
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("single write failed for address 0x%08lX\n", (unsigned long)(offset + x));
|
LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x));
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
LOG_DEBUG("wrote %d bytes at address 0x%08lX\n", (int)count, (unsigned long)(offset + x));
|
LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x));
|
||||||
|
|
||||||
aduc702x_set_write_enable(target, 0);
|
aduc702x_set_write_enable(target, 0);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@@ -417,6 +417,7 @@ struct flash_driver aduc702x_flash = {
|
|||||||
.erase = aduc702x_erase,
|
.erase = aduc702x_erase,
|
||||||
.protect = aduc702x_protect,
|
.protect = aduc702x_protect,
|
||||||
.write = aduc702x_write,
|
.write = aduc702x_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = aduc702x_probe,
|
.probe = aduc702x_probe,
|
||||||
.auto_probe = aduc702x_probe,
|
.auto_probe = aduc702x_probe,
|
||||||
.erase_check = default_flash_blank_check,
|
.erase_check = default_flash_blank_check,
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
* Copyright (C) 2009 by Duane Ellis *
|
* Copyright (C) 2009 by Duane Ellis *
|
||||||
* openocd@duaneellis.com *
|
* openocd@duaneellis.com *
|
||||||
* *
|
* *
|
||||||
|
* Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) *
|
||||||
|
* olaf@uni-paderborn.de *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General public License as published by *
|
* it under the terms of the GNU General public License as published by *
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
@@ -58,15 +62,16 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "at91sam3.h"
|
|
||||||
#include <helper/membuf.h>
|
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
|
|
||||||
#define REG_NAME_WIDTH (12)
|
#define REG_NAME_WIDTH (12)
|
||||||
|
|
||||||
|
// at91sam3u series (has one or two flash banks)
|
||||||
|
#define FLASH_BANK0_BASE_U 0x00080000
|
||||||
|
#define FLASH_BANK1_BASE_U 0x00100000
|
||||||
|
|
||||||
#define FLASH_BANK0_BASE 0x00080000
|
// at91sam3s series (has always one flash bank)
|
||||||
#define FLASH_BANK1_BASE 0x00100000
|
#define FLASH_BANK_BASE_S 0x00400000
|
||||||
|
|
||||||
#define AT91C_EFC_FCMD_GETD (0x0) // (EFC) Get Flash Descriptor
|
#define AT91C_EFC_FCMD_GETD (0x0) // (EFC) Get Flash Descriptor
|
||||||
#define AT91C_EFC_FCMD_WP (0x1) // (EFC) Write Page
|
#define AT91C_EFC_FCMD_WP (0x1) // (EFC) Write Page
|
||||||
@@ -93,6 +98,8 @@
|
|||||||
#define offset_EFC_FRR 12
|
#define offset_EFC_FRR 12
|
||||||
|
|
||||||
|
|
||||||
|
extern struct flash_driver at91sam3_flash;
|
||||||
|
|
||||||
static float
|
static float
|
||||||
_tomhz(uint32_t freq_hz)
|
_tomhz(uint32_t freq_hz)
|
||||||
{
|
{
|
||||||
@@ -211,8 +218,6 @@ struct sam3_chip {
|
|||||||
struct sam3_chip_details details;
|
struct sam3_chip_details details;
|
||||||
struct target *target;
|
struct target *target;
|
||||||
struct sam3_cfg cfg;
|
struct sam3_cfg cfg;
|
||||||
|
|
||||||
struct membuf *mbuf;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -257,6 +262,7 @@ get_current_sam3(struct command_context *cmd_ctx)
|
|||||||
|
|
||||||
// these are used to *initialize* the "pChip->details" structure.
|
// these are used to *initialize* the "pChip->details" structure.
|
||||||
static const struct sam3_chip_details all_sam3_details[] = {
|
static const struct sam3_chip_details all_sam3_details[] = {
|
||||||
|
// Start at91sam3u* series
|
||||||
{
|
{
|
||||||
.chipid_cidr = 0x28100960,
|
.chipid_cidr = 0x28100960,
|
||||||
.name = "at91sam3u4e",
|
.name = "at91sam3u4e",
|
||||||
@@ -287,7 +293,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -302,7 +308,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 1,
|
.bank_number = 1,
|
||||||
.base_address = FLASH_BANK1_BASE,
|
.base_address = FLASH_BANK1_BASE_U,
|
||||||
.controller_address = 0x400e0a00,
|
.controller_address = 0x400e0a00,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -336,7 +342,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -377,7 +383,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 64 * 1024,
|
.size_bytes = 64 * 1024,
|
||||||
@@ -425,7 +431,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -439,7 +445,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 1,
|
.bank_number = 1,
|
||||||
.base_address = FLASH_BANK1_BASE,
|
.base_address = FLASH_BANK1_BASE_U,
|
||||||
.controller_address = 0x400e0a00,
|
.controller_address = 0x400e0a00,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -473,7 +479,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 128 * 1024,
|
.size_bytes = 128 * 1024,
|
||||||
@@ -514,7 +520,7 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
.pChip = NULL,
|
.pChip = NULL,
|
||||||
.pBank = NULL,
|
.pBank = NULL,
|
||||||
.bank_number = 0,
|
.bank_number = 0,
|
||||||
.base_address = FLASH_BANK0_BASE,
|
.base_address = FLASH_BANK0_BASE_U,
|
||||||
.controller_address = 0x400e0800,
|
.controller_address = 0x400e0800,
|
||||||
.present = 1,
|
.present = 1,
|
||||||
.size_bytes = 64 * 1024,
|
.size_bytes = 64 * 1024,
|
||||||
@@ -532,6 +538,300 @@ static const struct sam3_chip_details all_sam3_details[] = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Start at91sam3s* series
|
||||||
|
|
||||||
|
// Note: The preliminary at91sam3s datasheet says on page 302
|
||||||
|
// that the flash controller is at address 0x400E0800.
|
||||||
|
// This is _not_ the case, the controller resides at address 0x400e0a0.
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28A00960,
|
||||||
|
.name = "at91sam3s4c",
|
||||||
|
.total_flash_size = 256 * 1024,
|
||||||
|
.total_sram_size = 48 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 256 * 1024,
|
||||||
|
.nsectors = 32,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28900960,
|
||||||
|
.name = "at91sam3s4b",
|
||||||
|
.total_flash_size = 256 * 1024,
|
||||||
|
.total_sram_size = 48 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 256 * 1024,
|
||||||
|
.nsectors = 32,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28800960,
|
||||||
|
.name = "at91sam3s4a",
|
||||||
|
.total_flash_size = 256 * 1024,
|
||||||
|
.total_sram_size = 48 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 256 * 1024,
|
||||||
|
.nsectors = 32,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28AA0760,
|
||||||
|
.name = "at91sam3s2c",
|
||||||
|
.total_flash_size = 128 * 1024,
|
||||||
|
.total_sram_size = 32 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 128 * 1024,
|
||||||
|
.nsectors = 16,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x289A0760,
|
||||||
|
.name = "at91sam3s2b",
|
||||||
|
.total_flash_size = 128 * 1024,
|
||||||
|
.total_sram_size = 32 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 128 * 1024,
|
||||||
|
.nsectors = 16,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x288A0760,
|
||||||
|
.name = "at91sam3s2a",
|
||||||
|
.total_flash_size = 128 * 1024,
|
||||||
|
.total_sram_size = 32 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 128 * 1024,
|
||||||
|
.nsectors = 16,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28A90560,
|
||||||
|
.name = "at91sam3s1c",
|
||||||
|
.total_flash_size = 64 * 1024,
|
||||||
|
.total_sram_size = 16 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 64 * 1024,
|
||||||
|
.nsectors = 8,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28990560,
|
||||||
|
.name = "at91sam3s1b",
|
||||||
|
.total_flash_size = 64 * 1024,
|
||||||
|
.total_sram_size = 16 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 64 * 1024,
|
||||||
|
.nsectors = 8,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.chipid_cidr = 0x28890560,
|
||||||
|
.name = "at91sam3s1a",
|
||||||
|
.total_flash_size = 64 * 1024,
|
||||||
|
.total_sram_size = 16 * 1024,
|
||||||
|
.n_gpnvms = 2,
|
||||||
|
.n_banks = 1,
|
||||||
|
{
|
||||||
|
// .bank[0] = {
|
||||||
|
{
|
||||||
|
.probed = 0,
|
||||||
|
.pChip = NULL,
|
||||||
|
.pBank = NULL,
|
||||||
|
.bank_number = 0,
|
||||||
|
.base_address = FLASH_BANK_BASE_S,
|
||||||
|
|
||||||
|
.controller_address = 0x400e0a00,
|
||||||
|
.present = 1,
|
||||||
|
.size_bytes = 64 * 1024,
|
||||||
|
.nsectors = 8,
|
||||||
|
.sector_size = 8192,
|
||||||
|
.page_size = 256,
|
||||||
|
},
|
||||||
|
// .bank[1] = {
|
||||||
|
{
|
||||||
|
.present = 0,
|
||||||
|
.probed = 0,
|
||||||
|
.bank_number = 1,
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
// terminate
|
// terminate
|
||||||
{
|
{
|
||||||
.chipid_cidr = 0,
|
.chipid_cidr = 0,
|
||||||
@@ -1000,20 +1300,6 @@ FLASHD_Lock(struct sam3_bank_private *pPrivate,
|
|||||||
/****** END SAM3 CODE ********/
|
/****** END SAM3 CODE ********/
|
||||||
|
|
||||||
/* begin helpful debug code */
|
/* begin helpful debug code */
|
||||||
|
|
||||||
static void
|
|
||||||
sam3_sprintf(struct sam3_chip *pChip , const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap,fmt);
|
|
||||||
if (pChip->mbuf == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
membuf_vsprintf(pChip->mbuf, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
// print the fieldname, the field value, in dec & hex, and return field value
|
// print the fieldname, the field value, in dec & hex, and return field value
|
||||||
static uint32_t
|
static uint32_t
|
||||||
sam3_reg_fieldname(struct sam3_chip *pChip,
|
sam3_reg_fieldname(struct sam3_chip *pChip,
|
||||||
@@ -1038,7 +1324,7 @@ sam3_reg_fieldname(struct sam3_chip *pChip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show the basics
|
// show the basics
|
||||||
sam3_sprintf(pChip, "\t%*s: %*d [0x%0*x] ",
|
LOG_USER_N("\t%*s: %*d [0x%0*x] ",
|
||||||
REG_NAME_WIDTH, regname,
|
REG_NAME_WIDTH, regname,
|
||||||
dwidth, v,
|
dwidth, v,
|
||||||
hwidth, v);
|
hwidth, v);
|
||||||
@@ -1173,16 +1459,16 @@ sam3_explain_ckgr_mor(struct sam3_chip *pChip)
|
|||||||
uint32_t rcen;
|
uint32_t rcen;
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1);
|
v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1);
|
||||||
sam3_sprintf(pChip, "(main xtal enabled: %s)\n",
|
LOG_USER("(main xtal enabled: %s)",
|
||||||
_yes_or_no(v));
|
_yes_or_no(v));
|
||||||
v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1);
|
v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1);
|
||||||
sam3_sprintf(pChip, "(main osc bypass: %s)\n",
|
LOG_USER("(main osc bypass: %s)",
|
||||||
_yes_or_no(v));
|
_yes_or_no(v));
|
||||||
rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 2, 1);
|
rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 3, 1);
|
||||||
sam3_sprintf(pChip, "(onchip RC-OSC enabled: %s)\n",
|
LOG_USER("(onchip RC-OSC enabled: %s)",
|
||||||
_yes_or_no(rcen));
|
_yes_or_no(rcen));
|
||||||
v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3);
|
v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3);
|
||||||
sam3_sprintf(pChip, "(onchip RC-OSC freq: %s)\n",
|
LOG_USER("(onchip RC-OSC freq: %s)",
|
||||||
_rc_freq[v]);
|
_rc_freq[v]);
|
||||||
|
|
||||||
pChip->cfg.rc_freq = 0;
|
pChip->cfg.rc_freq = 0;
|
||||||
@@ -1190,6 +1476,7 @@ sam3_explain_ckgr_mor(struct sam3_chip *pChip)
|
|||||||
switch (v) {
|
switch (v) {
|
||||||
default:
|
default:
|
||||||
pChip->cfg.rc_freq = 0;
|
pChip->cfg.rc_freq = 0;
|
||||||
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
pChip->cfg.rc_freq = 4 * 1000 * 1000;
|
pChip->cfg.rc_freq = 4 * 1000 * 1000;
|
||||||
break;
|
break;
|
||||||
@@ -1203,14 +1490,14 @@ sam3_explain_ckgr_mor(struct sam3_chip *pChip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip,"MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8);
|
v = sam3_reg_fieldname(pChip,"MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8);
|
||||||
sam3_sprintf(pChip, "(startup clks, time= %f uSecs)\n",
|
LOG_USER("(startup clks, time= %f uSecs)",
|
||||||
((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq)));
|
((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq)));
|
||||||
v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1);
|
v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1);
|
||||||
sam3_sprintf(pChip, "(mainosc source: %s)\n",
|
LOG_USER("(mainosc source: %s)",
|
||||||
v ? "external xtal" : "internal RC");
|
v ? "external xtal" : "internal RC");
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip,"CFDEN", pChip->cfg.CKGR_MOR, 25, 1);
|
v = sam3_reg_fieldname(pChip,"CFDEN", pChip->cfg.CKGR_MOR, 25, 1);
|
||||||
sam3_sprintf(pChip, "(clock failure enabled: %s)\n",
|
LOG_USER("(clock failure enabled: %s)",
|
||||||
_yes_or_no(v));
|
_yes_or_no(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,19 +1511,19 @@ sam3_explain_chipid_cidr(struct sam3_chip *pChip)
|
|||||||
const char *cp;
|
const char *cp;
|
||||||
|
|
||||||
sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5);
|
sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5);
|
||||||
sam3_sprintf(pChip,"\n");
|
LOG_USER_N("\n");
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3);
|
v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3);
|
||||||
sam3_sprintf(pChip, "%s\n", eproc_names[v]);
|
LOG_USER("%s", eproc_names[v]);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4);
|
v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4);
|
||||||
sam3_sprintf(pChip, "%s\n", nvpsize[v]);
|
LOG_USER("%s", nvpsize[v]);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4);
|
v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4);
|
||||||
sam3_sprintf(pChip, "%s\n", nvpsize2[v]);
|
LOG_USER("%s", nvpsize2[v]);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16,4);
|
v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16,4);
|
||||||
sam3_sprintf(pChip, "%s\n", sramsize[ v ]);
|
LOG_USER("%s", sramsize[ v ]);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8);
|
v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8);
|
||||||
cp = _unknown;
|
cp = _unknown;
|
||||||
@@ -1247,13 +1534,13 @@ sam3_explain_chipid_cidr(struct sam3_chip *pChip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sam3_sprintf(pChip, "%s\n", cp);
|
LOG_USER("%s", cp);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3);
|
v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3);
|
||||||
sam3_sprintf(pChip, "%s\n", nvptype[ v ]);
|
LOG_USER("%s", nvptype[ v ]);
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1);
|
v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1);
|
||||||
sam3_sprintf(pChip, "(exists: %s)\n", _yes_or_no(v));
|
LOG_USER("(exists: %s)", _yes_or_no(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1263,14 +1550,14 @@ sam3_explain_ckgr_mcfr(struct sam3_chip *pChip)
|
|||||||
|
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1);
|
v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1);
|
||||||
sam3_sprintf(pChip, "(main ready: %s)\n", _yes_or_no(v));
|
LOG_USER("(main ready: %s)", _yes_or_no(v));
|
||||||
|
|
||||||
v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16);
|
v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16);
|
||||||
|
|
||||||
v = (v * pChip->cfg.slow_freq) / 16;
|
v = (v * pChip->cfg.slow_freq) / 16;
|
||||||
pChip->cfg.mainosc_freq = v;
|
pChip->cfg.mainosc_freq = v;
|
||||||
|
|
||||||
sam3_sprintf(pChip, "(%3.03f Mhz (%d.%03dkhz slowclk)\n",
|
LOG_USER("(%3.03f Mhz (%d.%03dkhz slowclk)",
|
||||||
_tomhz(v),
|
_tomhz(v),
|
||||||
pChip->cfg.slow_freq / 1000,
|
pChip->cfg.slow_freq / 1000,
|
||||||
pChip->cfg.slow_freq % 1000);
|
pChip->cfg.slow_freq % 1000);
|
||||||
@@ -1283,17 +1570,17 @@ sam3_explain_ckgr_plla(struct sam3_chip *pChip)
|
|||||||
uint32_t mula,diva;
|
uint32_t mula,diva;
|
||||||
|
|
||||||
diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8);
|
diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8);
|
||||||
sam3_sprintf(pChip,"\n");
|
LOG_USER_N("\n");
|
||||||
mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11);
|
mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11);
|
||||||
sam3_sprintf(pChip,"\n");
|
LOG_USER_N("\n");
|
||||||
pChip->cfg.plla_freq = 0;
|
pChip->cfg.plla_freq = 0;
|
||||||
if (mula == 0) {
|
if (mula == 0) {
|
||||||
sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,mula = 0)\n");
|
LOG_USER("\tPLLA Freq: (Disabled,mula = 0)");
|
||||||
} else if (diva == 0) {
|
} else if (diva == 0) {
|
||||||
sam3_sprintf(pChip,"\tPLLA Freq: (Disabled,diva = 0)\n");
|
LOG_USER("\tPLLA Freq: (Disabled,diva = 0)");
|
||||||
} else if (diva == 1) {
|
} else if (diva == 1) {
|
||||||
pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1));
|
pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1));
|
||||||
sam3_sprintf(pChip,"\tPLLA Freq: %3.03f MHz\n",
|
LOG_USER("\tPLLA Freq: %3.03f MHz",
|
||||||
_tomhz(pChip->cfg.plla_freq));
|
_tomhz(pChip->cfg.plla_freq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1334,7 +1621,7 @@ sam3_explain_mckr(struct sam3_chip *pChip)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sam3_sprintf(pChip, "%s (%3.03f Mhz)\n",
|
LOG_USER("%s (%3.03f Mhz)",
|
||||||
cp,
|
cp,
|
||||||
_tomhz(fin));
|
_tomhz(fin));
|
||||||
pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3);
|
pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3);
|
||||||
@@ -1342,6 +1629,7 @@ sam3_explain_mckr(struct sam3_chip *pChip)
|
|||||||
case 0:
|
case 0:
|
||||||
pdiv = 1;
|
pdiv = 1;
|
||||||
cp = "selected clock";
|
cp = "selected clock";
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
pdiv = 2;
|
pdiv = 2;
|
||||||
cp = "clock/2";
|
cp = "clock/2";
|
||||||
@@ -1374,14 +1662,14 @@ sam3_explain_mckr(struct sam3_chip *pChip)
|
|||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sam3_sprintf(pChip, "(%s)\n", cp);
|
LOG_USER("(%s)", cp);
|
||||||
fin = fin / pdiv;
|
fin = fin / pdiv;
|
||||||
// sam3 has a *SINGLE* clock -
|
// sam3 has a *SINGLE* clock -
|
||||||
// other at91 series parts have divisors for these.
|
// other at91 series parts have divisors for these.
|
||||||
pChip->cfg.cpu_freq = fin;
|
pChip->cfg.cpu_freq = fin;
|
||||||
pChip->cfg.mclk_freq = fin;
|
pChip->cfg.mclk_freq = fin;
|
||||||
pChip->cfg.fclk_freq = fin;
|
pChip->cfg.fclk_freq = fin;
|
||||||
sam3_sprintf(pChip, "\t\tResult CPU Freq: %3.03f\n",
|
LOG_USER("\t\tResult CPU Freq: %3.03f",
|
||||||
_tomhz(fin));
|
_tomhz(fin));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1417,7 +1705,7 @@ sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_list *pList)
|
|||||||
// By using prototypes - we can detect what would
|
// By using prototypes - we can detect what would
|
||||||
// be casting errors.
|
// be casting errors.
|
||||||
|
|
||||||
return ((uint32_t *)(((char *)(pCfg)) + pList->struct_offset));
|
return ((uint32_t *)(void *)(((char *)(pCfg)) + pList->struct_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1471,7 +1759,7 @@ sam3_GetReg(struct sam3_chip *pChip, uint32_t *goes_here)
|
|||||||
// calculate where this one go..
|
// calculate where this one go..
|
||||||
// it is "possibly" this register.
|
// it is "possibly" this register.
|
||||||
|
|
||||||
pPossible = ((uint32_t *)(((char *)(&(pChip->cfg))) + pReg->struct_offset));
|
pPossible = ((uint32_t *)(void *)(((char *)(&(pChip->cfg))) + pReg->struct_offset));
|
||||||
|
|
||||||
// well? Is it this register
|
// well? Is it this register
|
||||||
if (pPossible == goes_here) {
|
if (pPossible == goes_here) {
|
||||||
@@ -1501,7 +1789,7 @@ sam3_ReadThisReg(struct sam3_chip *pChip, uint32_t *goes_here)
|
|||||||
|
|
||||||
r = target_read_u32(pChip->target, pReg->address, goes_here);
|
r = target_read_u32(pChip->target, pReg->address, goes_here);
|
||||||
if (r != ERROR_OK) {
|
if (r != ERROR_OK) {
|
||||||
LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d\n",
|
LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d",
|
||||||
pReg->name, (unsigned)(pReg->address), r);
|
pReg->name, (unsigned)(pReg->address), r);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@@ -1520,7 +1808,7 @@ sam3_ReadAllRegs(struct sam3_chip *pChip)
|
|||||||
r = sam3_ReadThisReg(pChip,
|
r = sam3_ReadThisReg(pChip,
|
||||||
sam3_get_reg_ptr(&(pChip->cfg), pReg));
|
sam3_get_reg_ptr(&(pChip->cfg), pReg));
|
||||||
if (r != ERROR_OK) {
|
if (r != ERROR_OK) {
|
||||||
LOG_ERROR("Cannot read SAM3 registere: %s @ 0x%08x, Error: %d\n",
|
LOG_ERROR("Cannot read SAM3 registere: %s @ 0x%08x, Error: %d",
|
||||||
pReg->name, ((unsigned)(pReg->address)), r);
|
pReg->name, ((unsigned)(pReg->address)), r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -1538,15 +1826,12 @@ sam3_GetInfo(struct sam3_chip *pChip)
|
|||||||
const struct sam3_reg_list *pReg;
|
const struct sam3_reg_list *pReg;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
membuf_reset(pChip->mbuf);
|
|
||||||
|
|
||||||
|
|
||||||
pReg = &(sam3_all_regs[0]);
|
pReg = &(sam3_all_regs[0]);
|
||||||
while (pReg->name) {
|
while (pReg->name) {
|
||||||
// display all regs
|
// display all regs
|
||||||
LOG_DEBUG("Start: %s", pReg->name);
|
LOG_DEBUG("Start: %s", pReg->name);
|
||||||
regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg);
|
regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg);
|
||||||
sam3_sprintf(pChip, "%*s: [0x%08x] -> 0x%08x\n",
|
LOG_USER("%*s: [0x%08x] -> 0x%08x",
|
||||||
REG_NAME_WIDTH,
|
REG_NAME_WIDTH,
|
||||||
pReg->name,
|
pReg->name,
|
||||||
pReg->address,
|
pReg->address,
|
||||||
@@ -1557,14 +1842,14 @@ sam3_GetInfo(struct sam3_chip *pChip)
|
|||||||
LOG_DEBUG("End: %s", pReg->name);
|
LOG_DEBUG("End: %s", pReg->name);
|
||||||
pReg++;
|
pReg++;
|
||||||
}
|
}
|
||||||
sam3_sprintf(pChip," rc-osc: %3.03f MHz\n", _tomhz(pChip->cfg.rc_freq));
|
LOG_USER(" rc-osc: %3.03f MHz", _tomhz(pChip->cfg.rc_freq));
|
||||||
sam3_sprintf(pChip," mainosc: %3.03f MHz\n", _tomhz(pChip->cfg.mainosc_freq));
|
LOG_USER(" mainosc: %3.03f MHz", _tomhz(pChip->cfg.mainosc_freq));
|
||||||
sam3_sprintf(pChip," plla: %3.03f MHz\n", _tomhz(pChip->cfg.plla_freq));
|
LOG_USER(" plla: %3.03f MHz", _tomhz(pChip->cfg.plla_freq));
|
||||||
sam3_sprintf(pChip," cpu-freq: %3.03f MHz\n", _tomhz(pChip->cfg.cpu_freq));
|
LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(pChip->cfg.cpu_freq));
|
||||||
sam3_sprintf(pChip,"mclk-freq: %3.03f MHz\n", _tomhz(pChip->cfg.mclk_freq));
|
LOG_USER("mclk-freq: %3.03f MHz", _tomhz(pChip->cfg.mclk_freq));
|
||||||
|
|
||||||
|
|
||||||
sam3_sprintf(pChip, " UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x\n",
|
LOG_USER(" UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x",
|
||||||
pChip->cfg.unique_id[0],
|
pChip->cfg.unique_id[0],
|
||||||
pChip->cfg.unique_id[1],
|
pChip->cfg.unique_id[1],
|
||||||
pChip->cfg.unique_id[2],
|
pChip->cfg.unique_id[2],
|
||||||
@@ -1586,7 +1871,7 @@ sam3_erase_check(struct flash_bank *bank)
|
|||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
if (0 == bank->num_sectors) {
|
if (0 == bank->num_sectors) {
|
||||||
LOG_ERROR("Target: not supported/not probed\n");
|
LOG_ERROR("Target: not supported/not probed");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1664,32 +1949,38 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
|
|||||||
// assumption is this runs at 32khz
|
// assumption is this runs at 32khz
|
||||||
pChip->cfg.slow_freq = 32768;
|
pChip->cfg.slow_freq = 32768;
|
||||||
pChip->probed = 0;
|
pChip->probed = 0;
|
||||||
pChip->mbuf = membuf_new();
|
|
||||||
if (!(pChip->mbuf)) {
|
|
||||||
LOG_ERROR("no memory");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bank->base) {
|
switch (bank->base) {
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x)",
|
LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x \
|
||||||
|
[at91sam3u series] or 0x%08x [at91sam3s series])",
|
||||||
((unsigned int)(bank->base)),
|
((unsigned int)(bank->base)),
|
||||||
((unsigned int)(FLASH_BANK0_BASE)),
|
((unsigned int)(FLASH_BANK0_BASE_U)),
|
||||||
((unsigned int)(FLASH_BANK1_BASE)));
|
((unsigned int)(FLASH_BANK1_BASE_U)),
|
||||||
|
((unsigned int)(FLASH_BANK_BASE_S)));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
break;
|
break;
|
||||||
case FLASH_BANK0_BASE:
|
|
||||||
|
// at91sam3u series
|
||||||
|
case FLASH_BANK0_BASE_U:
|
||||||
bank->driver_priv = &(pChip->details.bank[0]);
|
bank->driver_priv = &(pChip->details.bank[0]);
|
||||||
bank->bank_number = 0;
|
bank->bank_number = 0;
|
||||||
pChip->details.bank[0].pChip = pChip;
|
pChip->details.bank[0].pChip = pChip;
|
||||||
pChip->details.bank[0].pBank = bank;
|
pChip->details.bank[0].pBank = bank;
|
||||||
break;
|
break;
|
||||||
case FLASH_BANK1_BASE:
|
case FLASH_BANK1_BASE_U:
|
||||||
bank->driver_priv = &(pChip->details.bank[1]);
|
bank->driver_priv = &(pChip->details.bank[1]);
|
||||||
bank->bank_number = 1;
|
bank->bank_number = 1;
|
||||||
pChip->details.bank[1].pChip = pChip;
|
pChip->details.bank[1].pChip = pChip;
|
||||||
pChip->details.bank[1].pBank = bank;
|
pChip->details.bank[1].pBank = bank;
|
||||||
|
|
||||||
|
// at91sam3s series
|
||||||
|
case FLASH_BANK_BASE_S:
|
||||||
|
bank->driver_priv = &(pChip->details.bank[0]);
|
||||||
|
bank->bank_number = 0;
|
||||||
|
pChip->details.bank[0].pChip = pChip;
|
||||||
|
pChip->details.bank[0].pBank = bank;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1702,16 +1993,14 @@ sam3_GetDetails(struct sam3_bank_private *pPrivate)
|
|||||||
{
|
{
|
||||||
const struct sam3_chip_details *pDetails;
|
const struct sam3_chip_details *pDetails;
|
||||||
struct sam3_chip *pChip;
|
struct sam3_chip *pChip;
|
||||||
void *vp;
|
|
||||||
struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS];
|
struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS];
|
||||||
|
|
||||||
unsigned x;
|
unsigned x;
|
||||||
const char *cp;
|
|
||||||
|
|
||||||
LOG_DEBUG("Begin");
|
LOG_DEBUG("Begin");
|
||||||
pDetails = all_sam3_details;
|
pDetails = all_sam3_details;
|
||||||
while (pDetails->name) {
|
while (pDetails->name) {
|
||||||
if (pDetails->chipid_cidr == pPrivate->pChip->cfg.CHIPID_CIDR) {
|
// Compare cidr without version bits
|
||||||
|
if (pDetails->chipid_cidr == (pPrivate->pChip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
pDetails++;
|
pDetails++;
|
||||||
@@ -1721,16 +2010,9 @@ sam3_GetDetails(struct sam3_bank_private *pPrivate)
|
|||||||
LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can this chip?)",
|
LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can this chip?)",
|
||||||
(unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR));
|
(unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR));
|
||||||
// Help the victim, print details about the chip
|
// Help the victim, print details about the chip
|
||||||
membuf_reset(pPrivate->pChip->mbuf);
|
LOG_INFO("SAM3 CHIPID_CIDR: 0x%08x decodes as follows",
|
||||||
membuf_sprintf(pPrivate->pChip->mbuf,
|
|
||||||
"SAM3 CHIPID_CIDR: 0x%08x decodes as follows\n",
|
|
||||||
pPrivate->pChip->cfg.CHIPID_CIDR);
|
pPrivate->pChip->cfg.CHIPID_CIDR);
|
||||||
sam3_explain_chipid_cidr(pPrivate->pChip);
|
sam3_explain_chipid_cidr(pPrivate->pChip);
|
||||||
cp = membuf_strtok(pPrivate->pChip->mbuf, "\n", &vp);
|
|
||||||
while (cp) {
|
|
||||||
LOG_INFO("%s", cp);
|
|
||||||
cp = membuf_strtok(NULL, "\n", &vp);
|
|
||||||
}
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1787,7 +2069,7 @@ _sam3_probe(struct flash_bank *bank, int noise)
|
|||||||
|
|
||||||
pPrivate = get_sam3_bank_private(bank);
|
pPrivate = get_sam3_bank_private(bank);
|
||||||
if (!pPrivate) {
|
if (!pPrivate) {
|
||||||
LOG_ERROR("Invalid/unknown bank number\n");
|
LOG_ERROR("Invalid/unknown bank number");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1798,18 +2080,14 @@ _sam3_probe(struct flash_bank *bank, int noise)
|
|||||||
|
|
||||||
|
|
||||||
LOG_DEBUG("Here");
|
LOG_DEBUG("Here");
|
||||||
|
if (pPrivate->pChip->probed) {
|
||||||
r = sam3_GetInfo(pPrivate->pChip);
|
r = sam3_GetInfo(pPrivate->pChip);
|
||||||
if (r != ERROR_OK) {
|
} else {
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (!(pPrivate->pChip->probed)) {
|
|
||||||
pPrivate->pChip->probed = 1;
|
|
||||||
LOG_DEBUG("Here");
|
|
||||||
r = sam3_GetDetails(pPrivate);
|
r = sam3_GetDetails(pPrivate);
|
||||||
|
}
|
||||||
if (r != ERROR_OK) {
|
if (r != ERROR_OK) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// update the flash bank size
|
// update the flash bank size
|
||||||
for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
|
for (x = 0 ; x < SAM3_MAX_FLASH_BANKS ; x++) {
|
||||||
@@ -2046,9 +2324,7 @@ sam3_page_write_opcodes[] = {
|
|||||||
0x10,0xf0,0x01,0x0f,
|
0x10,0xf0,0x01,0x0f,
|
||||||
// 41 0024 FBD0 beq .L4
|
// 41 0024 FBD0 beq .L4
|
||||||
0xfb,0xd0,
|
0xfb,0xd0,
|
||||||
// 42 .done:
|
0x00,0xBE /* bkpt #0 */
|
||||||
// 43 0026 FEE7 b .done
|
|
||||||
0xfe,0xe7
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2258,8 +2534,6 @@ sam3_write(struct flash_bank *bank,
|
|||||||
COMMAND_HANDLER(sam3_handle_info_command)
|
COMMAND_HANDLER(sam3_handle_info_command)
|
||||||
{
|
{
|
||||||
struct sam3_chip *pChip;
|
struct sam3_chip *pChip;
|
||||||
void *vp;
|
|
||||||
const char *cp;
|
|
||||||
unsigned x;
|
unsigned x;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -2317,17 +2591,10 @@ COMMAND_HANDLER(sam3_handle_info_command)
|
|||||||
|
|
||||||
r = sam3_GetInfo(pChip);
|
r = sam3_GetInfo(pChip);
|
||||||
if (r != ERROR_OK) {
|
if (r != ERROR_OK) {
|
||||||
LOG_DEBUG("Sam3Info, Failed %d\n",r);
|
LOG_DEBUG("Sam3Info, Failed %d",r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// print results
|
|
||||||
cp = membuf_strtok(pChip->mbuf, "\n", &vp);
|
|
||||||
while (cp) {
|
|
||||||
command_print(CMD_CTX,"%s", cp);
|
|
||||||
cp = membuf_strtok(NULL, "\n", &vp);
|
|
||||||
}
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2418,7 +2685,7 @@ showall:
|
|||||||
(0 == strcmp("clear", CMD_ARGV[0]))) { // quietly accept both
|
(0 == strcmp("clear", CMD_ARGV[0]))) { // quietly accept both
|
||||||
r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who);
|
r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who);
|
||||||
} else {
|
} else {
|
||||||
command_print(CMD_CTX, "Unkown command: %s", CMD_ARGV[0]);
|
command_print(CMD_CTX, "Unknown command: %s", CMD_ARGV[0]);
|
||||||
r = ERROR_COMMAND_SYNTAX_ERROR;
|
r = ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@@ -2507,6 +2774,7 @@ struct flash_driver at91sam3_flash = {
|
|||||||
.erase = sam3_erase,
|
.erase = sam3_erase,
|
||||||
.protect = sam3_protect,
|
.protect = sam3_protect,
|
||||||
.write = sam3_write,
|
.write = sam3_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = sam3_probe,
|
.probe = sam3_probe,
|
||||||
.auto_probe = sam3_auto_probe,
|
.auto_probe = sam3_auto_probe,
|
||||||
.erase_check = sam3_erase_check,
|
.erase_check = sam3_erase_check,
|
||||||
|
|||||||
@@ -50,9 +50,55 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "at91sam7.h"
|
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* AT91SAM7 control registers */
|
||||||
|
#define DBGU_CIDR 0xFFFFF240
|
||||||
|
#define CKGR_MCFR 0xFFFFFC24
|
||||||
|
#define CKGR_MOR 0xFFFFFC20
|
||||||
|
#define CKGR_MCFR_MAINRDY 0x10000
|
||||||
|
#define CKGR_PLLR 0xFFFFFC2c
|
||||||
|
#define CKGR_PLLR_DIV 0xff
|
||||||
|
#define CKGR_PLLR_MUL 0x07ff0000
|
||||||
|
#define PMC_MCKR 0xFFFFFC30
|
||||||
|
#define PMC_MCKR_CSS 0x03
|
||||||
|
#define PMC_MCKR_PRES 0x1c
|
||||||
|
|
||||||
|
/* Flash Controller Commands */
|
||||||
|
#define WP 0x01
|
||||||
|
#define SLB 0x02
|
||||||
|
#define WPL 0x03
|
||||||
|
#define CLB 0x04
|
||||||
|
#define EA 0x08
|
||||||
|
#define SGPB 0x0B
|
||||||
|
#define CGPB 0x0D
|
||||||
|
#define SSB 0x0F
|
||||||
|
|
||||||
|
/* MC_FSR bit definitions */
|
||||||
|
#define MC_FSR_FRDY 1
|
||||||
|
#define MC_FSR_EOL 2
|
||||||
|
|
||||||
|
/* AT91SAM7 constants */
|
||||||
|
#define RC_FREQ 32000
|
||||||
|
|
||||||
|
/* Flash timing modes */
|
||||||
|
#define FMR_TIMING_NONE 0
|
||||||
|
#define FMR_TIMING_NVBITS 1
|
||||||
|
#define FMR_TIMING_FLASH 2
|
||||||
|
|
||||||
|
/* Flash size constants */
|
||||||
|
#define FLASH_SIZE_8KB 1
|
||||||
|
#define FLASH_SIZE_16KB 2
|
||||||
|
#define FLASH_SIZE_32KB 3
|
||||||
|
#define FLASH_SIZE_64KB 5
|
||||||
|
#define FLASH_SIZE_128KB 7
|
||||||
|
#define FLASH_SIZE_256KB 9
|
||||||
|
#define FLASH_SIZE_512KB 10
|
||||||
|
#define FLASH_SIZE_1024KB 12
|
||||||
|
#define FLASH_SIZE_2048KB 14
|
||||||
|
|
||||||
|
|
||||||
static int at91sam7_protect_check(struct flash_bank *bank);
|
static int at91sam7_protect_check(struct flash_bank *bank);
|
||||||
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||||
|
|
||||||
@@ -67,6 +113,50 @@ static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
|||||||
|
|
||||||
static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
|
static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
|
||||||
|
|
||||||
|
struct at91sam7_flash_bank
|
||||||
|
{
|
||||||
|
/* chip id register */
|
||||||
|
uint32_t cidr;
|
||||||
|
uint16_t cidr_ext;
|
||||||
|
uint16_t cidr_nvptyp;
|
||||||
|
uint16_t cidr_arch;
|
||||||
|
uint16_t cidr_sramsiz;
|
||||||
|
uint16_t cidr_nvpsiz;
|
||||||
|
uint16_t cidr_nvpsiz2;
|
||||||
|
uint16_t cidr_eproc;
|
||||||
|
uint16_t cidr_version;
|
||||||
|
const char *target_name;
|
||||||
|
|
||||||
|
/* flash auto-detection */
|
||||||
|
uint8_t flash_autodetection;
|
||||||
|
|
||||||
|
/* flash geometry */
|
||||||
|
uint16_t pages_per_sector;
|
||||||
|
uint16_t pagesize;
|
||||||
|
uint16_t pages_in_lockregion;
|
||||||
|
|
||||||
|
/* nv memory bits */
|
||||||
|
uint16_t num_lockbits_on;
|
||||||
|
uint16_t lockbits;
|
||||||
|
uint16_t num_nvmbits;
|
||||||
|
uint16_t num_nvmbits_on;
|
||||||
|
uint16_t nvmbits;
|
||||||
|
uint8_t securitybit;
|
||||||
|
|
||||||
|
/* 0: not init
|
||||||
|
* 1: fmcn for nvbits (1uS)
|
||||||
|
* 2: fmcn for flash (1.5uS) */
|
||||||
|
uint8_t flashmode;
|
||||||
|
|
||||||
|
/* main clock status */
|
||||||
|
uint8_t mck_valid;
|
||||||
|
uint32_t mck_freq;
|
||||||
|
|
||||||
|
/* external clock frequency */
|
||||||
|
uint32_t ext_freq;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static long SRAMSIZ[16] = {
|
static long SRAMSIZ[16] = {
|
||||||
-1,
|
-1,
|
||||||
@@ -298,7 +388,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
uint32_t ext_freq;
|
uint32_t ext_freq;
|
||||||
uint32_t bank_size;
|
uint32_t bank_size;
|
||||||
uint32_t base_address = 0;
|
uint32_t base_address = 0;
|
||||||
char *target_name = "Unknown";
|
char *target_name_t = "Unknown";
|
||||||
|
|
||||||
at91sam7_info = t_bank->driver_priv;
|
at91sam7_info = t_bank->driver_priv;
|
||||||
|
|
||||||
@@ -386,7 +476,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S161/16";
|
target_name_t = "AT91SAM7S161/16";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -399,12 +489,12 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S321/32";
|
target_name_t = "AT91SAM7S321/32";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7SE32";
|
target_name_t = "AT91SAM7SE32";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -417,7 +507,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S64";
|
target_name_t = "AT91SAM7S64";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -430,22 +520,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S128";
|
target_name_t = "AT91SAM7S128";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7XC128";
|
target_name_t = "AT91SAM7XC128";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7SE128";
|
target_name_t = "AT91SAM7SE128";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7X128";
|
target_name_t = "AT91SAM7X128";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -458,27 +548,27 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x60)
|
if (arch == 0x60)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7A3";
|
target_name_t = "AT91SAM7A3";
|
||||||
}
|
}
|
||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S256";
|
target_name_t = "AT91SAM7S256";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7XC256";
|
target_name_t = "AT91SAM7XC256";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7SE256";
|
target_name_t = "AT91SAM7SE256";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7X256";
|
target_name_t = "AT91SAM7X256";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -491,22 +581,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
if (arch == 0x70)
|
if (arch == 0x70)
|
||||||
{
|
{
|
||||||
num_nvmbits = 2;
|
num_nvmbits = 2;
|
||||||
target_name = "AT91SAM7S512";
|
target_name_t = "AT91SAM7S512";
|
||||||
}
|
}
|
||||||
if (arch == 0x71)
|
if (arch == 0x71)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7XC512";
|
target_name_t = "AT91SAM7XC512";
|
||||||
}
|
}
|
||||||
if (arch == 0x72)
|
if (arch == 0x72)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7SE512";
|
target_name_t = "AT91SAM7SE512";
|
||||||
}
|
}
|
||||||
if (arch == 0x75)
|
if (arch == 0x75)
|
||||||
{
|
{
|
||||||
num_nvmbits = 3;
|
num_nvmbits = 3;
|
||||||
target_name = "AT91SAM7X512";
|
target_name_t = "AT91SAM7X512";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -517,7 +607,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(target_name, "Unknown") == 0)
|
if (strcmp(target_name_t, "Unknown") == 0)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
|
LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
@@ -573,7 +663,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
|
|||||||
at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
|
at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
|
||||||
at91sam7_info->cidr_version = cidr&0x001F;
|
at91sam7_info->cidr_version = cidr&0x001F;
|
||||||
|
|
||||||
at91sam7_info->target_name = target_name;
|
at91sam7_info->target_name = target_name_t;
|
||||||
at91sam7_info->flashmode = 0;
|
at91sam7_info->flashmode = 0;
|
||||||
at91sam7_info->ext_freq = ext_freq;
|
at91sam7_info->ext_freq = ext_freq;
|
||||||
at91sam7_info->num_nvmbits = num_nvmbits;
|
at91sam7_info->num_nvmbits = num_nvmbits;
|
||||||
@@ -731,7 +821,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
uint16_t page_size;
|
uint16_t page_size;
|
||||||
uint16_t num_nvmbits;
|
uint16_t num_nvmbits;
|
||||||
|
|
||||||
char *target_name;
|
char *target_name_t;
|
||||||
|
|
||||||
int bnk, sec;
|
int bnk, sec;
|
||||||
|
|
||||||
@@ -775,8 +865,8 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_name = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
|
target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
|
||||||
strcpy(target_name, CMD_ARGV[7]);
|
strcpy(target_name_t, CMD_ARGV[7]);
|
||||||
|
|
||||||
/* calculate bank size */
|
/* calculate bank size */
|
||||||
bank_size = num_sectors * pages_per_sector * page_size;
|
bank_size = num_sectors * pages_per_sector * page_size;
|
||||||
@@ -816,7 +906,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
|||||||
|
|
||||||
at91sam7_info = t_bank->driver_priv;
|
at91sam7_info = t_bank->driver_priv;
|
||||||
|
|
||||||
at91sam7_info->target_name = target_name;
|
at91sam7_info->target_name = target_name_t;
|
||||||
at91sam7_info->flashmode = 0;
|
at91sam7_info->flashmode = 0;
|
||||||
at91sam7_info->ext_freq = ext_freq;
|
at91sam7_info->ext_freq = ext_freq;
|
||||||
at91sam7_info->num_nvmbits = num_nvmbits;
|
at91sam7_info->num_nvmbits = num_nvmbits;
|
||||||
@@ -1034,7 +1124,7 @@ static int at91sam7_probe(struct flash_bank *bank)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
{
|
{
|
||||||
int printed;
|
int printed;
|
||||||
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
|
||||||
@@ -1171,7 +1261,7 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
|
|||||||
|
|
||||||
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
||||||
status = at91sam7_get_flash_status(bank->target, 0);
|
status = at91sam7_get_flash_status(bank->target, 0);
|
||||||
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32 " \n", flashcmd, bit, status);
|
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32, flashcmd, bit, status);
|
||||||
|
|
||||||
/* check protect state */
|
/* check protect state */
|
||||||
at91sam7_protect_check(bank);
|
at91sam7_protect_check(bank);
|
||||||
@@ -1207,9 +1297,10 @@ struct flash_driver at91sam7_flash = {
|
|||||||
.erase = at91sam7_erase,
|
.erase = at91sam7_erase,
|
||||||
.protect = at91sam7_protect,
|
.protect = at91sam7_protect,
|
||||||
.write = at91sam7_write,
|
.write = at91sam7_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = at91sam7_probe,
|
.probe = at91sam7_probe,
|
||||||
.auto_probe = at91sam7_probe,
|
.auto_probe = at91sam7_probe,
|
||||||
.erase_check = at91sam7_erase_check,
|
.erase_check = at91sam7_erase_check,
|
||||||
.protect_check = at91sam7_protect_check,
|
.protect_check = at91sam7_protect_check,
|
||||||
.info = at91sam7_info,
|
.info = get_at91sam7_info,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2006 by Magnus Lundin *
|
|
||||||
* lundin@mlu.mine.nu *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2006 by Gheorghe Guran (atlas) *
|
|
||||||
* *
|
|
||||||
* 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 AT91SAM7_H
|
|
||||||
#define AT91SAM7_H
|
|
||||||
|
|
||||||
struct at91sam7_flash_bank
|
|
||||||
{
|
|
||||||
/* chip id register */
|
|
||||||
uint32_t cidr;
|
|
||||||
uint16_t cidr_ext;
|
|
||||||
uint16_t cidr_nvptyp;
|
|
||||||
uint16_t cidr_arch;
|
|
||||||
uint16_t cidr_sramsiz;
|
|
||||||
uint16_t cidr_nvpsiz;
|
|
||||||
uint16_t cidr_nvpsiz2;
|
|
||||||
uint16_t cidr_eproc;
|
|
||||||
uint16_t cidr_version;
|
|
||||||
char *target_name;
|
|
||||||
|
|
||||||
/* flash auto-detection */
|
|
||||||
uint8_t flash_autodetection;
|
|
||||||
|
|
||||||
/* flash geometry */
|
|
||||||
uint16_t pages_per_sector;
|
|
||||||
uint16_t pagesize;
|
|
||||||
uint16_t pages_in_lockregion;
|
|
||||||
|
|
||||||
/* nv memory bits */
|
|
||||||
uint16_t num_lockbits_on;
|
|
||||||
uint16_t lockbits;
|
|
||||||
uint16_t num_nvmbits;
|
|
||||||
uint16_t num_nvmbits_on;
|
|
||||||
uint16_t nvmbits;
|
|
||||||
uint8_t securitybit;
|
|
||||||
|
|
||||||
/* 0: not init
|
|
||||||
* 1: fmcn for nvbits (1uS)
|
|
||||||
* 2: fmcn for flash (1.5uS) */
|
|
||||||
uint8_t flashmode;
|
|
||||||
|
|
||||||
/* main clock status */
|
|
||||||
uint8_t mck_valid;
|
|
||||||
uint32_t mck_freq;
|
|
||||||
|
|
||||||
/* external clock frequency */
|
|
||||||
uint32_t ext_freq;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* AT91SAM7 control registers */
|
|
||||||
#define DBGU_CIDR 0xFFFFF240
|
|
||||||
#define CKGR_MCFR 0xFFFFFC24
|
|
||||||
#define CKGR_MOR 0xFFFFFC20
|
|
||||||
#define CKGR_MCFR_MAINRDY 0x10000
|
|
||||||
#define CKGR_PLLR 0xFFFFFC2c
|
|
||||||
#define CKGR_PLLR_DIV 0xff
|
|
||||||
#define CKGR_PLLR_MUL 0x07ff0000
|
|
||||||
#define PMC_MCKR 0xFFFFFC30
|
|
||||||
#define PMC_MCKR_CSS 0x03
|
|
||||||
#define PMC_MCKR_PRES 0x1c
|
|
||||||
|
|
||||||
/* Flash Controller Commands */
|
|
||||||
#define WP 0x01
|
|
||||||
#define SLB 0x02
|
|
||||||
#define WPL 0x03
|
|
||||||
#define CLB 0x04
|
|
||||||
#define EA 0x08
|
|
||||||
#define SGPB 0x0B
|
|
||||||
#define CGPB 0x0D
|
|
||||||
#define SSB 0x0F
|
|
||||||
|
|
||||||
/* MC_FSR bit definitions */
|
|
||||||
#define MC_FSR_FRDY 1
|
|
||||||
#define MC_FSR_EOL 2
|
|
||||||
|
|
||||||
/* AT91SAM7 constants */
|
|
||||||
#define RC_FREQ 32000
|
|
||||||
|
|
||||||
/* Flash timing modes */
|
|
||||||
#define FMR_TIMING_NONE 0
|
|
||||||
#define FMR_TIMING_NVBITS 1
|
|
||||||
#define FMR_TIMING_FLASH 2
|
|
||||||
|
|
||||||
/* Flash size constants */
|
|
||||||
#define FLASH_SIZE_8KB 1
|
|
||||||
#define FLASH_SIZE_16KB 2
|
|
||||||
#define FLASH_SIZE_32KB 3
|
|
||||||
#define FLASH_SIZE_64KB 5
|
|
||||||
#define FLASH_SIZE_128KB 7
|
|
||||||
#define FLASH_SIZE_256KB 9
|
|
||||||
#define FLASH_SIZE_512KB 10
|
|
||||||
#define FLASH_SIZE_1024KB 12
|
|
||||||
#define FLASH_SIZE_2048KB 14
|
|
||||||
|
|
||||||
#endif /* AT91SAM7_H */
|
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "avrf.h"
|
|
||||||
#include <target/avrt.h>
|
#include <target/avrt.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -50,24 +49,30 @@
|
|||||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||||
|
|
||||||
struct avrf_type avft_chips_info[] =
|
struct avrf_type
|
||||||
{
|
{
|
||||||
// name, chip_id, flash_page_size, flash_page_num, eeprom_page_size, eeprom_page_num
|
char name[15];
|
||||||
{"atmega128", 0x9702, 256, 512, 8, 512},
|
uint16_t chip_id;
|
||||||
|
int flash_page_size;
|
||||||
|
int flash_page_num;
|
||||||
|
int eeprom_page_size;
|
||||||
|
int eeprom_page_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out);
|
struct avrf_flash_bank
|
||||||
int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len);
|
{
|
||||||
|
int ppage_size;
|
||||||
|
int probed;
|
||||||
|
};
|
||||||
|
|
||||||
int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
|
static struct avrf_type avft_chips_info[] =
|
||||||
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);
|
/* name, chip_id, flash_page_size, flash_page_num,
|
||||||
int mcu_write_dr_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
|
* eeprom_page_size, eeprom_page_num
|
||||||
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);
|
{"atmega128", 0x9702, 256, 512, 8, 512},
|
||||||
int mcu_write_ir_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
|
{"at90can128", 0x9781, 256, 512, 8, 512},
|
||||||
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 */
|
/* avr program functions */
|
||||||
static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
|
static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
|
||||||
@@ -200,8 +205,27 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
|
|||||||
|
|
||||||
static int avrf_erase(struct flash_bank *bank, int first, int last)
|
static int avrf_erase(struct flash_bank *bank, int first, int last)
|
||||||
{
|
{
|
||||||
LOG_INFO("%s", __FUNCTION__);
|
struct target *target = bank->target;
|
||||||
return ERROR_OK;
|
struct avr_common *avr = target->arch_info;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
LOG_DEBUG("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = avr_jtagprg_enterprogmode(avr);
|
||||||
|
if (status != ERROR_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = avr_jtagprg_chiperase(avr);
|
||||||
|
if (status != ERROR_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
return avr_jtagprg_leaveprogmode(avr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
|
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
|
||||||
@@ -302,6 +326,12 @@ static int avrf_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
if (avr_info != NULL)
|
if (avr_info != NULL)
|
||||||
{
|
{
|
||||||
|
if (bank->sectors)
|
||||||
|
{
|
||||||
|
free(bank->sectors);
|
||||||
|
bank->sectors = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// chip found
|
// chip found
|
||||||
bank->base = 0x00000000;
|
bank->base = 0x00000000;
|
||||||
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
|
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
|
||||||
@@ -475,6 +505,7 @@ struct flash_driver avr_flash = {
|
|||||||
.erase = avrf_erase,
|
.erase = avrf_erase,
|
||||||
.protect = avrf_protect,
|
.protect = avrf_protect,
|
||||||
.write = avrf_write,
|
.write = avrf_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = avrf_probe,
|
.probe = avrf_probe,
|
||||||
.auto_probe = avrf_auto_probe,
|
.auto_probe = avrf_auto_probe,
|
||||||
.erase_check = default_flash_mem_blank_check,
|
.erase_check = default_flash_mem_blank_check,
|
||||||
|
|||||||
1749
src/flash/nor/cfi.c
1749
src/flash/nor/cfi.c
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ struct cfi_flash_bank
|
|||||||
uint16_t manufacturer;
|
uint16_t manufacturer;
|
||||||
uint16_t device_id;
|
uint16_t device_id;
|
||||||
|
|
||||||
char qry[3];
|
uint8_t qry[3];
|
||||||
|
|
||||||
/* identification string */
|
/* identification string */
|
||||||
uint16_t pri_id;
|
uint16_t pri_id;
|
||||||
@@ -68,6 +68,12 @@ struct cfi_flash_bank
|
|||||||
|
|
||||||
void *pri_ext;
|
void *pri_ext;
|
||||||
void *alt_ext;
|
void *alt_ext;
|
||||||
|
|
||||||
|
/* calculated timeouts */
|
||||||
|
unsigned word_write_timeout;
|
||||||
|
unsigned buf_write_timeout;
|
||||||
|
unsigned block_erase_timeout;
|
||||||
|
unsigned chip_erase_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Intel primary extended query table
|
/* Intel primary extended query table
|
||||||
@@ -76,7 +82,7 @@ struct cfi_flash_bank
|
|||||||
*/
|
*/
|
||||||
struct cfi_intel_pri_ext
|
struct cfi_intel_pri_ext
|
||||||
{
|
{
|
||||||
char pri[3];
|
uint8_t pri[3];
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
uint8_t minor_version;
|
uint8_t minor_version;
|
||||||
uint32_t feature_support;
|
uint32_t feature_support;
|
||||||
@@ -144,7 +150,7 @@ struct cfi_fixup
|
|||||||
{
|
{
|
||||||
uint16_t mfr;
|
uint16_t mfr;
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
void (*fixup)(struct flash_bank *flash, void *param);
|
void (*fixup)(struct flash_bank *bank, void *param);
|
||||||
void *param;
|
void *param;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
|
||||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
* Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||||
|
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
* primarily support access from Tcl scripts or from GDB.
|
* primarily support access from Tcl scripts or from GDB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct flash_bank *flash_banks;
|
static struct flash_bank *flash_banks;
|
||||||
|
|
||||||
int flash_driver_erase(struct flash_bank *bank, int first, int last)
|
int flash_driver_erase(struct flash_bank *bank, int first, int last)
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ int flash_driver_erase(struct flash_bank *bank, int first, int last)
|
|||||||
retval = bank->driver->erase(bank, first, last);
|
retval = bank->driver->erase(bank, first, last);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
|
LOG_ERROR("failed erasing sectors %d to %d", first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -55,10 +56,31 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
|
|||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
/* callers may not supply illegal parameters ... */
|
||||||
|
if (first < 0 || first > last || last >= bank->num_sectors)
|
||||||
|
{
|
||||||
|
LOG_ERROR("illegal sector range");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* force "set" to 0/1 */
|
||||||
|
set = !!set;
|
||||||
|
|
||||||
|
/* DANGER!
|
||||||
|
*
|
||||||
|
* We must not use any cached information about protection state!!!!
|
||||||
|
*
|
||||||
|
* There are a million things that could change the protect state:
|
||||||
|
*
|
||||||
|
* the target could have reset, power cycled, been hot plugged,
|
||||||
|
* the application could have run, etc.
|
||||||
|
*
|
||||||
|
* Drivers only receive valid sector range.
|
||||||
|
*/
|
||||||
retval = bank->driver->protect(bank, set, first, last);
|
retval = bank->driver->protect(bank, set, first, last);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
|
LOG_ERROR("failed setting protection for areas %d to %d", first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -72,13 +94,36 @@ int flash_driver_write(struct flash_bank *bank,
|
|||||||
retval = bank->driver->write(bank, buffer, offset, count);
|
retval = bank->driver->write(bank, buffer, offset, count);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)",
|
LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||||
bank->base, offset, retval);
|
bank->base, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flash_driver_read(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
LOG_DEBUG("call flash_driver_read()");
|
||||||
|
|
||||||
|
retval = bank->driver->read(bank, buffer, offset, count);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
|
||||||
|
bank->base, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int default_flash_read(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
return target_read_buffer(bank->target, offset + bank->base, count, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void flash_bank_add(struct flash_bank *bank)
|
void flash_bank_add(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
/* put flash bank in linked list */
|
/* put flash bank in linked list */
|
||||||
@@ -133,7 +178,7 @@ int flash_get_bank_count(void)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct flash_bank *get_flash_bank_by_name(const char *name)
|
struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
|
||||||
{
|
{
|
||||||
unsigned requested = get_flash_name_index(name);
|
unsigned requested = get_flash_name_index(name);
|
||||||
unsigned found = 0;
|
unsigned found = 0;
|
||||||
@@ -152,26 +197,51 @@ struct flash_bank *get_flash_bank_by_name(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct flash_bank *get_flash_bank_by_num(int num)
|
int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result)
|
||||||
|
{
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
bank = get_flash_bank_by_name_noprobe(name);
|
||||||
|
if (bank != NULL)
|
||||||
|
{
|
||||||
|
retval = bank->driver->auto_probe(bank);
|
||||||
|
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_ERROR("auto_probe failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*bank_result = bank;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_flash_bank_by_num(int num, struct flash_bank **bank)
|
||||||
{
|
{
|
||||||
struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
|
struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
{
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
retval = p->driver->auto_probe(p);
|
retval = p->driver->auto_probe(p);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("auto_probe failed %d\n", retval);
|
LOG_ERROR("auto_probe failed");
|
||||||
return NULL;
|
return retval;
|
||||||
}
|
}
|
||||||
return p;
|
*bank = p;
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup flash bank by address */
|
/* lookup flash bank by address, bank not found is success, but
|
||||||
struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
|
* result_bank is set to NULL. */
|
||||||
|
int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank)
|
||||||
{
|
{
|
||||||
struct flash_bank *c;
|
struct flash_bank *c;
|
||||||
|
|
||||||
@@ -183,15 +253,23 @@ struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
|
|||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
LOG_ERROR("auto_probe failed %d\n", retval);
|
LOG_ERROR("auto_probe failed");
|
||||||
return NULL;
|
return retval;
|
||||||
}
|
}
|
||||||
/* check whether address belongs to this flash bank */
|
/* check whether address belongs to this flash bank */
|
||||||
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
|
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
|
||||||
return c;
|
{
|
||||||
|
*result_bank = c;
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
|
}
|
||||||
return NULL;
|
*result_bank = NULL;
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int default_flash_mem_blank_check(struct flash_bank *bank)
|
int default_flash_mem_blank_check(struct flash_bank *bank)
|
||||||
@@ -301,7 +379,7 @@ int default_flash_blank_check(struct flash_bank *bank)
|
|||||||
* sectors will be added to the range, and that reason string is used when
|
* sectors will be added to the range, and that reason string is used when
|
||||||
* warning about those additions.
|
* warning about those additions.
|
||||||
*/
|
*/
|
||||||
static int flash_iterate_address_range(struct target *target,
|
static int flash_iterate_address_range_inner(struct target *target,
|
||||||
char *pad_reason, uint32_t addr, uint32_t length,
|
char *pad_reason, uint32_t addr, uint32_t length,
|
||||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||||
{
|
{
|
||||||
@@ -311,8 +389,9 @@ static int flash_iterate_address_range(struct target *target,
|
|||||||
int last = -1;
|
int last = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((c = get_flash_bank_by_addr(target, addr)) == NULL)
|
int retval = get_flash_bank_by_addr(target, addr, true, &c);
|
||||||
return ERROR_FLASH_DST_OUT_OF_BANK; /* no corresponding bank found */
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
if (c->size == 0 || c->num_sectors == 0)
|
if (c->size == 0 || c->num_sectors == 0)
|
||||||
{
|
{
|
||||||
@@ -419,6 +498,43 @@ static int flash_iterate_address_range(struct target *target,
|
|||||||
return callback(c, first, last);
|
return callback(c, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The inner fn only handles a single bank, we could be spanning
|
||||||
|
* multiple chips.
|
||||||
|
*/
|
||||||
|
static int flash_iterate_address_range(struct target *target,
|
||||||
|
char *pad_reason, uint32_t addr, uint32_t length,
|
||||||
|
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||||
|
{
|
||||||
|
struct flash_bank *c;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
/* Danger! zero-length iterations means entire bank! */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
retval = get_flash_bank_by_addr(target, addr, true, &c);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
uint32_t cur_length = length;
|
||||||
|
/* check whether it all fits in this bank */
|
||||||
|
if (addr + length - 1 > c->base + c->size - 1)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("iterating over more than one flash bank.");
|
||||||
|
cur_length = c->base + c->size - addr;
|
||||||
|
}
|
||||||
|
retval = flash_iterate_address_range_inner(target,
|
||||||
|
pad_reason, addr, cur_length,
|
||||||
|
callback);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
length -= cur_length;
|
||||||
|
addr += cur_length;
|
||||||
|
} while (length > 0);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int flash_erase_address_range(struct target *target,
|
int flash_erase_address_range(struct target *target,
|
||||||
bool pad, uint32_t addr, uint32_t length)
|
bool pad, uint32_t addr, uint32_t length)
|
||||||
{
|
{
|
||||||
@@ -431,7 +547,7 @@ static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
|
|||||||
return flash_driver_protect(bank, 0, first, last);
|
return flash_driver_protect(bank, 0, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
|
int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
|
||||||
{
|
{
|
||||||
/* By default, pad to sector boundaries ... the real issue here
|
/* By default, pad to sector boundaries ... the real issue here
|
||||||
* is that our (only) caller *permanently* removes protection,
|
* is that our (only) caller *permanently* removes protection,
|
||||||
@@ -441,6 +557,25 @@ static int flash_unlock_address_range(struct target *target, uint32_t addr, uint
|
|||||||
addr, length, &flash_driver_unprotect);
|
addr, length, &flash_driver_unprotect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compare_section (const void * a, const void * b)
|
||||||
|
{
|
||||||
|
struct imagesection *b1, *b2;
|
||||||
|
b1=*((struct imagesection **)a);
|
||||||
|
b2=*((struct imagesection **)b);
|
||||||
|
|
||||||
|
if (b1->base_address == b2->base_address)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
} else if (b1->base_address > b2->base_address)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int flash_write_unlock(struct target *target, struct image *image,
|
int flash_write_unlock(struct target *target, struct image *image,
|
||||||
uint32_t *written, int erase, bool unlock)
|
uint32_t *written, int erase, bool unlock)
|
||||||
{
|
{
|
||||||
@@ -451,12 +586,6 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
struct flash_bank *c;
|
struct flash_bank *c;
|
||||||
int *padding;
|
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 = 0;
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
|
|
||||||
@@ -474,18 +603,30 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
/* allocate padding array */
|
/* allocate padding array */
|
||||||
padding = calloc(image->num_sections, sizeof(*padding));
|
padding = calloc(image->num_sections, sizeof(*padding));
|
||||||
|
|
||||||
|
/* This fn requires all sections to be in ascending order of addresses,
|
||||||
|
* whereas an image can have sections out of order. */
|
||||||
|
struct imagesection **sections = malloc(sizeof(struct imagesection *) *
|
||||||
|
image->num_sections);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < image->num_sections; i++)
|
||||||
|
{
|
||||||
|
sections[i] = &image->sections[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(sections, image->num_sections, sizeof(struct imagesection *),
|
||||||
|
compare_section);
|
||||||
|
|
||||||
/* loop until we reach end of the image */
|
/* loop until we reach end of the image */
|
||||||
while (section < image->num_sections)
|
while (section < image->num_sections)
|
||||||
{
|
{
|
||||||
uint32_t buffer_size;
|
uint32_t buffer_size;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
int section_first;
|
|
||||||
int section_last;
|
int section_last;
|
||||||
uint32_t run_address = image->sections[section].base_address + section_offset;
|
uint32_t run_address = sections[section]->base_address + section_offset;
|
||||||
uint32_t run_size = image->sections[section].size - section_offset;
|
uint32_t run_size = sections[section]->size - section_offset;
|
||||||
int pad_bytes = 0;
|
int pad_bytes = 0;
|
||||||
|
|
||||||
if (image->sections[section].size == 0)
|
if (sections[section]->size == 0)
|
||||||
{
|
{
|
||||||
LOG_WARNING("empty section %d", section);
|
LOG_WARNING("empty section %d", section);
|
||||||
section++;
|
section++;
|
||||||
@@ -494,7 +635,12 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* find the corresponding flash bank */
|
/* find the corresponding flash bank */
|
||||||
if ((c = get_flash_bank_by_addr(target, run_address)) == NULL)
|
retval = get_flash_bank_by_addr(target, run_address, false, &c);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (c == NULL)
|
||||||
{
|
{
|
||||||
section++; /* and skip it */
|
section++; /* and skip it */
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
@@ -502,20 +648,16 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* collect consecutive sections which fall into the same bank */
|
/* collect consecutive sections which fall into the same bank */
|
||||||
section_first = section;
|
|
||||||
section_last = section;
|
section_last = section;
|
||||||
padding[section] = 0;
|
padding[section] = 0;
|
||||||
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
||||||
&& (section_last + 1 < image->num_sections))
|
&& (section_last + 1 < image->num_sections))
|
||||||
{
|
{
|
||||||
if (image->sections[section_last + 1].base_address < (run_address + run_size))
|
/* sections are sorted */
|
||||||
|
assert(sections[section_last + 1]->base_address >= c->base);
|
||||||
|
if (sections[section_last + 1]->base_address >= (c->base + c->size))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("section %d out of order "
|
/* Done with this bank */
|
||||||
"(surprising, but supported)",
|
|
||||||
section_last + 1);
|
|
||||||
/* REVISIT this can break with autoerase ...
|
|
||||||
* clobbering data after it's written.
|
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,25 +678,24 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
/* if we have multiple sections within our image,
|
/* if we have multiple sections within our image,
|
||||||
* flash programming could fail due to alignment issues
|
* flash programming could fail due to alignment issues
|
||||||
* attempt to rebuild a consecutive buffer for the flash loader */
|
* attempt to rebuild a consecutive buffer for the flash loader */
|
||||||
pad_bytes = (image->sections[section_last + 1].base_address) - (run_address + run_size);
|
pad_bytes = (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;
|
padding[section_last] = pad_bytes;
|
||||||
run_size += image->sections[++section_last].size;
|
run_size += sections[++section_last]->size;
|
||||||
run_size += pad_bytes;
|
run_size += pad_bytes;
|
||||||
|
|
||||||
|
if (pad_bytes > 0)
|
||||||
LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
|
LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fit the run into bank constraints */
|
|
||||||
if (run_address + run_size - 1 > c->base + c->size - 1)
|
if (run_address + run_size - 1 > c->base + c->size - 1)
|
||||||
{
|
{
|
||||||
/* REVISIT isn't this superfluous, given the while()
|
/* If we have more than one flash chip back to back, then we limit
|
||||||
* loop conditions above??
|
* the current write operation to the current chip.
|
||||||
*/
|
*/
|
||||||
LOG_WARNING("writing %d bytes only - as image section is %d bytes and bank is only %d bytes", \
|
LOG_DEBUG("Truncate flash run size to the current flash chip.");
|
||||||
(int)(c->base + c->size - run_address), (int)(run_size), (int)(c->size));
|
|
||||||
run_size = c->base + c->size - run_address;
|
run_size = c->base + c->size - run_address;
|
||||||
|
assert(run_size > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're applying any sector automagic, then pad this
|
/* If we're applying any sector automagic, then pad this
|
||||||
@@ -580,6 +721,12 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
|
|
||||||
/* allocate buffer */
|
/* allocate buffer */
|
||||||
buffer = malloc(run_size);
|
buffer = malloc(run_size);
|
||||||
|
if (buffer == NULL)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Out of memory for flash bank buffer");
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
buffer_size = 0;
|
buffer_size = 0;
|
||||||
|
|
||||||
/* read sections to the buffer */
|
/* read sections to the buffer */
|
||||||
@@ -588,15 +735,25 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
size_t size_read;
|
size_t size_read;
|
||||||
|
|
||||||
size_read = run_size - buffer_size;
|
size_read = run_size - buffer_size;
|
||||||
if (size_read > image->sections[section].size - section_offset)
|
if (size_read > sections[section]->size - section_offset)
|
||||||
size_read = image->sections[section].size - section_offset;
|
size_read = sections[section]->size - section_offset;
|
||||||
|
|
||||||
if ((retval = image_read_section(image, section, section_offset,
|
/* KLUDGE!
|
||||||
|
*
|
||||||
|
* #¤%#"%¤% we have to figure out the section # from the sorted
|
||||||
|
* list of pointers to sections to invoke image_read_section()...
|
||||||
|
*/
|
||||||
|
intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections;
|
||||||
|
int t_section_num = diff / sizeof(struct imagesection);
|
||||||
|
|
||||||
|
LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, section_offset = %d, buffer_size = %d, size_read = %d",
|
||||||
|
(int)section,
|
||||||
|
(int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read);
|
||||||
|
if ((retval = image_read_section(image, t_section_num, section_offset,
|
||||||
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
|
size_read, buffer + buffer_size, &size_read)) != ERROR_OK || size_read == 0)
|
||||||
{
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
free(padding);
|
goto done;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see if we need to pad the section */
|
/* see if we need to pad the section */
|
||||||
@@ -606,7 +763,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
buffer_size += size_read;
|
buffer_size += size_read;
|
||||||
section_offset += size_read;
|
section_offset += size_read;
|
||||||
|
|
||||||
if (section_offset >= image->sections[section].size)
|
if (section_offset >= sections[section]->size)
|
||||||
{
|
{
|
||||||
section++;
|
section++;
|
||||||
section_offset = 0;
|
section_offset = 0;
|
||||||
@@ -625,7 +782,7 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
{
|
{
|
||||||
/* calculate and erase sectors */
|
/* calculate and erase sectors */
|
||||||
retval = flash_erase_address_range(target,
|
retval = flash_erase_address_range(target,
|
||||||
do_pad, run_address, run_size);
|
true, run_address, run_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,14 +796,17 @@ int flash_write_unlock(struct target *target, struct image *image,
|
|||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
{
|
{
|
||||||
free(padding);
|
/* abort operation */
|
||||||
return retval; /* abort operation */
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written != NULL)
|
if (written != NULL)
|
||||||
*written += run_size; /* add run size to total written counter */
|
*written += run_size; /* add run size to total written counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(sections);
|
||||||
free(padding);
|
free(padding);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||||
|
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -53,6 +54,10 @@ struct flash_sector
|
|||||||
* Indication of protection status: 0 = unprotected/unlocked,
|
* Indication of protection status: 0 = unprotected/unlocked,
|
||||||
* 1 = protected/locked, other = unknown. Set by
|
* 1 = protected/locked, other = unknown. Set by
|
||||||
* @c flash_driver_s::protect_check.
|
* @c flash_driver_s::protect_check.
|
||||||
|
*
|
||||||
|
* This information must be considered stale immediately.
|
||||||
|
* A million things could make it stale: power cycle,
|
||||||
|
* reset of target, code running on target, etc.
|
||||||
*/
|
*/
|
||||||
int is_protected;
|
int is_protected;
|
||||||
};
|
};
|
||||||
@@ -69,7 +74,7 @@ struct flash_sector
|
|||||||
*/
|
*/
|
||||||
struct flash_bank
|
struct flash_bank
|
||||||
{
|
{
|
||||||
char *name;
|
const char *name;
|
||||||
|
|
||||||
struct target *target; /**< Target to which this bank belongs. */
|
struct target *target; /**< Target to which this bank belongs. */
|
||||||
|
|
||||||
@@ -97,8 +102,6 @@ struct flash_bank
|
|||||||
|
|
||||||
/// Registers the 'flash' subsystem commands
|
/// Registers the 'flash' subsystem commands
|
||||||
int flash_register_commands(struct command_context *cmd_ctx);
|
int flash_register_commands(struct command_context *cmd_ctx);
|
||||||
/// 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.
|
* Erases @a length bytes in the @a target flash, starting at @a addr.
|
||||||
@@ -110,6 +113,9 @@ int flash_init_drivers(struct command_context *cmd_ctx);
|
|||||||
int flash_erase_address_range(struct target *target,
|
int flash_erase_address_range(struct target *target,
|
||||||
bool pad, uint32_t addr, uint32_t length);
|
bool pad, uint32_t addr, uint32_t length);
|
||||||
|
|
||||||
|
int flash_unlock_address_range(struct target *target, uint32_t addr,
|
||||||
|
uint32_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes @a image into the @a target flash. The @a written parameter
|
* Writes @a image into the @a target flash. The @a written parameter
|
||||||
* will contain the
|
* will contain the
|
||||||
@@ -122,6 +128,7 @@ int flash_erase_address_range(struct target *target,
|
|||||||
*/
|
*/
|
||||||
int flash_write(struct target *target,
|
int flash_write(struct target *target,
|
||||||
struct image *image, uint32_t *written, int erase);
|
struct image *image, uint32_t *written, int erase);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces targets to re-examine their erase/protection state.
|
* Forces targets to re-examine their erase/protection state.
|
||||||
* This routine must be called when the system may modify the status.
|
* This routine must be called when the system may modify the status.
|
||||||
@@ -129,6 +136,16 @@ int flash_write(struct target *target,
|
|||||||
void flash_set_dirty(void);
|
void flash_set_dirty(void);
|
||||||
/// @returns The number of flash banks currently defined.
|
/// @returns The number of flash banks currently defined.
|
||||||
int flash_get_bank_count(void);
|
int flash_get_bank_count(void);
|
||||||
|
/**
|
||||||
|
* Provides default read implementation for flash memory.
|
||||||
|
* @param bank The bank to read.
|
||||||
|
* @param buffer The data bytes read.
|
||||||
|
* @param offset The offset into the chip to read.
|
||||||
|
* @param count The number of bytes to read.
|
||||||
|
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||||
|
*/
|
||||||
|
int default_flash_read(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||||
/**
|
/**
|
||||||
* Provides default erased-bank check handling. Checks to see if
|
* Provides default erased-bank check handling. Checks to see if
|
||||||
* the flash driver knows they are erased; if things look uncertain,
|
* the flash driver knows they are erased; if things look uncertain,
|
||||||
@@ -151,13 +168,22 @@ int default_flash_mem_blank_check(struct flash_bank *bank);
|
|||||||
* bank number: when two str9x banks are defined, then 'str9x.1' refers
|
* bank number: when two str9x banks are defined, then 'str9x.1' refers
|
||||||
* to the second.
|
* to the second.
|
||||||
*/
|
*/
|
||||||
struct flash_bank *get_flash_bank_by_name(const char *name);
|
int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result);
|
||||||
/**
|
/**
|
||||||
* Returns a flash bank by the specified flash_bank_s bank_number, @a num.
|
* Returns the flash bank specified by @a name, which matches the
|
||||||
* @param num The flash bank number.
|
* driver name and a suffix (option) specify the driver-specific
|
||||||
* @returns A struct flash_bank for flash bank @a num, or NULL
|
* 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_num(int num);
|
struct flash_bank *get_flash_bank_by_name_noprobe(const char *name);
|
||||||
|
/**
|
||||||
|
* Returns the flash bank like get_flash_bank_by_name(), without probing.
|
||||||
|
* @param num The flash bank number.
|
||||||
|
* @param bank returned bank if fn returns ERROR_OK
|
||||||
|
* @returns ERROR_OK if successful
|
||||||
|
*/
|
||||||
|
int get_flash_bank_by_num(int num, struct flash_bank **bank);
|
||||||
/**
|
/**
|
||||||
* Retreives @a bank from a command argument, reporting errors parsing
|
* Retreives @a bank from a command argument, reporting errors parsing
|
||||||
* the bank identifier or retreiving the specified bank. The bank
|
* the bank identifier or retreiving the specified bank. The bank
|
||||||
@@ -180,8 +206,9 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num);
|
|||||||
* Returns the flash bank located at a specified address.
|
* Returns the flash bank located at a specified address.
|
||||||
* @param target The target, presumed to contain one or more banks.
|
* @param target The target, presumed to contain one or more banks.
|
||||||
* @param addr An address that is within the range of the bank.
|
* @param addr An address that is within the range of the bank.
|
||||||
|
* @param check return ERROR_OK and result_bank NULL if the bank does not exist
|
||||||
* @returns The struct flash_bank located at @a addr, or NULL.
|
* @returns The struct flash_bank located at @a addr, or NULL.
|
||||||
*/
|
*/
|
||||||
struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr);
|
int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank);
|
||||||
|
|
||||||
#endif // FLASH_NOR_CORE_H
|
#endif // FLASH_NOR_CORE_H
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
|
||||||
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
|
||||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
|
||||||
|
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU General Public License as published by *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -53,7 +54,7 @@ struct flash_driver
|
|||||||
* Gives a human-readable name of this flash driver,
|
* Gives a human-readable name of this flash driver,
|
||||||
* This field is used to select and initialize the driver.
|
* This field is used to select and initialize the driver.
|
||||||
*/
|
*/
|
||||||
char *name;
|
const char *name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of driver-specific commands to register. When called
|
* An array of driver-specific commands to register. When called
|
||||||
@@ -75,11 +76,12 @@ struct flash_driver
|
|||||||
* CMD_ARGV[2] = baseaddress
|
* CMD_ARGV[2] = baseaddress
|
||||||
* CMD_ARGV[3] = lengthbytes
|
* CMD_ARGV[3] = lengthbytes
|
||||||
* CMD_ARGV[4] = chip_width_in bytes
|
* CMD_ARGV[4] = chip_width_in bytes
|
||||||
* CMD_ARGV[5] = bus_width_bytes
|
* CMD_ARGV[5] = bus_width_in_bytes
|
||||||
* CMD_ARGV[6] = driver-specific parameters
|
* CMD_ARGV[6] = driver-specific parameters
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
* For example, CMD_ARGV[4] = 16 bit flash, CMD_ARGV[5] = 32bit bus.
|
* For example, CMD_ARGV[4] = 2 (for 16 bit flash),
|
||||||
|
* CMD_ARGV[5] = 4 (for 32 bit bus).
|
||||||
*
|
*
|
||||||
* If extra arguments are provided (@a CMD_ARGC > 6), they will
|
* If extra arguments are provided (@a CMD_ARGC > 6), they will
|
||||||
* start in @a CMD_ARGV[6]. These can be used to implement
|
* start in @a CMD_ARGV[6]. These can be used to implement
|
||||||
@@ -103,9 +105,12 @@ struct flash_driver
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Bank/sector protection routine (target-specific).
|
* 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
|
* When called, the driver should enable/disable protection
|
||||||
* sectors.
|
* for MINIMUM the range covered by first..last sectors
|
||||||
|
* inclusive. Some chips have alignment requirements will
|
||||||
|
* cause the actual range to be protected / unprotected to
|
||||||
|
* be larger than the first..last range.
|
||||||
*
|
*
|
||||||
* @param bank The bank to protect or unprotect.
|
* @param bank The bank to protect or unprotect.
|
||||||
* @param set If non-zero, enable protection; if 0, disable it.
|
* @param set If non-zero, enable protection; if 0, disable it.
|
||||||
@@ -129,6 +134,20 @@ struct flash_driver
|
|||||||
int (*write)(struct flash_bank *bank,
|
int (*write)(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from 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 read.
|
||||||
|
* @param buffer The data bytes read.
|
||||||
|
* @param offset The offset into the chip to read.
|
||||||
|
* @param count The number of bytes to read.
|
||||||
|
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||||
|
*/
|
||||||
|
int (*read)(struct flash_bank *bank,
|
||||||
|
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probe to determine what kind of flash is present.
|
* Probe to determine what kind of flash is present.
|
||||||
* This is invoked by the "probe" script command.
|
* This is invoked by the "probe" script command.
|
||||||
|
|||||||
@@ -33,18 +33,23 @@ extern struct flash_driver aduc702x_flash;
|
|||||||
extern struct flash_driver stellaris_flash;
|
extern struct flash_driver stellaris_flash;
|
||||||
extern struct flash_driver str9xpec_flash;
|
extern struct flash_driver str9xpec_flash;
|
||||||
extern struct flash_driver stm32x_flash;
|
extern struct flash_driver stm32x_flash;
|
||||||
|
extern struct flash_driver stm32xf2xxx_flash;
|
||||||
extern struct flash_driver tms470_flash;
|
extern struct flash_driver tms470_flash;
|
||||||
extern struct flash_driver ecosflash_flash;
|
extern struct flash_driver ecosflash_flash;
|
||||||
extern struct flash_driver ocl_flash;
|
extern struct flash_driver ocl_flash;
|
||||||
extern struct flash_driver pic32mx_flash;
|
extern struct flash_driver pic32mx_flash;
|
||||||
extern struct flash_driver avr_flash;
|
extern struct flash_driver avr_flash;
|
||||||
extern struct flash_driver faux_flash;
|
extern struct flash_driver faux_flash;
|
||||||
|
extern struct flash_driver virtual_flash;
|
||||||
|
extern struct flash_driver stmsmi_flash;
|
||||||
|
extern struct flash_driver em357_flash;
|
||||||
|
extern struct flash_driver dsp5680xx_flash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of built-in flash drivers.
|
* The list of built-in flash drivers.
|
||||||
* @todo Make this dynamically extendable with loadable modules.
|
* @todo Make this dynamically extendable with loadable modules.
|
||||||
*/
|
*/
|
||||||
struct flash_driver *flash_drivers[] = {
|
static struct flash_driver *flash_drivers[] = {
|
||||||
&lpc2000_flash,
|
&lpc2000_flash,
|
||||||
&lpc288x_flash,
|
&lpc288x_flash,
|
||||||
&lpc2900_flash,
|
&lpc2900_flash,
|
||||||
@@ -57,12 +62,17 @@ struct flash_driver *flash_drivers[] = {
|
|||||||
&stellaris_flash,
|
&stellaris_flash,
|
||||||
&str9xpec_flash,
|
&str9xpec_flash,
|
||||||
&stm32x_flash,
|
&stm32x_flash,
|
||||||
|
&stm32xf2xxx_flash,
|
||||||
&tms470_flash,
|
&tms470_flash,
|
||||||
&ecosflash_flash,
|
&ecosflash_flash,
|
||||||
&ocl_flash,
|
&ocl_flash,
|
||||||
&pic32mx_flash,
|
&pic32mx_flash,
|
||||||
&avr_flash,
|
&avr_flash,
|
||||||
&faux_flash,
|
&faux_flash,
|
||||||
|
&virtual_flash,
|
||||||
|
&stmsmi_flash,
|
||||||
|
&em357_flash,
|
||||||
|
&dsp5680xx_flash,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
245
src/flash/nor/dsp5680xx_flash.c
Normal file
245
src/flash/nor/dsp5680xx_flash.c
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Rodrigo L. Rosa *
|
||||||
|
* rodrigorosa.LG@gmail.com *
|
||||||
|
* *
|
||||||
|
* Based on a file written by: *
|
||||||
|
* Kevin McGuire *
|
||||||
|
* Marcel Wijlaars *
|
||||||
|
* Michael Ashton *
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file dsp5680xx_flash.c
|
||||||
|
* @author Rodrigo L. Rosa <rodrigorosa.LG@gmail.com>
|
||||||
|
* @date Thu Jun 9 18:21:58 2011
|
||||||
|
*
|
||||||
|
* @brief This file implements the basic functions to run flashing commands
|
||||||
|
* from the TCL interface.
|
||||||
|
* It allows the user to flash the Freescale 5680xx DSP.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DSP5680XX_FLASH_H
|
||||||
|
#define DSP5680XX_FLASH_H
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <helper/binarybuffer.h>
|
||||||
|
#include <helper/time_support.h>
|
||||||
|
#include <target/algorithm.h>
|
||||||
|
#include <target/dsp5680xx.h>
|
||||||
|
|
||||||
|
struct dsp5680xx_flash_bank {
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dsp5680xx_build_sector_list(struct flash_bank *bank){
|
||||||
|
uint32_t offset = HFM_FLASH_BASE_ADDR;
|
||||||
|
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < bank->num_sectors; ++i){
|
||||||
|
bank->sectors[i].offset = i*HFM_SECTOR_SIZE;
|
||||||
|
bank->sectors[i].size = HFM_SECTOR_SIZE;
|
||||||
|
offset += bank->sectors[i].size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = -1;
|
||||||
|
}
|
||||||
|
LOG_USER("%s not tested yet.",__FUNCTION__);
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// flash bank dsp5680xx 0 0 0 0 <target#>
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command){
|
||||||
|
struct dsp5680xx_flash_bank *nbank;
|
||||||
|
|
||||||
|
nbank = malloc(sizeof(struct dsp5680xx_flash_bank));
|
||||||
|
|
||||||
|
bank->base = HFM_FLASH_BASE_ADDR;
|
||||||
|
bank->size = HFM_SIZE_BYTES; // top 4k not accessible
|
||||||
|
bank->driver_priv = nbank;
|
||||||
|
bank->num_sectors = HFM_SECTOR_COUNT;
|
||||||
|
dsp5680xx_build_sector_list(bank);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A memory mapped register (PROT) holds information regarding sector protection.
|
||||||
|
* Protection refers to undesired core access.
|
||||||
|
* The value in this register is loaded from flash upon reset.
|
||||||
|
*
|
||||||
|
* @param bank
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int dsp5680xx_flash_protect_check(struct flash_bank *bank){
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint16_t protected = 0;
|
||||||
|
retval = dsp5680xx_f_protect_check(bank->target,&protected);
|
||||||
|
if(retval != ERROR_OK){
|
||||||
|
for(int i = 0;i<HFM_SECTOR_COUNT;i++)
|
||||||
|
bank->sectors[i].is_protected = -1;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
for(int i = 0;i<HFM_SECTOR_COUNT/2;i++){
|
||||||
|
if(protected & 1){
|
||||||
|
bank->sectors[2*i].is_protected = 1;
|
||||||
|
bank->sectors[2*i+1].is_protected = 1;
|
||||||
|
}else{
|
||||||
|
bank->sectors[2*i].is_protected = 0;
|
||||||
|
bank->sectors[2*i+1].is_protected = 0;
|
||||||
|
}
|
||||||
|
protected = (protected >> 1);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protection funcionality is not implemented.
|
||||||
|
* The current implementation applies/removes security on the chip.
|
||||||
|
* The chip is effectively secured/unsecured after the first reset following the execution of this function.
|
||||||
|
*
|
||||||
|
* @param bank
|
||||||
|
* @param set Apply or remove security on the chip.
|
||||||
|
* @param first This parameter is ignored.
|
||||||
|
* @param last This parameter is ignored.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, int last){
|
||||||
|
// This applies security to flash module after next reset, it does not actually apply protection (protection refers to undesired access from the core)
|
||||||
|
int retval;
|
||||||
|
if(set)
|
||||||
|
retval = dsp5680xx_f_lock(bank->target);
|
||||||
|
else
|
||||||
|
retval = dsp5680xx_f_unlock(bank->target);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dsp5680xx use word addressing. The "/2" that appear in the following code are a workaround for the fact that OpenOCD uses byte addressing.
|
||||||
|
*
|
||||||
|
* @param bank
|
||||||
|
* @param buffer Data to write to flash.
|
||||||
|
* @param offset
|
||||||
|
* @param count In bytes (2 bytes per address).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count){
|
||||||
|
int retval;
|
||||||
|
if((offset + count/2)>bank->size){
|
||||||
|
LOG_ERROR("%s: Flash bank cannot fit data.",__FUNCTION__);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if(offset%2){
|
||||||
|
LOG_ERROR("%s: Writing to odd addresses not supported. This chip uses word addressing, Openocd only supports byte addressing. The workaround results in disabling writing to odd byte addresses.",__FUNCTION__);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset/2, count);
|
||||||
|
uint32_t addr_word;
|
||||||
|
for(addr_word = bank->base + offset/2;addr_word<count/2;addr_word+=(HFM_SECTOR_SIZE/2)){
|
||||||
|
if(retval == ERROR_OK)
|
||||||
|
bank->sectors[addr_word/(HFM_SECTOR_SIZE/2)].is_erased = 0;
|
||||||
|
else
|
||||||
|
bank->sectors[addr_word/(HFM_SECTOR_SIZE/2)].is_erased = -1;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dsp5680xx_probe(struct flash_bank *bank){
|
||||||
|
LOG_DEBUG("%s not implemented",__FUNCTION__);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf, int buf_size){
|
||||||
|
snprintf(buf, buf_size, "\ndsp5680xx flash driver info:\n - Currently only full erase/lock/unlock are implemented. \n - Call with bank==0 and sector 0 to 0.\n - Protect requires arp_init-reset to complete. \n - Before removing protection the master tap must be selected, and arp_init-reset is required to complete unlocking.");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flash module (FM) on the dsp5680xx supports both individual sector and mass erase of the flash memory.
|
||||||
|
* If this function is called with @first == @last == 0 or if @first is the first sector (#0) and @last is the last sector then the mass erase command is executed (much faster than erasing each sector individually).
|
||||||
|
*
|
||||||
|
* @param bank
|
||||||
|
* @param first
|
||||||
|
* @param last
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int dsp5680xx_flash_erase(struct flash_bank * bank, int first, int last){
|
||||||
|
int retval;
|
||||||
|
retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last);
|
||||||
|
if(retval == ERROR_OK)
|
||||||
|
for(int i = first;i<=last;i++)
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
else
|
||||||
|
// If an error occurred unknown status is set even though some sector could have been correctly erased.
|
||||||
|
for(int i = first;i<=last;i++)
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flash module (FM) on the dsp5680xx support a blank check function.
|
||||||
|
* This function executes the FM's blank check functionality on each and every sector.
|
||||||
|
*
|
||||||
|
* @param bank
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static int dsp5680xx_flash_erase_check(struct flash_bank * bank){
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
uint8_t erased = 0;
|
||||||
|
uint32_t i;
|
||||||
|
for(i=0;i<HFM_SECTOR_COUNT;i++){
|
||||||
|
if(bank->sectors[i].is_erased == -1){
|
||||||
|
retval = dsp5680xx_f_erase_check(bank->target,&erased,i);
|
||||||
|
if (retval != ERROR_OK){
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
}else{
|
||||||
|
if(erased)
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
else
|
||||||
|
bank->sectors[i].is_erased = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_driver dsp5680xx_flash = {
|
||||||
|
.name = "dsp5680xx_flash",
|
||||||
|
.flash_bank_command = dsp5680xx_flash_bank_command,
|
||||||
|
.erase = dsp5680xx_flash_erase,
|
||||||
|
.protect = dsp5680xx_flash_protect,
|
||||||
|
.write = dsp5680xx_flash_write,
|
||||||
|
//.read = default_flash_read,
|
||||||
|
.probe = dsp5680xx_probe,
|
||||||
|
.auto_probe = dsp5680xx_probe,
|
||||||
|
.erase_check = dsp5680xx_flash_erase_check,
|
||||||
|
.protect_check = dsp5680xx_flash_protect_check,
|
||||||
|
.info = dsp5680xx_flash_info
|
||||||
|
};
|
||||||
|
#endif // dsp5680xx_flash.h
|
||||||
@@ -173,7 +173,6 @@ static int loadDriver(struct ecosflash_flash_bank *info)
|
|||||||
for (i = 0; i < image.num_sections; i++)
|
for (i = 0; i < image.num_sections; i++)
|
||||||
{
|
{
|
||||||
void *buffer = malloc(image.sections[i].size);
|
void *buffer = malloc(image.sections[i].size);
|
||||||
int retval;
|
|
||||||
if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
|
if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
|
||||||
{
|
{
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -265,7 +264,7 @@ static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address,
|
|||||||
|
|
||||||
if (flashErr != 0x0)
|
if (flashErr != 0x0)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Flash erase failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
|
LOG_ERROR("Flash erase failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,7 +304,6 @@ static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32
|
|||||||
t = chunk;
|
t = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
int retval;
|
|
||||||
retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
|
retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
@@ -324,7 +322,7 @@ static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32
|
|||||||
|
|
||||||
if (flashErr != 0x0)
|
if (flashErr != 0x0)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Flash prog failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
|
LOG_ERROR("Flash prog failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,6 +434,7 @@ struct flash_driver ecosflash_flash = {
|
|||||||
.erase = ecosflash_erase,
|
.erase = ecosflash_erase,
|
||||||
.protect = ecosflash_protect,
|
.protect = ecosflash_protect,
|
||||||
.write = ecosflash_write,
|
.write = ecosflash_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = ecosflash_probe,
|
.probe = ecosflash_probe,
|
||||||
.auto_probe = ecosflash_probe,
|
.auto_probe = ecosflash_probe,
|
||||||
.erase_check = default_flash_blank_check,
|
.erase_check = default_flash_blank_check,
|
||||||
|
|||||||
974
src/flash/nor/em357.c
Normal file
974
src/flash/nor/em357.c
Normal file
@@ -0,0 +1,974 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2005 by Dominic Rath *
|
||||||
|
* Dominic.Rath@gmx.de *
|
||||||
|
* *
|
||||||
|
* Copyright (C) 2008 by Spencer Oliver *
|
||||||
|
* spen@spen-soft.co.uk *
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 by Erik Botö
|
||||||
|
* erik.boto@pelagicore.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "imp.h"
|
||||||
|
#include <helper/binarybuffer.h>
|
||||||
|
#include <target/algorithm.h>
|
||||||
|
#include <target/armv7m.h>
|
||||||
|
|
||||||
|
/* em357 register locations */
|
||||||
|
|
||||||
|
#define EM357_FLASH_ACR 0x40008000
|
||||||
|
#define EM357_FLASH_KEYR 0x40008004
|
||||||
|
#define EM357_FLASH_OPTKEYR 0x40008008
|
||||||
|
#define EM357_FLASH_SR 0x4000800C
|
||||||
|
#define EM357_FLASH_CR 0x40008010
|
||||||
|
#define EM357_FLASH_AR 0x40008014
|
||||||
|
#define EM357_FLASH_OBR 0x4000801C
|
||||||
|
#define EM357_FLASH_WRPR 0x40008020
|
||||||
|
|
||||||
|
#define EM357_FPEC_CLK 0x4000402c
|
||||||
|
/* option byte location */
|
||||||
|
|
||||||
|
#define EM357_OB_RDP 0x08040800
|
||||||
|
#define EM357_OB_WRP0 0x08040808
|
||||||
|
#define EM357_OB_WRP1 0x0804080A
|
||||||
|
#define EM357_OB_WRP2 0x0804080C
|
||||||
|
|
||||||
|
/* FLASH_CR register bits */
|
||||||
|
|
||||||
|
#define FLASH_PG (1 << 0)
|
||||||
|
#define FLASH_PER (1 << 1)
|
||||||
|
#define FLASH_MER (1 << 2)
|
||||||
|
#define FLASH_OPTPG (1 << 4)
|
||||||
|
#define FLASH_OPTER (1 << 5)
|
||||||
|
#define FLASH_STRT (1 << 6)
|
||||||
|
#define FLASH_LOCK (1 << 7)
|
||||||
|
#define FLASH_OPTWRE (1 << 9)
|
||||||
|
|
||||||
|
/* FLASH_SR register bits */
|
||||||
|
|
||||||
|
#define FLASH_BSY (1 << 0)
|
||||||
|
#define FLASH_PGERR (1 << 2)
|
||||||
|
#define FLASH_WRPRTERR (1 << 4)
|
||||||
|
#define FLASH_EOP (1 << 5)
|
||||||
|
|
||||||
|
/* EM357_FLASH_OBR bit definitions (reading) */
|
||||||
|
|
||||||
|
#define OPT_ERROR 0
|
||||||
|
#define OPT_READOUT 1
|
||||||
|
|
||||||
|
/* register unlock keys */
|
||||||
|
|
||||||
|
#define KEY1 0x45670123
|
||||||
|
#define KEY2 0xCDEF89AB
|
||||||
|
|
||||||
|
struct em357_options
|
||||||
|
{
|
||||||
|
uint16_t RDP;
|
||||||
|
uint16_t user_options;
|
||||||
|
uint16_t protection[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct em357_flash_bank
|
||||||
|
{
|
||||||
|
struct em357_options option_bytes;
|
||||||
|
struct working_area *write_algorithm;
|
||||||
|
int ppage_size;
|
||||||
|
int probed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int em357_mass_erase(struct flash_bank *bank);
|
||||||
|
|
||||||
|
/* flash bank em357 <base> <size> 0 0 <target#>
|
||||||
|
*/
|
||||||
|
FLASH_BANK_COMMAND_HANDLER(em357_flash_bank_command)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 6)
|
||||||
|
{
|
||||||
|
LOG_WARNING("incomplete flash_bank em357 configuration");
|
||||||
|
return ERROR_FLASH_BANK_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
em357_info = malloc(sizeof(struct em357_flash_bank));
|
||||||
|
bank->driver_priv = em357_info;
|
||||||
|
|
||||||
|
em357_info->write_algorithm = NULL;
|
||||||
|
em357_info->probed = 0;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int em357_get_flash_status(struct flash_bank *bank, uint32_t *status)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
return target_read_u32(target, EM357_FLASH_SR, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_wait_status_busy(struct flash_bank *bank, int timeout)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint32_t status;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
/* wait for busy to clear */
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
retval = em357_get_flash_status(bank, &status);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
||||||
|
if ((status & FLASH_BSY) == 0)
|
||||||
|
break;
|
||||||
|
if (timeout-- <= 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("timed out waiting for flash");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
alive_sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & FLASH_WRPRTERR)
|
||||||
|
{
|
||||||
|
LOG_ERROR("em357 device protected");
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & FLASH_PGERR)
|
||||||
|
{
|
||||||
|
LOG_ERROR("em357 device programming failed");
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear but report errors */
|
||||||
|
if (status & (FLASH_WRPRTERR | FLASH_PGERR))
|
||||||
|
{
|
||||||
|
/* If this operation fails, we ignore it and report the original
|
||||||
|
* retval
|
||||||
|
*/
|
||||||
|
target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_read_options(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
uint32_t optiondata;
|
||||||
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
/* read current option bytes */
|
||||||
|
int retval = target_read_u32(target, EM357_FLASH_OBR, &optiondata);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
em357_info->option_bytes.user_options = (uint16_t)0xFFFC | ((optiondata >> 2) & 0x03);
|
||||||
|
em357_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
|
||||||
|
|
||||||
|
if (optiondata & (1 << OPT_READOUT))
|
||||||
|
LOG_INFO("Device Security Bit Set");
|
||||||
|
|
||||||
|
/* each bit refers to a 4bank protection */
|
||||||
|
retval = target_read_u32(target, EM357_FLASH_WRPR, &optiondata);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
em357_info->option_bytes.protection[0] = (uint16_t)optiondata;
|
||||||
|
em357_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8);
|
||||||
|
em357_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_erase_options(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
/* read current options */
|
||||||
|
em357_read_options(bank);
|
||||||
|
|
||||||
|
/* unlock flash registers */
|
||||||
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* unlock option flash registers */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* erase option bytes */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* clear readout protection and complementary option bytes
|
||||||
|
* this will also force a device unlock if set */
|
||||||
|
em357_info->option_bytes.RDP = 0x5AA5;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_write_options(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
/* unlock flash registers */
|
||||||
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* unlock option flash registers */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* program option bytes */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* write protection byte 1 */
|
||||||
|
retval = target_write_u16(target, EM357_OB_WRP0, em357_info->option_bytes.protection[0]);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* write protection byte 2 */
|
||||||
|
retval = target_write_u16(target, EM357_OB_WRP1, em357_info->option_bytes.protection[1]);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* write protection byte 3 */
|
||||||
|
retval = target_write_u16(target, EM357_OB_WRP2, em357_info->option_bytes.protection[2]);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* write readout protection bit */
|
||||||
|
retval = target_write_u16(target, EM357_OB_RDP, em357_info->option_bytes.RDP);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 10);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_protect_check(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
struct em357_flash_bank *em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
uint32_t protection;
|
||||||
|
int i, s;
|
||||||
|
int num_bits;
|
||||||
|
int set;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* each bit refers to a 4bank protection (bit 0-23) */
|
||||||
|
int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* each protection bit is for 4 * 2K pages */
|
||||||
|
num_bits = (bank->num_sectors / em357_info->ppage_size);
|
||||||
|
|
||||||
|
for (i = 0; i < num_bits; i++)
|
||||||
|
{
|
||||||
|
set = 1;
|
||||||
|
if (protection & (1 << i))
|
||||||
|
set = 0;
|
||||||
|
|
||||||
|
for (s = 0; s < em357_info->ppage_size; s++)
|
||||||
|
bank->sectors[(i * em357_info->ppage_size) + s].is_protected = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_erase(struct flash_bank *bank, int first, int last)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first == 0) && (last == (bank->num_sectors - 1)))
|
||||||
|
{
|
||||||
|
return em357_mass_erase(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unlock flash registers */
|
||||||
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
{
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_AR,
|
||||||
|
bank->base + bank->sectors[i].offset);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER | FLASH_STRT);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 100);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_protect(struct flash_bank *bank, int set, int first, int last)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||||
|
int i, reg, bit;
|
||||||
|
int status;
|
||||||
|
uint32_t protection;
|
||||||
|
|
||||||
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first % em357_info->ppage_size) != 0)
|
||||||
|
{
|
||||||
|
LOG_WARNING("aligned start protect sector to a %d sector boundary",
|
||||||
|
em357_info->ppage_size);
|
||||||
|
first = first - (first % em357_info->ppage_size);
|
||||||
|
}
|
||||||
|
if (((last + 1) % em357_info->ppage_size) != 0)
|
||||||
|
{
|
||||||
|
LOG_WARNING("aligned end protect sector to a %d sector boundary",
|
||||||
|
em357_info->ppage_size);
|
||||||
|
last++;
|
||||||
|
last = last - (last % em357_info->ppage_size);
|
||||||
|
last--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* each bit refers to a 4bank protection */
|
||||||
|
int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
prot_reg[0] = (uint16_t)protection;
|
||||||
|
prot_reg[1] = (uint16_t)(protection >> 8);
|
||||||
|
prot_reg[2] = (uint16_t)(protection >> 16);
|
||||||
|
|
||||||
|
for (i = first; i <= last; i++)
|
||||||
|
{
|
||||||
|
reg = (i / em357_info->ppage_size) / 8;
|
||||||
|
bit = (i / em357_info->ppage_size) - (reg * 8);
|
||||||
|
|
||||||
|
LOG_WARNING("reg, bit: %d, %d", reg, bit);
|
||||||
|
if (set)
|
||||||
|
prot_reg[reg] &= ~(1 << bit);
|
||||||
|
else
|
||||||
|
prot_reg[reg] |= (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status = em357_erase_options(bank)) != ERROR_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
em357_info->option_bytes.protection[0] = prot_reg[0];
|
||||||
|
em357_info->option_bytes.protection[1] = prot_reg[1];
|
||||||
|
em357_info->option_bytes.protection[2] = prot_reg[2];
|
||||||
|
|
||||||
|
return em357_write_options(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_write_block(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint32_t buffer_size = 16384;
|
||||||
|
struct working_area *source;
|
||||||
|
uint32_t address = bank->base + offset;
|
||||||
|
struct reg_param reg_params[4];
|
||||||
|
struct armv7m_algorithm armv7m_info;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
/* see contib/loaders/flash/stm32x.s for src, the same is used here except for
|
||||||
|
* a modified *_FLASH_BASE */
|
||||||
|
|
||||||
|
static const uint8_t em357_flash_write_code[] = {
|
||||||
|
/* #define EM357_FLASH_CR_OFFSET 0x10 */
|
||||||
|
/* #define EM357_FLASH_SR_OFFSET 0x0C */
|
||||||
|
/* write: */
|
||||||
|
0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */
|
||||||
|
0x1c, 0x44, /* add r4, r3 */
|
||||||
|
/* write_half_word: */
|
||||||
|
0x01, 0x23, /* movs r3, #0x01 */
|
||||||
|
0x23, 0x61, /* str r3, [r4, #EM357_FLASH_CR_OFFSET] */
|
||||||
|
0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
|
||||||
|
0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
|
||||||
|
/* busy: */
|
||||||
|
0xe3, 0x68, /* ldr r3, [r4, #EM357_FLASH_SR_OFFSET] */
|
||||||
|
0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
|
||||||
|
0xfb, 0xd0, /* beq busy */
|
||||||
|
0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
|
||||||
|
0x01, 0xd1, /* bne exit */
|
||||||
|
0x01, 0x3a, /* subs r2, r2, #0x01 */
|
||||||
|
0xf0, 0xd1, /* bne write_half_word */
|
||||||
|
/* exit: */
|
||||||
|
0x00, 0xbe, /* bkpt #0x00 */
|
||||||
|
0x00, 0x80, 0x00, 0x40, /* EM357_FLASH_BASE: .word 0x40008000 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* flash write code */
|
||||||
|
if (target_alloc_working_area(target, sizeof(em357_flash_write_code),
|
||||||
|
&em357_info->write_algorithm) != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_WARNING("no working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((retval = target_write_buffer(target, em357_info->write_algorithm->address,
|
||||||
|
sizeof(em357_flash_write_code),
|
||||||
|
(uint8_t*)em357_flash_write_code)) != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* memory buffer */
|
||||||
|
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
|
||||||
|
{
|
||||||
|
buffer_size /= 2;
|
||||||
|
if (buffer_size <= 256)
|
||||||
|
{
|
||||||
|
/* if we already allocated the writing code, but failed to get a
|
||||||
|
* buffer, free the algorithm */
|
||||||
|
if (em357_info->write_algorithm)
|
||||||
|
target_free_working_area(target, em357_info->write_algorithm);
|
||||||
|
|
||||||
|
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
||||||
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
|
armv7m_info.core_mode = ARMV7M_MODE_ANY;
|
||||||
|
|
||||||
|
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||||
|
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||||
|
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||||
|
init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT);
|
||||||
|
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
uint32_t thisrun_count = (count > (buffer_size / 2)) ?
|
||||||
|
(buffer_size / 2) : count;
|
||||||
|
|
||||||
|
if ((retval = target_write_buffer(target, source->address,
|
||||||
|
thisrun_count * 2, buffer)) != ERROR_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||||
|
buf_set_u32(reg_params[1].value, 0, 32, address);
|
||||||
|
buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
|
||||||
|
buf_set_u32(reg_params[3].value, 0, 32, 0);
|
||||||
|
|
||||||
|
if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||||
|
em357_info->write_algorithm->address,
|
||||||
|
0,
|
||||||
|
10000, &armv7m_info)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
LOG_ERROR("error executing em357 flash write algorithm");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
|
||||||
|
{
|
||||||
|
LOG_ERROR("flash memory not erased before writing");
|
||||||
|
/* Clear but report errors */
|
||||||
|
target_write_u32(target, EM357_FLASH_SR, FLASH_PGERR);
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
|
||||||
|
{
|
||||||
|
LOG_ERROR("flash memory write protected");
|
||||||
|
/* Clear but report errors */
|
||||||
|
target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR);
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += thisrun_count * 2;
|
||||||
|
address += thisrun_count * 2;
|
||||||
|
count -= thisrun_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_free_working_area(target, source);
|
||||||
|
target_free_working_area(target, em357_info->write_algorithm);
|
||||||
|
|
||||||
|
destroy_reg_param(®_params[0]);
|
||||||
|
destroy_reg_param(®_params[1]);
|
||||||
|
destroy_reg_param(®_params[2]);
|
||||||
|
destroy_reg_param(®_params[3]);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_write(struct flash_bank *bank, uint8_t *buffer,
|
||||||
|
uint32_t offset, uint32_t count)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
uint32_t words_remaining = (count / 2);
|
||||||
|
uint32_t bytes_remaining = (count & 0x00000001);
|
||||||
|
uint32_t address = bank->base + offset;
|
||||||
|
uint32_t bytes_written = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (bank->target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset & 0x1)
|
||||||
|
{
|
||||||
|
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unlock flash registers */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* multiple half words (2-byte) to be programmed? */
|
||||||
|
if (words_remaining > 0)
|
||||||
|
{
|
||||||
|
/* try using a block write */
|
||||||
|
if ((retval = em357_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
|
||||||
|
{
|
||||||
|
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
||||||
|
{
|
||||||
|
/* if block write failed (no sufficient working area),
|
||||||
|
* we use normal (slow) single dword accesses */
|
||||||
|
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer += words_remaining * 2;
|
||||||
|
address += words_remaining * 2;
|
||||||
|
words_remaining = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
while (words_remaining > 0)
|
||||||
|
{
|
||||||
|
uint16_t value;
|
||||||
|
memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u16(target, address, value);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 5);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
bytes_written += 2;
|
||||||
|
words_remaining--;
|
||||||
|
address += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_remaining)
|
||||||
|
{
|
||||||
|
uint16_t value = 0xffff;
|
||||||
|
memcpy(&value, buffer + bytes_written, bytes_remaining);
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u16(target, address, value);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 5);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
struct em357_flash_bank *em357_info = bank->driver_priv;
|
||||||
|
int i;
|
||||||
|
uint16_t num_pages;
|
||||||
|
int page_size;
|
||||||
|
uint32_t base_address = 0x08000000;
|
||||||
|
|
||||||
|
em357_info->probed = 0;
|
||||||
|
|
||||||
|
/* Enable FPEC CLK */
|
||||||
|
int retval = target_write_u32(target, EM357_FPEC_CLK, 0x00000001);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
page_size = 2048;
|
||||||
|
em357_info->ppage_size = 4;
|
||||||
|
num_pages = 96;
|
||||||
|
|
||||||
|
LOG_INFO("flash size = %dkbytes", num_pages*page_size/1024);
|
||||||
|
|
||||||
|
if (bank->sectors)
|
||||||
|
{
|
||||||
|
free(bank->sectors);
|
||||||
|
bank->sectors = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bank->base = base_address;
|
||||||
|
bank->size = (num_pages * page_size);
|
||||||
|
bank->num_sectors = num_pages;
|
||||||
|
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||||
|
|
||||||
|
for (i = 0; i < num_pages; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].offset = i * page_size;
|
||||||
|
bank->sectors[i].size = page_size;
|
||||||
|
bank->sectors[i].is_erased = -1;
|
||||||
|
bank->sectors[i].is_protected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
em357_info->probed = 1;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_auto_probe(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct em357_flash_bank *em357_info = bank->driver_priv;
|
||||||
|
if (em357_info->probed)
|
||||||
|
return ERROR_OK;
|
||||||
|
return em357_probe(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int get_em357_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
int printed;
|
||||||
|
printed = snprintf(buf, buf_size, "em357\n");
|
||||||
|
buf += printed;
|
||||||
|
buf_size -= printed;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(em357_handle_lock_command)
|
||||||
|
{
|
||||||
|
struct target *target = NULL;
|
||||||
|
struct em357_flash_bank *em357_info = NULL;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 1)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 lock <bank>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
em357_info = bank->driver_priv;
|
||||||
|
|
||||||
|
target = bank->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (em357_erase_options(bank) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 failed to erase options");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set readout protection */
|
||||||
|
em357_info->option_bytes.RDP = 0;
|
||||||
|
|
||||||
|
if (em357_write_options(bank) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 failed to lock device");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(CMD_CTX, "em357 locked");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(em357_handle_unlock_command)
|
||||||
|
{
|
||||||
|
struct target *target = NULL;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 1)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 unlock <bank>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
target = bank->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (em357_erase_options(bank) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 failed to unlock device");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (em357_write_options(bank) != ERROR_OK)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 failed to lock device");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(CMD_CTX, "em357 unlocked.\n"
|
||||||
|
"INFO: a reset or power cycle is required "
|
||||||
|
"for the new settings to take effect.");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int em357_mass_erase(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unlock option flash registers */
|
||||||
|
int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
/* mass erase flash memory */
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER | FLASH_STRT);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_wait_status_busy(bank, 100);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(em357_handle_mass_erase_command)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (CMD_ARGC < 1)
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 mass_erase <bank>");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_bank *bank;
|
||||||
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||||
|
if (ERROR_OK != retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = em357_mass_erase(bank);
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
{
|
||||||
|
/* set all sectors as erased */
|
||||||
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
|
{
|
||||||
|
bank->sectors[i].is_erased = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(CMD_CTX, "em357 mass erase complete");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_print(CMD_CTX, "em357 mass erase failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct command_registration em357_exec_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "lock",
|
||||||
|
.handler = em357_handle_lock_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "bank_id",
|
||||||
|
.help = "Lock entire flash device.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "unlock",
|
||||||
|
.handler = em357_handle_unlock_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "bank_id",
|
||||||
|
.help = "Unlock entire protected flash device.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mass_erase",
|
||||||
|
.handler = em357_handle_mass_erase_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "bank_id",
|
||||||
|
.help = "Erase entire flash device.",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration em357_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "em357",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "em357 flash command group",
|
||||||
|
.chain = em357_exec_command_handlers,
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flash_driver em357_flash = {
|
||||||
|
.name = "em357",
|
||||||
|
.commands = em357_command_handlers,
|
||||||
|
.flash_bank_command = em357_flash_bank_command,
|
||||||
|
.erase = em357_erase,
|
||||||
|
.protect = em357_protect,
|
||||||
|
.write = em357_write,
|
||||||
|
.read = default_flash_read,
|
||||||
|
.probe = em357_probe,
|
||||||
|
.auto_probe = em357_auto_probe,
|
||||||
|
.erase_check = default_flash_mem_blank_check,
|
||||||
|
.protect_check = em357_protect_check,
|
||||||
|
.info = get_em357_info,
|
||||||
|
};
|
||||||
@@ -141,6 +141,7 @@ struct flash_driver faux_flash = {
|
|||||||
.erase = faux_erase,
|
.erase = faux_erase,
|
||||||
.protect = faux_protect,
|
.protect = faux_protect,
|
||||||
.write = faux_write,
|
.write = faux_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = faux_probe,
|
.probe = faux_probe,
|
||||||
.auto_probe = faux_probe,
|
.auto_probe = faux_probe,
|
||||||
.erase_check = default_flash_blank_check,
|
.erase_check = default_flash_blank_check,
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ 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_protect(struct flash_bank *bank, int set, int first, int last);
|
||||||
int flash_driver_write(struct flash_bank *bank,
|
int flash_driver_write(struct flash_bank *bank,
|
||||||
uint8_t *buffer, uint32_t offset, uint32_t count);
|
uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||||
|
int flash_driver_read(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 */
|
/* write (optional verify) an image to flash memory of the given target */
|
||||||
int flash_write_unlock(struct target *target, struct image *image,
|
int flash_write_unlock(struct target *target, struct image *image,
|
||||||
|
|||||||
@@ -26,14 +26,21 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "lpc2000.h"
|
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
#include <target/algorithm.h>
|
#include <target/algorithm.h>
|
||||||
#include <target/arm_opcodes.h>
|
#include <target/arm_opcodes.h>
|
||||||
#include <target/armv7m.h>
|
#include <target/armv7m.h>
|
||||||
|
|
||||||
|
|
||||||
/* flash programming support for NXP LPC17xx and LPC2xxx devices
|
/**
|
||||||
|
* @file
|
||||||
|
* flash programming support for NXP LPC17xx and LPC2xxx devices.
|
||||||
|
*
|
||||||
|
* @todo Provide a way to update CCLK after declaring the flash bank.
|
||||||
|
* The value which is correct after chip reset will rarely still work
|
||||||
|
* right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
|
||||||
|
*/
|
||||||
|
/*
|
||||||
* currently supported devices:
|
* currently supported devices:
|
||||||
* variant 1 (lpc2000_v1):
|
* variant 1 (lpc2000_v1):
|
||||||
* - 2104 | 5 | 6
|
* - 2104 | 5 | 6
|
||||||
@@ -55,6 +62,51 @@
|
|||||||
* - 176x (tested with LPC1768)
|
* - 176x (tested with LPC1768)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
lpc2000_v1,
|
||||||
|
lpc2000_v2,
|
||||||
|
lpc1700
|
||||||
|
} lpc2000_variant;
|
||||||
|
|
||||||
|
struct lpc2000_flash_bank
|
||||||
|
{
|
||||||
|
lpc2000_variant variant;
|
||||||
|
struct working_area *iap_working_area;
|
||||||
|
uint32_t cclk;
|
||||||
|
int cmd51_dst_boundary;
|
||||||
|
int cmd51_can_256b;
|
||||||
|
int cmd51_can_8192b;
|
||||||
|
int calc_checksum;
|
||||||
|
uint32_t cmd51_max_buffer;
|
||||||
|
int checksum_vector;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum lpc2000_status_codes
|
||||||
|
{
|
||||||
|
LPC2000_CMD_SUCCESS = 0,
|
||||||
|
LPC2000_INVALID_COMMAND = 1,
|
||||||
|
LPC2000_SRC_ADDR_ERROR = 2,
|
||||||
|
LPC2000_DST_ADDR_ERROR = 3,
|
||||||
|
LPC2000_SRC_ADDR_NOT_MAPPED = 4,
|
||||||
|
LPC2000_DST_ADDR_NOT_MAPPED = 5,
|
||||||
|
LPC2000_COUNT_ERROR = 6,
|
||||||
|
LPC2000_INVALID_SECTOR = 7,
|
||||||
|
LPC2000_SECTOR_NOT_BLANK = 8,
|
||||||
|
LPC2000_SECTOR_NOT_PREPARED = 9,
|
||||||
|
LPC2000_COMPARE_ERROR = 10,
|
||||||
|
LPC2000_BUSY = 11,
|
||||||
|
LPC2000_PARAM_ERROR = 12,
|
||||||
|
LPC2000_ADDR_ERROR = 13,
|
||||||
|
LPC2000_ADDR_NOT_MAPPED = 14,
|
||||||
|
LPC2000_CMD_NOT_LOCKED = 15,
|
||||||
|
LPC2000_INVALID_CODE = 16,
|
||||||
|
LPC2000_INVALID_BAUD_RATE = 17,
|
||||||
|
LPC2000_INVALID_STOP_BIT = 18,
|
||||||
|
LPC2000_CRP_ENABLED = 19
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
static int lpc2000_build_sector_list(struct flash_bank *bank)
|
static int lpc2000_build_sector_list(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||||
@@ -144,10 +196,13 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
case 256 * 1024:
|
case 256 * 1024:
|
||||||
bank->num_sectors = 15;
|
bank->num_sectors = 15;
|
||||||
break;
|
break;
|
||||||
case 512 * 1024:
|
|
||||||
case 500 * 1024:
|
case 500 * 1024:
|
||||||
bank->num_sectors = 27;
|
bank->num_sectors = 27;
|
||||||
break;
|
break;
|
||||||
|
case 512 * 1024:
|
||||||
|
case 504 * 1024:
|
||||||
|
bank->num_sectors = 28;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -158,7 +213,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
|
|
||||||
for (i = 0; i < bank->num_sectors; i++)
|
for (i = 0; i < bank->num_sectors; i++)
|
||||||
{
|
{
|
||||||
if ((i >= 0) && (i < 8))
|
if (i < 8)
|
||||||
{
|
{
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 4 * 1024;
|
bank->sectors[i].size = 4 * 1024;
|
||||||
@@ -166,7 +221,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
if ((i >= 8) && (i < 22))
|
else if (i < 22)
|
||||||
{
|
{
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 32 * 1024;
|
bank->sectors[i].size = 32 * 1024;
|
||||||
@@ -174,7 +229,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
|
|||||||
bank->sectors[i].is_erased = -1;
|
bank->sectors[i].is_erased = -1;
|
||||||
bank->sectors[i].is_protected = 1;
|
bank->sectors[i].is_protected = 1;
|
||||||
}
|
}
|
||||||
if ((i >= 22) && (i < 27))
|
else if (i < 28)
|
||||||
{
|
{
|
||||||
bank->sectors[i].offset = offset;
|
bank->sectors[i].offset = offset;
|
||||||
bank->sectors[i].size = 4 * 1024;
|
bank->sectors[i].size = 4 * 1024;
|
||||||
@@ -267,7 +322,7 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
target_buffer_set_u32(target, jump_gate,
|
target_buffer_set_u32(target, jump_gate,
|
||||||
ARMV4_5_T_BX(12));
|
ARMV4_5_T_BX(12));
|
||||||
target_buffer_set_u32(target, jump_gate + 4,
|
target_buffer_set_u32(target, jump_gate + 4,
|
||||||
ARMV4_5_T_B(0xfffffe));
|
ARMV5_T_BKPT(0));
|
||||||
break;
|
break;
|
||||||
case lpc2000_v1:
|
case lpc2000_v1:
|
||||||
case lpc2000_v2:
|
case lpc2000_v2:
|
||||||
@@ -338,7 +393,7 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
|
|||||||
init_reg_param(®_params[4], "lr", 32, PARAM_OUT);
|
init_reg_param(®_params[4], "lr", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
|
buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
|
||||||
|
|
||||||
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
|
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
|
||||||
break;
|
break;
|
||||||
case lpc2000_v1:
|
case lpc2000_v1:
|
||||||
case lpc2000_v2:
|
case lpc2000_v2:
|
||||||
@@ -586,7 +641,6 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
|
|||||||
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
||||||
{
|
{
|
||||||
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
||||||
int i;
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||||
@@ -732,7 +786,7 @@ static int lpc2000_protect_check(struct flash_bank *bank)
|
|||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
|
static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||||
{
|
{
|
||||||
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
|
||||||
|
|
||||||
@@ -806,9 +860,10 @@ struct flash_driver lpc2000_flash = {
|
|||||||
.erase = lpc2000_erase,
|
.erase = lpc2000_erase,
|
||||||
.protect = lpc2000_protect,
|
.protect = lpc2000_protect,
|
||||||
.write = lpc2000_write,
|
.write = lpc2000_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = lpc2000_probe,
|
.probe = lpc2000_probe,
|
||||||
.auto_probe = lpc2000_probe,
|
.auto_probe = lpc2000_probe,
|
||||||
.erase_check = lpc2000_erase_check,
|
.erase_check = lpc2000_erase_check,
|
||||||
.protect_check = lpc2000_protect_check,
|
.protect_check = lpc2000_protect_check,
|
||||||
.info = lpc2000_info,
|
.info = get_lpc2000_info,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "lpc288x.h"
|
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -85,6 +84,19 @@
|
|||||||
/* F_CLK_TIME */
|
/* F_CLK_TIME */
|
||||||
#define FCT_CLK_DIV_MASK 0x0FFF
|
#define FCT_CLK_DIV_MASK 0x0FFF
|
||||||
|
|
||||||
|
struct lpc288x_flash_bank
|
||||||
|
{
|
||||||
|
uint32_t working_area;
|
||||||
|
uint32_t working_area_size;
|
||||||
|
|
||||||
|
/* chip id register */
|
||||||
|
uint32_t cidr;
|
||||||
|
const char * target_name;
|
||||||
|
uint32_t cclk;
|
||||||
|
|
||||||
|
uint32_t sector_size_break;
|
||||||
|
};
|
||||||
|
|
||||||
static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
|
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_load_timer(int erase, struct target *target);
|
||||||
static void lpc288x_set_flash_clk(struct flash_bank *bank);
|
static void lpc288x_set_flash_clk(struct flash_bank *bank);
|
||||||
@@ -478,6 +490,7 @@ struct flash_driver lpc288x_flash = {
|
|||||||
.erase = lpc288x_erase,
|
.erase = lpc288x_erase,
|
||||||
.protect = lpc288x_protect,
|
.protect = lpc288x_protect,
|
||||||
.write = lpc288x_write,
|
.write = lpc288x_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = lpc288x_probe,
|
.probe = lpc288x_probe,
|
||||||
.auto_probe = lpc288x_probe,
|
.auto_probe = lpc288x_probe,
|
||||||
.erase_check = lpc288x_erase_check,
|
.erase_check = lpc288x_erase_check,
|
||||||
|
|||||||
@@ -131,6 +131,11 @@
|
|||||||
*/
|
*/
|
||||||
struct lpc2900_flash_bank
|
struct lpc2900_flash_bank
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* This flag is set when the device has been successfully probed.
|
||||||
|
*/
|
||||||
|
bool is_probed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the value read from CHIPID register.
|
* Holds the value read from CHIPID register.
|
||||||
* The driver will not load if the chipid doesn't match the expected
|
* The driver will not load if the chipid doesn't match the expected
|
||||||
@@ -179,7 +184,7 @@ static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
|
|||||||
uint32_t addr_from, uint32_t addr_to,
|
uint32_t addr_from, uint32_t addr_to,
|
||||||
uint32_t (*signature)[4] );
|
uint32_t (*signature)[4] );
|
||||||
static uint32_t lpc2900_address2sector(struct flash_bank *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 );
|
static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var);
|
||||||
|
|
||||||
|
|
||||||
/*********************** Helper functions **************************/
|
/*********************** Helper functions **************************/
|
||||||
@@ -255,7 +260,7 @@ static uint32_t lpc2900_is_ready( struct flash_bank *bank )
|
|||||||
{
|
{
|
||||||
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
|
||||||
|
|
||||||
if( lpc2900_info->chipid != EXPECTED_CHIPID )
|
if( !lpc2900_info->is_probed )
|
||||||
{
|
{
|
||||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||||
}
|
}
|
||||||
@@ -306,39 +311,39 @@ static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
|
|||||||
* a protected sector!
|
* a protected sector!
|
||||||
*/
|
*/
|
||||||
int sector;
|
int sector;
|
||||||
int index;
|
int index_t;
|
||||||
for( sector = 0; sector < bank->num_sectors; sector++ )
|
for( sector = 0; sector < bank->num_sectors; sector++ )
|
||||||
{
|
{
|
||||||
/* Convert logical sector number to physical sector number */
|
/* Convert logical sector number to physical sector number */
|
||||||
if( sector <= 4 )
|
if( sector <= 4 )
|
||||||
{
|
{
|
||||||
index = sector + 11;
|
index_t = sector + 11;
|
||||||
}
|
}
|
||||||
else if( sector <= 7 )
|
else if( sector <= 7 )
|
||||||
{
|
{
|
||||||
index = sector + 27;
|
index_t = sector + 27;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
index = sector - 8;
|
index_t = sector - 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bank->sectors[sector].is_protected = -1;
|
bank->sectors[sector].is_protected = -1;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(iss_secured_field[index][0] == 0x00000000) &&
|
(iss_secured_field[index_t][0] == 0x00000000) &&
|
||||||
(iss_secured_field[index][1] == 0x00000000) &&
|
(iss_secured_field[index_t][1] == 0x00000000) &&
|
||||||
(iss_secured_field[index][2] == 0x00000000) &&
|
(iss_secured_field[index_t][2] == 0x00000000) &&
|
||||||
(iss_secured_field[index][3] == 0x00000000) )
|
(iss_secured_field[index_t][3] == 0x00000000) )
|
||||||
{
|
{
|
||||||
bank->sectors[sector].is_protected = 1;
|
bank->sectors[sector].is_protected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(iss_secured_field[index][0] == 0xFFFFFFFF) &&
|
(iss_secured_field[index_t][0] == 0xFFFFFFFF) &&
|
||||||
(iss_secured_field[index][1] == 0xFFFFFFFF) &&
|
(iss_secured_field[index_t][1] == 0xFFFFFFFF) &&
|
||||||
(iss_secured_field[index][2] == 0xFFFFFFFF) &&
|
(iss_secured_field[index_t][2] == 0xFFFFFFFF) &&
|
||||||
(iss_secured_field[index][3] == 0xFFFFFFFF) )
|
(iss_secured_field[index_t][3] == 0xFFFFFFFF) )
|
||||||
{
|
{
|
||||||
bank->sectors[sector].is_protected = 0;
|
bank->sectors[sector].is_protected = 0;
|
||||||
}
|
}
|
||||||
@@ -507,16 +512,14 @@ static int lpc2900_write_index_page( struct flash_bank *bank,
|
|||||||
* @param clock System clock in Hz
|
* @param clock System clock in Hz
|
||||||
* @param time Program/erase time in µs
|
* @param time Program/erase time in µs
|
||||||
*/
|
*/
|
||||||
static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time )
|
static uint32_t lpc2900_calc_tr( uint32_t clock_var, uint32_t time_var )
|
||||||
{
|
{
|
||||||
/* ((time[µs]/1e6) * f[Hz]) + 511
|
/* ((time[µs]/1e6) * f[Hz]) + 511
|
||||||
* FPTR.TR = -------------------------------
|
* FPTR.TR = -------------------------------
|
||||||
* 512
|
* 512
|
||||||
*
|
|
||||||
* The result is the
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t tr_val = (uint32_t)((((time / 1e6) * clock) + 511.0) / 512.0);
|
uint32_t tr_val = (uint32_t)((((time_var / 1e6) * clock_var) + 511.0) / 512.0);
|
||||||
|
|
||||||
return tr_val;
|
return tr_val;
|
||||||
}
|
}
|
||||||
@@ -1050,6 +1053,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
|
|||||||
|
|
||||||
/* Chip ID will be obtained by probing the device later */
|
/* Chip ID will be obtained by probing the device later */
|
||||||
lpc2900_info->chipid = 0;
|
lpc2900_info->chipid = 0;
|
||||||
|
lpc2900_info->is_probed = false;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -1288,7 +1292,7 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
reduced size if that fails. */
|
reduced size if that fails. */
|
||||||
struct working_area *warea;
|
struct working_area *warea;
|
||||||
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
|
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
|
||||||
while( (retval = target_alloc_working_area(target,
|
while( (retval = target_alloc_working_area_try(target,
|
||||||
buffer_size + target_code_size,
|
buffer_size + target_code_size,
|
||||||
&warea)) != ERROR_OK )
|
&warea)) != ERROR_OK )
|
||||||
{
|
{
|
||||||
@@ -1365,7 +1369,7 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
|
|||||||
this_buffer = buffer;
|
this_buffer = buffer;
|
||||||
|
|
||||||
/* Make sure we stop at the next secured sector */
|
/* Make sure we stop at the next secured sector */
|
||||||
int sector = start_sector + 1;
|
sector = start_sector + 1;
|
||||||
while( sector < bank->num_sectors )
|
while( sector < bank->num_sectors )
|
||||||
{
|
{
|
||||||
/* Secured? */
|
/* Secured? */
|
||||||
@@ -1554,10 +1558,8 @@ static int lpc2900_probe(struct flash_bank *bank)
|
|||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We want to do this only once. Check if we already have a valid CHIPID,
|
/* We want to do this only once. */
|
||||||
* because then we will have already successfully probed the device.
|
if (lpc2900_info->is_probed)
|
||||||
*/
|
|
||||||
if (lpc2900_info->chipid == EXPECTED_CHIPID)
|
|
||||||
{
|
{
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
@@ -1636,7 +1638,11 @@ static int lpc2900_probe(struct flash_bank *bank)
|
|||||||
else if ( package_code == 4 )
|
else if ( package_code == 4 )
|
||||||
{
|
{
|
||||||
/* 144-pin package */
|
/* 144-pin package */
|
||||||
if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
|
if ( (bank->size == 256*KiB) && (feat3 == 0xFFFFFFE9) )
|
||||||
|
{
|
||||||
|
lpc2900_info->target_name = "LPC2926";
|
||||||
|
}
|
||||||
|
else if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
|
||||||
{
|
{
|
||||||
lpc2900_info->target_name = "LPC2917/01";
|
lpc2900_info->target_name = "LPC2917/01";
|
||||||
}
|
}
|
||||||
@@ -1670,7 +1676,11 @@ static int lpc2900_probe(struct flash_bank *bank)
|
|||||||
|
|
||||||
if ( !found )
|
if ( !found )
|
||||||
{
|
{
|
||||||
LOG_WARNING("Unknown LPC29xx derivative");
|
LOG_WARNING("Unknown LPC29xx derivative"
|
||||||
|
" (FEATx="
|
||||||
|
"%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ")",
|
||||||
|
feat0, feat1, feat2, feat3
|
||||||
|
);
|
||||||
return ERROR_FLASH_OPERATION_FAILED;
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1723,6 +1733,8 @@ static int lpc2900_probe(struct flash_bank *bank)
|
|||||||
offset += bank->sectors[i].size;
|
offset += bank->sectors[i].size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lpc2900_info->is_probed = true;
|
||||||
|
|
||||||
/* Read sector security status */
|
/* Read sector security status */
|
||||||
if ( lpc2900_read_security_status(bank) != ERROR_OK )
|
if ( lpc2900_read_security_status(bank) != ERROR_OK )
|
||||||
{
|
{
|
||||||
@@ -1830,6 +1842,7 @@ struct flash_driver lpc2900_flash =
|
|||||||
.erase = lpc2900_erase,
|
.erase = lpc2900_erase,
|
||||||
.protect = lpc2900_protect,
|
.protect = lpc2900_protect,
|
||||||
.write = lpc2900_write,
|
.write = lpc2900_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = lpc2900_probe,
|
.probe = lpc2900_probe,
|
||||||
.auto_probe = lpc2900_probe,
|
.auto_probe = lpc2900_probe,
|
||||||
.erase_check = lpc2900_erase_check,
|
.erase_check = lpc2900_erase_check,
|
||||||
|
|||||||
@@ -90,6 +90,20 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
ERASE_REGION(128, 4*KB)
|
ERASE_REGION(128, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.mfr = CFI_MFR_AMD, /* Spansion AM29LV040B */
|
||||||
|
.id = 0x4f,
|
||||||
|
.pri_id = 0x02,
|
||||||
|
.dev_size = 512*KB,
|
||||||
|
.interface_desc = 0x0, /* x8 only device */
|
||||||
|
.max_buf_write_size = 0x0,
|
||||||
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
|
.num_erase_regions = 1,
|
||||||
|
.erase_region_info =
|
||||||
|
{
|
||||||
|
ERASE_REGION(8, 64*KB)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.mfr = CFI_MFR_SST,
|
.mfr = CFI_MFR_SST,
|
||||||
.id = 0x2780,
|
.id = 0x2780,
|
||||||
@@ -229,6 +243,20 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
ERASE_REGION(1024, 4*KB)
|
ERASE_REGION(1024, 4*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.mfr = CFI_MFR_SST,
|
||||||
|
.id = 0x236d, /* SST39VF6401B */
|
||||||
|
.pri_id = 0x02,
|
||||||
|
.dev_size = 8*MB,
|
||||||
|
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||||
|
.max_buf_write_size = 0x0,
|
||||||
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||||
|
.num_erase_regions = 1,
|
||||||
|
.erase_region_info =
|
||||||
|
{
|
||||||
|
ERASE_REGION(2048, 4*KB)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.mfr = CFI_MFR_AMD,
|
.mfr = CFI_MFR_AMD,
|
||||||
.id = 0x22ab, /* AM29F400BB */
|
.id = 0x22ab, /* AM29F400BB */
|
||||||
@@ -280,6 +308,23 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
ERASE_REGION(15, 64*KB)
|
ERASE_REGION(15, 64*KB)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.mfr = CFI_MFR_FUJITSU,
|
||||||
|
.id = 0x22ea, /* MBM29SL800TE */
|
||||||
|
.pri_id = 0x02,
|
||||||
|
.dev_size = 1*MB,
|
||||||
|
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||||
|
.max_buf_write_size = 0x0,
|
||||||
|
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||||
|
.num_erase_regions = 4,
|
||||||
|
.erase_region_info =
|
||||||
|
{
|
||||||
|
ERASE_REGION(15, 64*KB),
|
||||||
|
ERASE_REGION(1, 32*KB),
|
||||||
|
ERASE_REGION(2, 8*KB),
|
||||||
|
ERASE_REGION(1, 16*KB)
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.mfr = CFI_MFR_FUJITSU,
|
.mfr = CFI_MFR_FUJITSU,
|
||||||
.id = 0xba, /* 29LV400BC */
|
.id = 0xba, /* 29LV400BC */
|
||||||
@@ -423,13 +468,19 @@ static struct non_cfi non_cfi_flashes[] = {
|
|||||||
|
|
||||||
void cfi_fixup_non_cfi(struct flash_bank *bank)
|
void cfi_fixup_non_cfi(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
|
unsigned int mask;
|
||||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||||
struct non_cfi *non_cfi = non_cfi_flashes;
|
struct non_cfi *non_cfi = non_cfi_flashes;
|
||||||
|
|
||||||
|
if(cfi_info->x16_as_x8)
|
||||||
|
mask = 0xFF;
|
||||||
|
else
|
||||||
|
mask = 0xFFFF;
|
||||||
|
|
||||||
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
|
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
|
||||||
{
|
{
|
||||||
if ((cfi_info->manufacturer == non_cfi->mfr)
|
if ((cfi_info->manufacturer == non_cfi->mfr)
|
||||||
&& (cfi_info->device_id == non_cfi->id))
|
&& (cfi_info->device_id == (non_cfi->id & mask)))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -446,10 +497,12 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
|
|||||||
cfi_info->vcc_max = 0x0;
|
cfi_info->vcc_max = 0x0;
|
||||||
cfi_info->vpp_min = 0x0;
|
cfi_info->vpp_min = 0x0;
|
||||||
cfi_info->vpp_max = 0x0;
|
cfi_info->vpp_max = 0x0;
|
||||||
cfi_info->word_write_timeout_typ = 0x0;
|
/* these are used for timeouts - use vales that should be long enough
|
||||||
cfi_info->buf_write_timeout_typ = 0x0;
|
for normal operation. */
|
||||||
cfi_info->block_erase_timeout_typ = 0x0;
|
cfi_info->word_write_timeout_typ = 0x0a;
|
||||||
cfi_info->chip_erase_timeout_typ = 0x0;
|
cfi_info->buf_write_timeout_typ = 0x0d;
|
||||||
|
cfi_info->block_erase_timeout_typ = 0x0d;
|
||||||
|
cfi_info->chip_erase_timeout_typ = 0x10;
|
||||||
cfi_info->word_write_timeout_max = 0x0;
|
cfi_info->word_write_timeout_max = 0x0;
|
||||||
cfi_info->buf_write_timeout_max = 0x0;
|
cfi_info->buf_write_timeout_max = 0x0;
|
||||||
cfi_info->block_erase_timeout_max = 0x0;
|
cfi_info->block_erase_timeout_max = 0x0;
|
||||||
@@ -469,7 +522,11 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
|
|||||||
cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
|
cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
|
||||||
cfi_info->status_poll_mask = non_cfi->status_poll_mask;
|
cfi_info->status_poll_mask = non_cfi->status_poll_mask;
|
||||||
cfi_info->num_erase_regions = non_cfi->num_erase_regions;
|
cfi_info->num_erase_regions = non_cfi->num_erase_regions;
|
||||||
cfi_info->erase_region_info = non_cfi->erase_region_info;
|
size_t erase_region_info_size = sizeof(*cfi_info->erase_region_info) *
|
||||||
|
cfi_info->num_erase_regions;
|
||||||
|
cfi_info->erase_region_info = malloc(erase_region_info_size);
|
||||||
|
memcpy(cfi_info->erase_region_info,
|
||||||
|
non_cfi->erase_region_info, erase_region_info_size);
|
||||||
cfi_info->dev_size = non_cfi->dev_size;
|
cfi_info->dev_size = non_cfi->dev_size;
|
||||||
|
|
||||||
if (cfi_info->pri_id == 0x2)
|
if (cfi_info->pri_id == 0x2)
|
||||||
|
|||||||
@@ -101,8 +101,6 @@ static int ocl_erase(struct flash_bank *bank, int first, int last)
|
|||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
||||||
{
|
{
|
||||||
if (retval == ERROR_TARGET_TIMEOUT)
|
|
||||||
LOG_ERROR("loader not responding");
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +204,6 @@ static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
|
|||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
||||||
{
|
{
|
||||||
if (retval == ERROR_TARGET_TIMEOUT)
|
|
||||||
LOG_ERROR("loader not responding");
|
|
||||||
free(dcc_buffer);
|
free(dcc_buffer);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -252,8 +248,6 @@ static int ocl_probe(struct flash_bank *bank)
|
|||||||
/* wait for response, fixed timeout of 1 s */
|
/* wait for response, fixed timeout of 1 s */
|
||||||
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
if ((retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000) != ERROR_OK))
|
||||||
{
|
{
|
||||||
if (retval == ERROR_TARGET_TIMEOUT)
|
|
||||||
LOG_ERROR("loader not responding");
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,6 +347,7 @@ struct flash_driver ocl_flash = {
|
|||||||
.erase = ocl_erase,
|
.erase = ocl_erase,
|
||||||
.protect = ocl_protect,
|
.protect = ocl_protect,
|
||||||
.write = ocl_write,
|
.write = ocl_write,
|
||||||
|
.read = default_flash_read,
|
||||||
.probe = ocl_probe,
|
.probe = ocl_probe,
|
||||||
.erase_check = ocl_erase_check,
|
.erase_check = ocl_erase_check,
|
||||||
.protect_check = ocl_protect_check,
|
.protect_check = ocl_protect_check,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,111 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2005 by Dominic Rath *
|
|
||||||
* Dominic.Rath@gmx.de *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2008 by Spencer Oliver *
|
|
||||||
* spen@spen-soft.co.uk *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 2008 by John McCarthy *
|
|
||||||
* jgmcc@magma.ca *
|
|
||||||
* *
|
|
||||||
* 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 PIC32MX_H
|
|
||||||
#define PIC32MX_H
|
|
||||||
|
|
||||||
struct pic32mx_flash_bank
|
|
||||||
{
|
|
||||||
struct working_area *write_algorithm;
|
|
||||||
int devid;
|
|
||||||
int ppage_size;
|
|
||||||
int probed;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PIC32MX_MANUF_ID 0x029
|
|
||||||
|
|
||||||
/* pic32mx memory locations */
|
|
||||||
|
|
||||||
#define PIC32MX_KUSEG_PGM_FLASH 0x7D000000
|
|
||||||
#define PIC32MX_KUSEG_RAM 0x7F000000
|
|
||||||
|
|
||||||
#define PIC32MX_KSEG0_RAM 0x80000000
|
|
||||||
#define PIC32MX_KSEG0_PGM_FLASH 0x9D000000
|
|
||||||
#define PIC32MX_KSEG0_BOOT_FLASH 0x9FC00000
|
|
||||||
|
|
||||||
#define PIC32MX_KSEG1_RAM 0xA0000000
|
|
||||||
#define PIC32MX_KSEG1_PGM_FLASH 0xBD000000
|
|
||||||
#define PIC32MX_KSEG1_PERIPHERAL 0xBF800000
|
|
||||||
#define PIC32MX_KSEG1_BOOT_FLASH 0xBFC00000
|
|
||||||
|
|
||||||
#define PIC32MX_PHYS_RAM 0x00000000
|
|
||||||
#define PIC32MX_PHYS_PGM_FLASH 0x1D000000
|
|
||||||
#define PIC32MX_PHYS_PERIPHERALS 0x1F800000
|
|
||||||
#define PIC32MX_PHYS_BOOT_FLASH 0x1FC00000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Translate Virtual and Physical addresses.
|
|
||||||
* Note: These macros only work for KSEG0/KSEG1 addresses.
|
|
||||||
*/
|
|
||||||
#define KS1Virt2Phys(vaddr) ((vaddr)-0xA0000000)
|
|
||||||
#define Phys2KS1Virt(paddr) ((paddr) + 0xA0000000)
|
|
||||||
#define KS0Virt2Phys(vaddr) ((vaddr)-0x80000000)
|
|
||||||
#define Phys2KS0Virt(paddr) ((paddr) + 0x80000000)
|
|
||||||
|
|
||||||
/* pic32mx configuration register locations */
|
|
||||||
|
|
||||||
#define PIC32MX_DEVCFG0 0xBFC02FFC
|
|
||||||
#define PIC32MX_DEVCFG1 0xBFC02FF8
|
|
||||||
#define PIC32MX_DEVCFG2 0xBFC02FF4
|
|
||||||
#define PIC32MX_DEVCFG3 0XBFC02FF0
|
|
||||||
#define PIC32MX_DEVID 0xBF80F220
|
|
||||||
|
|
||||||
/* pic32mx flash controller register locations */
|
|
||||||
|
|
||||||
#define PIC32MX_NVMCON 0xBF80F400
|
|
||||||
#define PIC32MX_NVMCONCLR 0xBF80F404
|
|
||||||
#define PIC32MX_NVMCONSET 0xBF80F408
|
|
||||||
#define PIC32MX_NVMCONINV 0xBF80F40C
|
|
||||||
#define NVMCON_NVMWR (1 << 15)
|
|
||||||
#define NVMCON_NVMWREN (1 << 14)
|
|
||||||
#define NVMCON_NVMERR (1 << 13)
|
|
||||||
#define NVMCON_LVDERR (1 << 12)
|
|
||||||
#define NVMCON_LVDSTAT (1 << 11)
|
|
||||||
#define NVMCON_OP_PFM_ERASE 0x5
|
|
||||||
#define NVMCON_OP_PAGE_ERASE 0x4
|
|
||||||
#define NVMCON_OP_ROW_PROG 0x3
|
|
||||||
#define NVMCON_OP_WORD_PROG 0x1
|
|
||||||
#define NVMCON_OP_NOP 0x0
|
|
||||||
|
|
||||||
#define PIC32MX_NVMKEY 0xBF80F410
|
|
||||||
#define PIC32MX_NVMADDR 0xBF80F420
|
|
||||||
#define PIC32MX_NVMADDRCLR 0xBF80F424
|
|
||||||
#define PIC32MX_NVMADDRSET 0xBF80F428
|
|
||||||
#define PIC32MX_NVMADDRINV 0xBF80F42C
|
|
||||||
#define PIC32MX_NVMDATA 0xBF80F430
|
|
||||||
#define PIC32MX_NVMSRCADDR 0xBF80F440
|
|
||||||
|
|
||||||
/* flash unlock keys */
|
|
||||||
|
|
||||||
#define NVMKEY1 0xAA996655
|
|
||||||
#define NVMKEY2 0x556699AA
|
|
||||||
|
|
||||||
struct pic32mx_mem_layout {
|
|
||||||
uint32_t sector_start;
|
|
||||||
uint32_t sector_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* PIC32MX_H */
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user