Compare commits
1599 Commits
v0.1.0
...
v0.3.0-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70f735007d | ||
|
|
ce88e8adf7 | ||
|
|
4d17541a2c | ||
|
|
053a763aa6 | ||
|
|
0b882951b7 | ||
|
|
e8dc384be9 | ||
|
|
07c85e41a4 | ||
|
|
c970d03ddb | ||
|
|
eb9790dc91 | ||
|
|
89c1bea931 | ||
|
|
76afa936ba | ||
|
|
39dd68bca6 | ||
|
|
993fe4ab63 | ||
|
|
ad5192a2b9 | ||
|
|
68937cadfb | ||
|
|
068a6c7895 | ||
|
|
ee8e93cb83 | ||
|
|
1020569b9f | ||
|
|
0b476c9f4c | ||
|
|
4a26390eec | ||
|
|
4a91b070ff | ||
|
|
ddade10d4a | ||
|
|
8f3b28ff41 | ||
|
|
d87ee640c7 | ||
|
|
eaebc6cd69 | ||
|
|
592e021543 | ||
|
|
8b30f22dec | ||
|
|
6cb1d10cda | ||
|
|
0cac8b67be | ||
|
|
a07422c26c | ||
|
|
d785f552ee | ||
|
|
19b84dafb0 | ||
|
|
e98817c463 | ||
|
|
2a8aa3b7ef | ||
|
|
0b436497e0 | ||
|
|
75cdc8a260 | ||
|
|
bfefe85645 | ||
|
|
cb854323c9 | ||
|
|
0a1356c9cc | ||
|
|
18aad44f71 | ||
|
|
79f71fad58 | ||
|
|
814183a5c4 | ||
|
|
517e812de3 | ||
|
|
f593ff0a3d | ||
|
|
344bed2f7e | ||
|
|
3537c368fe | ||
|
|
fcf1301e52 | ||
|
|
e996452089 | ||
|
|
1e5daf5886 | ||
|
|
2d45a10dfd | ||
|
|
85bf1627cd | ||
|
|
2783cba810 | ||
|
|
818cedaff3 | ||
|
|
69a6037ce6 | ||
|
|
e895246966 | ||
|
|
a4a1de4dd1 | ||
|
|
62525792e0 | ||
|
|
a02411a15f | ||
|
|
7556a93aed | ||
|
|
a1609e5ad1 | ||
|
|
79e257a209 | ||
|
|
ad75639611 | ||
|
|
e4dba30b63 | ||
|
|
6907ef9d50 | ||
|
|
c70073ef67 | ||
|
|
d243e641d3 | ||
|
|
3cc147efd9 | ||
|
|
53979244b1 | ||
|
|
fb61f52731 | ||
|
|
0388a9c0e5 | ||
|
|
6ec1026bbb | ||
|
|
6726b78707 | ||
|
|
97166327db | ||
|
|
113679ff59 | ||
|
|
557d1b6490 | ||
|
|
89a8a37998 | ||
|
|
76b4ee8935 | ||
|
|
990f50a73b | ||
|
|
5cf0af002c | ||
|
|
73349dc5ac | ||
|
|
c9fbfbd95c | ||
|
|
05d6716936 | ||
|
|
cb7965da15 | ||
|
|
a61b57a87f | ||
|
|
510db585fd | ||
|
|
bc792857a5 | ||
|
|
dd54981702 | ||
|
|
a894c2d8b2 | ||
|
|
4490a42a09 | ||
|
|
44e9200d0a | ||
|
|
1ee8ef4210 | ||
|
|
7afc181e42 | ||
|
|
9b9bc78ef1 | ||
|
|
ed1e45b388 | ||
|
|
5535399a46 | ||
|
|
6a2fd7cad5 | ||
|
|
bc0cc62afd | ||
|
|
79bf27da71 | ||
|
|
4d32b6eee9 | ||
|
|
20c8f64f0a | ||
|
|
1f917bdc0c | ||
|
|
f8cd850c4d | ||
|
|
86cbbe8a4a | ||
|
|
b6c4d1006f | ||
|
|
85398ccdcf | ||
|
|
23c629a85e | ||
|
|
407061eaa6 | ||
|
|
35affce085 | ||
|
|
0ca473468c | ||
|
|
165e3a1468 | ||
|
|
bbd7e22f0b | ||
|
|
b5b4fee811 | ||
|
|
5e837387aa | ||
|
|
9f6c23f479 | ||
|
|
026559068d | ||
|
|
c8d935ab7c | ||
|
|
b23b096c8e | ||
|
|
2d924a59db | ||
|
|
688003cb23 | ||
|
|
8b3bfcfc5b | ||
|
|
5aba621b55 | ||
|
|
a0b1e05b53 | ||
|
|
456ec36795 | ||
|
|
dbf7440148 | ||
|
|
bc13c12be9 | ||
|
|
c3428f5b7a | ||
|
|
8f09c5df85 | ||
|
|
20a3b14828 | ||
|
|
bffe824df6 | ||
|
|
60e24aa597 | ||
|
|
6160a946ec | ||
|
|
5b352c9e79 | ||
|
|
7b650a6abe | ||
|
|
41c1af7c67 | ||
|
|
a8234af06c | ||
|
|
40c9668b70 | ||
|
|
22aff82cae | ||
|
|
4aacf01e19 | ||
|
|
cf7eae176e | ||
|
|
f525f2ef0d | ||
|
|
d75b9ec697 | ||
|
|
6efaa95c44 | ||
|
|
37e9f65f5a | ||
|
|
7252a72465 | ||
|
|
8a162e5e06 | ||
|
|
03c9e48f88 | ||
|
|
cdc33b3808 | ||
|
|
246ff4f601 | ||
|
|
7035b37e71 | ||
|
|
4c450b5c6b | ||
|
|
55f4e430e8 | ||
|
|
f8c8d8bc72 | ||
|
|
f2dc1eeef1 | ||
|
|
b83d79a42f | ||
|
|
dc871f422d | ||
|
|
71bca7640a | ||
|
|
616c154866 | ||
|
|
b4e4532dd2 | ||
|
|
40ac8d7753 | ||
|
|
53dea2f952 | ||
|
|
e4cc19521b | ||
|
|
b1f7b35983 | ||
|
|
a343b18bfb | ||
|
|
0da2f750a1 | ||
|
|
60f8770502 | ||
|
|
7d78021efa | ||
|
|
4119cd6db2 | ||
|
|
39b57471bf | ||
|
|
a2886fe3c6 | ||
|
|
00f2c9e062 | ||
|
|
0d3632adff | ||
|
|
64ec7f66a8 | ||
|
|
7280a52e69 | ||
|
|
7a57c31619 | ||
|
|
7c7467b34f | ||
|
|
16a7ad5799 | ||
|
|
3aa9fabfe9 | ||
|
|
c6b24fb4f0 | ||
|
|
f87985b614 | ||
|
|
16742b529b | ||
|
|
49f3497bfa | ||
|
|
1b90a9f5eb | ||
|
|
84dabdcc72 | ||
|
|
c74ede4248 | ||
|
|
1033633321 | ||
|
|
d340906476 | ||
|
|
e3d82fe24d | ||
|
|
1beb24a61c | ||
|
|
eccd9059d3 | ||
|
|
740fd107f2 | ||
|
|
14be119906 | ||
|
|
7b9f01e0ae | ||
|
|
8624535b80 | ||
|
|
32599fab1a | ||
|
|
aaf1daa056 | ||
|
|
54c16fc56e | ||
|
|
642519649e | ||
|
|
e4de4251fe | ||
|
|
6d4cdddbe2 | ||
|
|
4297209ac9 | ||
|
|
bde4a40422 | ||
|
|
d96e3eae23 | ||
|
|
afc3a5cc6f | ||
|
|
f4fce92f28 | ||
|
|
035b6ba84b | ||
|
|
9bdbffb8cc | ||
|
|
c5949a03a7 | ||
|
|
e3a0647558 | ||
|
|
62b7e1ce64 | ||
|
|
cbe34d0819 | ||
|
|
9a4e650083 | ||
|
|
817ea3f4e4 | ||
|
|
fbbd3066ff | ||
|
|
5c3c4af88f | ||
|
|
2329ae9306 | ||
|
|
f64e924ba9 | ||
|
|
2e210ee48f | ||
|
|
ad43374c7f | ||
|
|
43b3807878 | ||
|
|
1c262c8826 | ||
|
|
37755ffdb6 | ||
|
|
23e22b6ec4 | ||
|
|
22045fa6f2 | ||
|
|
d9ce8a2f60 | ||
|
|
a6d858ebcd | ||
|
|
7393fcfc90 | ||
|
|
6521b75ec2 | ||
|
|
a2a3620d35 | ||
|
|
50b94628ae | ||
|
|
6cba486356 | ||
|
|
b11d79110e | ||
|
|
71af49ca7f | ||
|
|
86a7d813a1 | ||
|
|
0bcf5a6b76 | ||
|
|
108028112f | ||
|
|
d20103cd93 | ||
|
|
48e96a18ed | ||
|
|
24df719b09 | ||
|
|
0c4b119d3f | ||
|
|
75581ffea6 | ||
|
|
965b331d0b | ||
|
|
781997f556 | ||
|
|
01735c515f | ||
|
|
3e87fc20ab | ||
|
|
2d3bcddf04 | ||
|
|
74ae645623 | ||
|
|
7b3be0e21e | ||
|
|
631b2ab244 | ||
|
|
358263f484 | ||
|
|
e961bd14d9 | ||
|
|
9536577c02 | ||
|
|
9655c5b093 | ||
|
|
84f51bf50c | ||
|
|
1dd302883d | ||
|
|
016e7ebbfa | ||
|
|
cb7ad25c04 | ||
|
|
e18bd3b55e | ||
|
|
9b11eebf33 | ||
|
|
45f03dd9b5 | ||
|
|
9542318312 | ||
|
|
6d2473b65b | ||
|
|
f0ddb40ced | ||
|
|
7e4f9ac697 | ||
|
|
388e94d5c1 | ||
|
|
379386743a | ||
|
|
45674af63a | ||
|
|
d4e4d65d28 | ||
|
|
14dc22612b | ||
|
|
5a6980869b | ||
|
|
8e39f86ef4 | ||
|
|
9816f2ecda | ||
|
|
772d8d06ea | ||
|
|
d4607c1f7c | ||
|
|
c4ee12ea77 | ||
|
|
a17eb667a3 | ||
|
|
40f361dd94 | ||
|
|
c993d75d1f | ||
|
|
f6a29d438e | ||
|
|
4f7761828c | ||
|
|
ec3015db1a | ||
|
|
25f9a466ca | ||
|
|
00e900f8a1 | ||
|
|
f89d1cbfd6 | ||
|
|
0dcfbec7fb | ||
|
|
58b78818e0 | ||
|
|
6dd8f37e6d | ||
|
|
9b1a938a22 | ||
|
|
c5f54c5333 | ||
|
|
49d0ea2126 | ||
|
|
9262e0dbdf | ||
|
|
3bade442b1 | ||
|
|
b4acbee47f | ||
|
|
7b5ddb4a58 | ||
|
|
983f5a1ae9 | ||
|
|
aa46b15377 | ||
|
|
8b2b0071a9 | ||
|
|
857c06ca8b | ||
|
|
f6a5749c1b | ||
|
|
5dae4753ff | ||
|
|
57e12b7e45 | ||
|
|
2c76cd7171 | ||
|
|
a690ee3c0c | ||
|
|
0b11e4dbb4 | ||
|
|
b13dbc80e0 | ||
|
|
982ac083f0 | ||
|
|
2e29131f2b | ||
|
|
81b57a3fb6 | ||
|
|
ee329275d3 | ||
|
|
51be978b43 | ||
|
|
ce89c7bf65 | ||
|
|
76b78feef1 | ||
|
|
a89dd2ca65 | ||
|
|
3878b12793 | ||
|
|
cde17a42e9 | ||
|
|
f7f38fa70d | ||
|
|
fbf775c0b7 | ||
|
|
a41725c788 | ||
|
|
bb5f713e44 | ||
|
|
0dd669f2a7 | ||
|
|
2a86a53c3f | ||
|
|
072d6d3db6 | ||
|
|
fbe1c23c12 | ||
|
|
98ae6c24f0 | ||
|
|
ab30d5203c | ||
|
|
d879faa3cb | ||
|
|
4b9bdd664a | ||
|
|
69b8b5e0aa | ||
|
|
ed8fd94d7c | ||
|
|
efef05870d | ||
|
|
a5d02116a6 | ||
|
|
997d5284cb | ||
|
|
ae17ce23eb | ||
|
|
c5145ceb19 | ||
|
|
bb000a6f77 | ||
|
|
32a2c70d3e | ||
|
|
641c574425 | ||
|
|
327ba6cb0a | ||
|
|
e921fead94 | ||
|
|
01000e988a | ||
|
|
fc7cd1d85e | ||
|
|
56a04a3413 | ||
|
|
f36d0083de | ||
|
|
56b346447b | ||
|
|
dce1cdc9fb | ||
|
|
0de530067f | ||
|
|
c87357a33f | ||
|
|
9a9ebfb924 | ||
|
|
11856bcffc | ||
|
|
a5354ff5cb | ||
|
|
34e8c67b1f | ||
|
|
bc075606b7 | ||
|
|
24f011ebb4 | ||
|
|
86b49612a6 | ||
|
|
6f359fba68 | ||
|
|
bd7cbd01e8 | ||
|
|
0c41395fc3 | ||
|
|
7a1ac49ac9 | ||
|
|
8e1d516927 | ||
|
|
696ed5fdc4 | ||
|
|
d11c8e3c8e | ||
|
|
14f2189e1a | ||
|
|
fd4c0f33b1 | ||
|
|
ae4c224459 | ||
|
|
41bb41bb93 | ||
|
|
9df861b0c0 | ||
|
|
1d0b276c9f | ||
|
|
6f7491c1c1 | ||
|
|
0ed5f5afd9 | ||
|
|
bf5f21e39a | ||
|
|
332c8d78d8 | ||
|
|
6336ebb05c | ||
|
|
5c50cf802c | ||
|
|
0a7158140a | ||
|
|
8b73ec8d64 | ||
|
|
afae28fb2c | ||
|
|
ef30f22fd3 | ||
|
|
028e535604 | ||
|
|
c2f593bdc1 | ||
|
|
18d8ac5267 | ||
|
|
57578b4ea3 | ||
|
|
69dd81dcf8 | ||
|
|
1b092a27f0 | ||
|
|
a6f9c5a796 | ||
|
|
a634b5d52e | ||
|
|
bb5086b83e | ||
|
|
7b4428df97 | ||
|
|
ed22097a55 | ||
|
|
a4c7e2dd96 | ||
|
|
5badd9b29a | ||
|
|
35e5e07127 | ||
|
|
1d96a84f06 | ||
|
|
ad23cb97b2 | ||
|
|
2a0e491d9a | ||
|
|
a33e272abd | ||
|
|
b747da2663 | ||
|
|
59b295dbbe | ||
|
|
720c39ba2f | ||
|
|
732df6fea0 | ||
|
|
ad800b1c02 | ||
|
|
84903467ec | ||
|
|
d40fd9e0f4 | ||
|
|
1ee32a8fa1 | ||
|
|
398f60af56 | ||
|
|
9b29b729f3 | ||
|
|
5a824c934f | ||
|
|
e9b919fbc6 | ||
|
|
e31e6a10de | ||
|
|
49e2267f1f | ||
|
|
3bcf8a8a25 | ||
|
|
fc318c0298 | ||
|
|
67dbf35896 | ||
|
|
ad3a24f944 | ||
|
|
431925a452 | ||
|
|
50aa561796 | ||
|
|
31b520c379 | ||
|
|
c7565cc381 | ||
|
|
30b1bbceea | ||
|
|
7986ed5ac2 | ||
|
|
a7a1ae032b | ||
|
|
d460a7cd6c | ||
|
|
4da019edeb | ||
|
|
eea0486263 | ||
|
|
cd0ca916b3 | ||
|
|
55b1ea1d8e | ||
|
|
f703322b3f | ||
|
|
8b994145b8 | ||
|
|
14cbd545bf | ||
|
|
bd4377194e | ||
|
|
4deb8530c6 | ||
|
|
4ebd353ae1 | ||
|
|
1af6b72fc1 | ||
|
|
16e17ab1b3 | ||
|
|
0c2ff267aa | ||
|
|
fdfd434c24 | ||
|
|
00adcc773a | ||
|
|
930269b483 | ||
|
|
421b8e133a | ||
|
|
889bd3e716 | ||
|
|
84e86e9aee | ||
|
|
d2088f0d29 | ||
|
|
f163d0009d | ||
|
|
0165ae4405 | ||
|
|
8b89224c6e | ||
|
|
b71e3aff6d | ||
|
|
309870e414 | ||
|
|
2ff59c9aaf | ||
|
|
e76fe13a95 | ||
|
|
d78d79aff6 | ||
|
|
8b82de60c7 | ||
|
|
1df358855a | ||
|
|
197a195191 | ||
|
|
4eb2e50e4d | ||
|
|
f9c65b5cd5 | ||
|
|
64d998e584 | ||
|
|
e057491d3c | ||
|
|
ff5170a979 | ||
|
|
6d20e27f9a | ||
|
|
ebd46e23b3 | ||
|
|
b1ccc35323 | ||
|
|
baa63aa608 | ||
|
|
5198968116 | ||
|
|
14ed84fdbe | ||
|
|
6996e628f8 | ||
|
|
5627e841e3 | ||
|
|
c05cb61b32 | ||
|
|
ef7722e6af | ||
|
|
e4cff09137 | ||
|
|
3cf4717a2a | ||
|
|
eaa895a0b2 | ||
|
|
adae530eb7 | ||
|
|
deda6ea509 | ||
|
|
1ee66e0ce7 | ||
|
|
13e6aa6e03 | ||
|
|
f19565b226 | ||
|
|
d68096dcf2 | ||
|
|
51c0ef94d1 | ||
|
|
5c1ae65f8e | ||
|
|
3ce038baa3 | ||
|
|
b80f6f96d3 | ||
|
|
561502ae31 | ||
|
|
8ba6f13067 | ||
|
|
f56c2db5a7 | ||
|
|
f4a9db660b | ||
|
|
fc889f0357 | ||
|
|
587aa64850 | ||
|
|
f21026e2f5 | ||
|
|
42115c0997 | ||
|
|
cd1b2c15ab | ||
|
|
d41f2bfb14 | ||
|
|
26b60a6ade | ||
|
|
6128c515db | ||
|
|
d5e183c31f | ||
|
|
56944ac1c8 | ||
|
|
a4081acc51 | ||
|
|
164c9c75d8 | ||
|
|
df25617e54 | ||
|
|
1930e08b99 | ||
|
|
ce0824868c | ||
|
|
d6a686c852 | ||
|
|
a604b570da | ||
|
|
e48e7000b0 | ||
|
|
83655bf49b | ||
|
|
96ff1d278b | ||
|
|
0ab8e710db | ||
|
|
e2dd1dbab9 | ||
|
|
5fe4500e50 | ||
|
|
fca8cddc26 | ||
|
|
07f13dff2a | ||
|
|
153270fea3 | ||
|
|
bb363c77e8 | ||
|
|
c946358a06 | ||
|
|
c33a1d764c | ||
|
|
f16a603506 | ||
|
|
00fad24996 | ||
|
|
f1f54a0fc5 | ||
|
|
a239d6b334 | ||
|
|
fc240afcac | ||
|
|
e755b0eb86 | ||
|
|
12c13acdf8 | ||
|
|
35000e10d0 | ||
|
|
14fb875e8f | ||
|
|
6d08c1800c | ||
|
|
b3e6cb6d56 | ||
|
|
59a3df127e | ||
|
|
a13d08bced | ||
|
|
f7c85c42a0 | ||
|
|
44f72dbdb2 | ||
|
|
3731bc5877 | ||
|
|
917f92f052 | ||
|
|
f486f86c6c | ||
|
|
3eb441bbcc | ||
|
|
7d3706c980 | ||
|
|
92ddc0266b | ||
|
|
ef733b48e9 | ||
|
|
2afb46ab34 | ||
|
|
ad50a99d6a | ||
|
|
2eff86ab23 | ||
|
|
d3c77fdbb2 | ||
|
|
41057944b5 | ||
|
|
f130f95d45 | ||
|
|
0894ae214a | ||
|
|
5195405da8 | ||
|
|
1d61e34e1e | ||
|
|
48b3b3afba | ||
|
|
0c9d86b273 | ||
|
|
54b32f4cd6 | ||
|
|
44b06db783 | ||
|
|
4d26afdf5c | ||
|
|
557cafcc70 | ||
|
|
f8cc725e0e | ||
|
|
3d9551241b | ||
|
|
d3315c4183 | ||
|
|
95da247b40 | ||
|
|
f0fd28a66c | ||
|
|
54ffd82a1a | ||
|
|
c2cecc74b0 | ||
|
|
445fef39fb | ||
|
|
2378eaadef | ||
|
|
261e04466d | ||
|
|
9ab9786f67 | ||
|
|
78c0e873d2 | ||
|
|
f538794bf6 | ||
|
|
9c05c92c14 | ||
|
|
92db0c58b0 | ||
|
|
37b15fb2c4 | ||
|
|
374f6c8b70 | ||
|
|
1e8225c738 | ||
|
|
8adda07ed1 | ||
|
|
5505b8fa63 | ||
|
|
997df70f6e | ||
|
|
fddbc58091 | ||
|
|
2428bc2a5c | ||
|
|
f11b1ff485 | ||
|
|
1793150091 | ||
|
|
dbb0f31abb | ||
|
|
3e538f9248 | ||
|
|
9cd160608c | ||
|
|
5e53d488dc | ||
|
|
e47be43ed1 | ||
|
|
c3e7d33b54 | ||
|
|
2a4223dc68 | ||
|
|
eee3b0c2a8 | ||
|
|
cb3429570c | ||
|
|
38a1ae7281 | ||
|
|
3324841558 | ||
|
|
0ace4d24db | ||
|
|
30814c2904 | ||
|
|
176b5600ed | ||
|
|
c97caebccd | ||
|
|
2e77919853 | ||
|
|
c493543fc9 | ||
|
|
dc575dc5bf | ||
|
|
f90d8fa45f | ||
|
|
6d1d58a1fc | ||
|
|
fb1a9b2cb2 | ||
|
|
8959de9f67 | ||
|
|
84df52f9ea | ||
|
|
3813fda44a | ||
|
|
aea6815462 | ||
|
|
0e2c2fe1d1 | ||
|
|
6319ea33f7 | ||
|
|
4ce93ac479 | ||
|
|
128a733428 | ||
|
|
319fdecb76 | ||
|
|
d61714f4d5 | ||
|
|
53d605e12c | ||
|
|
5e98c71436 | ||
|
|
0ab650293a | ||
|
|
95d2a23724 | ||
|
|
9af5e445b7 | ||
|
|
50c086ffb9 | ||
|
|
e43979e702 | ||
|
|
8591335ba6 | ||
|
|
5a6f218a9c | ||
|
|
1017e62c97 | ||
|
|
974d5f8391 | ||
|
|
1f28b934ce | ||
|
|
26807d1935 | ||
|
|
1d9ce8d2b3 | ||
|
|
bc9df17e42 | ||
|
|
bed9c62f9e | ||
|
|
2004f2be41 | ||
|
|
9e343a4102 | ||
|
|
90d6c8f0a0 | ||
|
|
4486321dd9 | ||
|
|
4f79ba3ca0 | ||
|
|
ac05113f7a | ||
|
|
b96052d591 | ||
|
|
68f30a77f1 | ||
|
|
97856dc8b1 | ||
|
|
991a5311c6 | ||
|
|
940703e16c | ||
|
|
f6dcfac679 | ||
|
|
96c8ff3d08 | ||
|
|
aa0b69ad5f | ||
|
|
db4daee44f | ||
|
|
cbc3543247 | ||
|
|
92aa05c105 | ||
|
|
bf509dbafa | ||
|
|
a388736c41 | ||
|
|
3bb216f112 | ||
|
|
9218d4be9b | ||
|
|
99e8c9fccb | ||
|
|
afc3eb1dc1 | ||
|
|
f0bd9e1083 | ||
|
|
19a678834d | ||
|
|
5c82587a1e | ||
|
|
de39cb7724 | ||
|
|
610f4e9522 | ||
|
|
6e2bdc3e68 | ||
|
|
c25d4d4f30 | ||
|
|
d3a6ae5442 | ||
|
|
b6fe525580 | ||
|
|
19bab50773 | ||
|
|
57be9774bf | ||
|
|
75bb37056a | ||
|
|
0f9c1bfd82 | ||
|
|
be680ada77 | ||
|
|
819944fb28 | ||
|
|
e06e22dbbd | ||
|
|
aabee7e8ca | ||
|
|
05f0e6e9d5 | ||
|
|
b9feaddd75 | ||
|
|
b54f4c5cb6 | ||
|
|
be1ab108f3 | ||
|
|
7b97e5b1cc | ||
|
|
fde4f37f6a | ||
|
|
f2f612aa69 | ||
|
|
b521037509 | ||
|
|
d84bba66ae | ||
|
|
7e07b9abf1 | ||
|
|
245b0213f5 | ||
|
|
836b6c18f0 | ||
|
|
5f48cefb10 | ||
|
|
580a05a07f | ||
|
|
40d7e81c45 | ||
|
|
9eb3181cc8 | ||
|
|
13e592f9f6 | ||
|
|
333642fcff | ||
|
|
a1c14646cb | ||
|
|
01823f5e0b | ||
|
|
8f87f8945e | ||
|
|
e8ba53ef6f | ||
|
|
592e080690 | ||
|
|
c5de7b6bd7 | ||
|
|
4cf8d5ec17 | ||
|
|
0ca97d82d8 | ||
|
|
86e4324f1b | ||
|
|
1840226d55 | ||
|
|
3c2eabd20f | ||
|
|
db7e77237c | ||
|
|
f876d5e9c7 | ||
|
|
c18947b947 | ||
|
|
310be8a838 | ||
|
|
86173cdbdd | ||
|
|
8f9f5c189b | ||
|
|
1642dd2ea0 | ||
|
|
6f4d876c88 | ||
|
|
8ab9b6d39e | ||
|
|
1a400f8b8e | ||
|
|
8d8937f1a6 | ||
|
|
d727e31af9 | ||
|
|
7ddc6c3d55 | ||
|
|
10e435c961 | ||
|
|
d31e57a10d | ||
|
|
6ba0b46cec | ||
|
|
ed5b5b834e | ||
|
|
e2cacd4368 | ||
|
|
2d0afa36a8 | ||
|
|
c0f4495d5e | ||
|
|
d579befc07 | ||
|
|
0e28997989 | ||
|
|
06a1bb335e | ||
|
|
a830197f59 | ||
|
|
a3ec1e1f94 | ||
|
|
8b16068941 | ||
|
|
c928fe0fa0 | ||
|
|
a0c10dd29b | ||
|
|
491083a248 | ||
|
|
0de478618a | ||
|
|
011e9b85b1 | ||
|
|
14f88acaf6 | ||
|
|
5f9b74d055 | ||
|
|
03803a9d79 | ||
|
|
c7cfb3417b | ||
|
|
cc9488008a | ||
|
|
1ac220df71 | ||
|
|
588a17da43 | ||
|
|
4f4592539d | ||
|
|
0ffbc60333 | ||
|
|
af52480a45 | ||
|
|
b7c5e630ea | ||
|
|
f7afcfe23f | ||
|
|
d0a300e0a0 | ||
|
|
16c77cf3ca | ||
|
|
890973acc4 | ||
|
|
bb37adadab | ||
|
|
6f9aac1892 | ||
|
|
08128b572a | ||
|
|
71f95de8a6 | ||
|
|
5d0cdf4d94 | ||
|
|
fad8521a87 | ||
|
|
45ec363c4a | ||
|
|
2343245090 | ||
|
|
cdd8f23b9b | ||
|
|
7b65cb367f | ||
|
|
8551803eb5 | ||
|
|
a92cc405ac | ||
|
|
7fdce0e8bc | ||
|
|
c6e80f63a3 | ||
|
|
a351c57261 | ||
|
|
f5e4511701 | ||
|
|
a9d5119825 | ||
|
|
ea95cdb8e2 | ||
|
|
70d853b9fa | ||
|
|
82403fe644 | ||
|
|
5d657571cb | ||
|
|
d5339d2eb4 | ||
|
|
f218f36df5 | ||
|
|
ae28b96ab9 | ||
|
|
0f6a47837e | ||
|
|
5af1bdcff4 | ||
|
|
5c123481a1 | ||
|
|
5bb0f1d29a | ||
|
|
72687f227a | ||
|
|
b3edde7b7d | ||
|
|
2e0be4e18b | ||
|
|
eb9ecb8224 | ||
|
|
1b2c1c6ff0 | ||
|
|
538050c146 | ||
|
|
8e899d43ef | ||
|
|
7c892082c9 | ||
|
|
57612ecf1d | ||
|
|
d7ada2457e | ||
|
|
e4850d7159 | ||
|
|
78cf92166a | ||
|
|
4c31d5d179 | ||
|
|
128ff94226 | ||
|
|
28fa603eff | ||
|
|
5208481fb3 | ||
|
|
08382e0601 | ||
|
|
04cb121073 | ||
|
|
c1995bb08f | ||
|
|
6dc8bbdc2b | ||
|
|
79d80e40bd | ||
|
|
ba0f4a254c | ||
|
|
8b7f813b23 | ||
|
|
bdb7dd5e0f | ||
|
|
82aa9af1ad | ||
|
|
0bc53e73cc | ||
|
|
b8034bd9ee | ||
|
|
9d19468502 | ||
|
|
e582ea9776 | ||
|
|
00228aa839 | ||
|
|
e8febc2255 | ||
|
|
5f4ecc60a9 | ||
|
|
15974a0eeb | ||
|
|
aabb31d571 | ||
|
|
ae52de5ad5 | ||
|
|
a485ded4bf | ||
|
|
a2d18e9111 | ||
|
|
55be316dbf | ||
|
|
a70d77aec3 | ||
|
|
f9596e96c9 | ||
|
|
6dc2c2ce97 | ||
|
|
2a8e37173a | ||
|
|
cd7f89f6bc | ||
|
|
bcad121d2b | ||
|
|
175867ea32 | ||
|
|
92a102c2d5 | ||
|
|
d19643f774 | ||
|
|
7a53ff6633 | ||
|
|
f5d2e29763 | ||
|
|
133a616572 | ||
|
|
8e081cf401 | ||
|
|
aed24a5946 | ||
|
|
66707c94d7 | ||
|
|
03b2b345ed | ||
|
|
cf08b00376 | ||
|
|
3cd428ffdb | ||
|
|
f7216ffa33 | ||
|
|
2410d4b2b9 | ||
|
|
0c3e5b5069 | ||
|
|
009034f56c | ||
|
|
9f185eef7d | ||
|
|
1c74d0e3a4 | ||
|
|
d706eb206e | ||
|
|
ff85ad7c12 | ||
|
|
731d2d0cb6 | ||
|
|
b3121aac76 | ||
|
|
ec274b2707 | ||
|
|
594abeb82b | ||
|
|
f0bb29b9d9 | ||
|
|
3245a0cd5f | ||
|
|
76d9c3d5b8 | ||
|
|
6dc00b00a4 | ||
|
|
51d158c410 | ||
|
|
7bcd2e6854 | ||
|
|
8290a05c2b | ||
|
|
8c21ca7e81 | ||
|
|
6f4de887f7 | ||
|
|
d76c63431f | ||
|
|
521d8d5bfa | ||
|
|
8a89899860 | ||
|
|
d3d0f662ef | ||
|
|
1497e6699a | ||
|
|
e3b1937aaf | ||
|
|
9bdbe70ceb | ||
|
|
4cff9dc0c1 | ||
|
|
f418fcbff0 | ||
|
|
791701165c | ||
|
|
5c9221ce61 | ||
|
|
c75ef1cd37 | ||
|
|
ae0ba6f355 | ||
|
|
d7c4e1ec93 | ||
|
|
47a1185d5d | ||
|
|
620ecedf42 | ||
|
|
e468797e41 | ||
|
|
a405fd1581 | ||
|
|
a221892f60 | ||
|
|
5ee0379be1 | ||
|
|
35f7c4e478 | ||
|
|
1419a72892 | ||
|
|
f84c78a2e1 | ||
|
|
b770ad5b19 | ||
|
|
695c6c0960 | ||
|
|
d512fe71ea | ||
|
|
733dfb288f | ||
|
|
a8d621325b | ||
|
|
1edd16dc3c | ||
|
|
c28efd0a0e | ||
|
|
b90d7d12f1 | ||
|
|
3363851781 | ||
|
|
14d6605cc9 | ||
|
|
7dd8754575 | ||
|
|
b550f70100 | ||
|
|
63c4848d11 | ||
|
|
f106382055 | ||
|
|
9eefd4d7e5 | ||
|
|
d8421f2766 | ||
|
|
feb865f9ee | ||
|
|
c318068839 | ||
|
|
90dbfcea7d | ||
|
|
861f52ff16 | ||
|
|
15ae1ac678 | ||
|
|
32350a5006 | ||
|
|
401d6472cc | ||
|
|
0b08845e3f | ||
|
|
43e1ed244f | ||
|
|
f92b104d8d | ||
|
|
aee65603ee | ||
|
|
af838b03a0 | ||
|
|
3b3a5b642c | ||
|
|
a49faa206d | ||
|
|
0eb5c7509d | ||
|
|
0d39db1109 | ||
|
|
92cf94295e | ||
|
|
7db5839608 | ||
|
|
689e9664b0 | ||
|
|
473dc89c24 | ||
|
|
05eb8d8c13 | ||
|
|
dd89964ae0 | ||
|
|
eaf37cf9e8 | ||
|
|
499f30f693 | ||
|
|
99fd479503 | ||
|
|
d530313866 | ||
|
|
8580c70172 | ||
|
|
a847326216 | ||
|
|
d3d02f4789 | ||
|
|
82a5f6ff3e | ||
|
|
c0f9fbcca5 | ||
|
|
01801e3f45 | ||
|
|
f7d3fdb195 | ||
|
|
d861002612 | ||
|
|
f133158175 | ||
|
|
310a9eabff | ||
|
|
9e8dce64fc | ||
|
|
89e9d86a56 | ||
|
|
040e6cef41 | ||
|
|
f499341558 | ||
|
|
f86f2ab3f8 | ||
|
|
6468859389 | ||
|
|
bb1a1ddb54 | ||
|
|
9ab49135c6 | ||
|
|
de7cb1c76b | ||
|
|
e7d6306b23 | ||
|
|
ec2bc2259c | ||
|
|
4123f08263 | ||
|
|
99fbbdc9c4 | ||
|
|
b619b7466f | ||
|
|
976f13d27b | ||
|
|
0c57bc8be2 | ||
|
|
c68684c2e6 | ||
|
|
80d66c9fcb | ||
|
|
a3e84343e2 | ||
|
|
4a6adee17e | ||
|
|
4bc3af0374 | ||
|
|
2d0e1dbc02 | ||
|
|
9a5acdc161 | ||
|
|
6c39b5dd52 | ||
|
|
58c19285e2 | ||
|
|
b344ea9b97 | ||
|
|
003318b911 | ||
|
|
c41db358a0 | ||
|
|
36432c9ba6 | ||
|
|
41018ff44b | ||
|
|
0d5da4bccb | ||
|
|
67caf323f7 | ||
|
|
c275cfd3da | ||
|
|
49a22dbf98 | ||
|
|
5ca513a097 | ||
|
|
4ecf2c7dd8 | ||
|
|
f7d011a955 | ||
|
|
f0b1b206cd | ||
|
|
2c69be13ea | ||
|
|
def4ed3b2a | ||
|
|
84d88ef9d7 | ||
|
|
a546729609 | ||
|
|
7dc29156fe | ||
|
|
88b5c6da2a | ||
|
|
339dc0bcd0 | ||
|
|
b7a133bd48 | ||
|
|
cd5e09303c | ||
|
|
34b6fc3ce4 | ||
|
|
1d230b88d2 | ||
|
|
6625e926fd | ||
|
|
8dab0ecf23 | ||
|
|
a372074d21 | ||
|
|
4a70eeffb0 | ||
|
|
c10d4d9a00 | ||
|
|
e733ac36bf | ||
|
|
6ef5a622af | ||
|
|
76bd16e9e3 | ||
|
|
d0a6db31a3 | ||
|
|
deed7fb56c | ||
|
|
a8f3ba8f5f | ||
|
|
5120d1263b | ||
|
|
4caa72b988 | ||
|
|
7da3c2cda2 | ||
|
|
a88871bc6a | ||
|
|
35082f788b | ||
|
|
41565073c5 | ||
|
|
337017d626 | ||
|
|
7662bbeaa5 | ||
|
|
414245c9ce | ||
|
|
cf04b59517 | ||
|
|
ddc9fd7274 | ||
|
|
30fca8e531 | ||
|
|
a066529fa5 | ||
|
|
878d0cb043 | ||
|
|
b3d797699c | ||
|
|
278ca633da | ||
|
|
74df79d4d8 | ||
|
|
e8e0af3956 | ||
|
|
818aa27a9d | ||
|
|
4deb42ed00 | ||
|
|
d00ac17e8e | ||
|
|
0de78ed02c | ||
|
|
17fa4de854 | ||
|
|
df4cf0615f | ||
|
|
11edf22776 | ||
|
|
9cb3af610a | ||
|
|
fbe8cf72a5 | ||
|
|
95e13054ca | ||
|
|
b6db182c00 | ||
|
|
6785193118 | ||
|
|
55f21192b0 | ||
|
|
12df0f0090 | ||
|
|
79cec48ba2 | ||
|
|
cc639cc44c | ||
|
|
58e31916de | ||
|
|
335fee3f36 | ||
|
|
77015d5ae3 | ||
|
|
9557d8a9b1 | ||
|
|
7992eaf0fc | ||
|
|
d12a47d558 | ||
|
|
aea132ca48 | ||
|
|
2327b8603c | ||
|
|
91d55c0e50 | ||
|
|
d00a5cfe97 | ||
|
|
ebcde562d9 | ||
|
|
188cf8d960 | ||
|
|
80856c1e34 | ||
|
|
3aa4e9ebf6 | ||
|
|
ea62c7964a | ||
|
|
6149c509ca | ||
|
|
f37a8136fe | ||
|
|
d9284c0611 | ||
|
|
19124a34f3 | ||
|
|
9a8650ec05 | ||
|
|
35d8b2bf77 | ||
|
|
afa77f8672 | ||
|
|
3d79669c5e | ||
|
|
ee9766f1db | ||
|
|
d2089dbae0 | ||
|
|
2caf8655b5 | ||
|
|
5c478a2cab | ||
|
|
df60933321 | ||
|
|
ff2737b429 | ||
|
|
edab91e576 | ||
|
|
43ea8d9179 | ||
|
|
c71f891f2e | ||
|
|
eedfcb2cbe | ||
|
|
dd86b54e6e | ||
|
|
dbbc9c41f7 | ||
|
|
140d6c8e79 | ||
|
|
7c0e823d0a | ||
|
|
f1f0d5e2d5 | ||
|
|
3848774d33 | ||
|
|
fe465bd33e | ||
|
|
83902cc984 | ||
|
|
29bff0929c | ||
|
|
3c27bc8774 | ||
|
|
ad8f1b4295 | ||
|
|
5ecae346cc | ||
|
|
2e55b68360 | ||
|
|
e046954d53 | ||
|
|
42c009e2be | ||
|
|
76d3131f48 | ||
|
|
eb385b2e70 | ||
|
|
c0fc8f93f1 | ||
|
|
67dd29a4af | ||
|
|
a6f7ca1a3a | ||
|
|
8717ed04aa | ||
|
|
7e11f08a77 | ||
|
|
045362d74a | ||
|
|
08d5f114c9 | ||
|
|
3131636492 | ||
|
|
a0f9869030 | ||
|
|
b3a8f5dc2a | ||
|
|
ce55905fb7 | ||
|
|
b6d87ad03d | ||
|
|
d305e2c35b | ||
|
|
2a6c215c45 | ||
|
|
b11a5b07c6 | ||
|
|
96d3de002d | ||
|
|
7d96440435 | ||
|
|
aaa6dd927f | ||
|
|
c48ad46aa3 | ||
|
|
da5c37517a | ||
|
|
c78ad57bb7 | ||
|
|
1be7374c28 | ||
|
|
3d0b474da9 | ||
|
|
ebd3f88798 | ||
|
|
61c77af0ab | ||
|
|
2f8c6015ba | ||
|
|
576b8a8a48 | ||
|
|
0ce234491a | ||
|
|
e2abb325df | ||
|
|
08c11a4c70 | ||
|
|
570631454d | ||
|
|
5982d4eca8 | ||
|
|
988d6a49a9 | ||
|
|
4b992717b5 | ||
|
|
869ef01f3c | ||
|
|
788cad7244 | ||
|
|
73e31653fc | ||
|
|
e007342669 | ||
|
|
7e3fd48b6a | ||
|
|
d7dccfbf82 | ||
|
|
2783a940e2 | ||
|
|
8cb3e95b39 | ||
|
|
3bc0997e28 | ||
|
|
f96077ec8d | ||
|
|
d14b6ca015 | ||
|
|
e666807a6f | ||
|
|
8686a33807 | ||
|
|
5a080c8f6e | ||
|
|
c46dc5ba2d | ||
|
|
5545aca4d7 | ||
|
|
ed294121ef | ||
|
|
2cca6fcb8b | ||
|
|
64faff8f9c | ||
|
|
30268bc40f | ||
|
|
b7b0452517 | ||
|
|
1ed16c57bc | ||
|
|
955d6af47a | ||
|
|
645bde6e57 | ||
|
|
fe54d5f5e6 | ||
|
|
044e3a4904 | ||
|
|
c1b397e48c | ||
|
|
8632901e7d | ||
|
|
98e3541333 | ||
|
|
5c9c7af198 | ||
|
|
5fe786f166 | ||
|
|
d78df28121 | ||
|
|
208fda15d5 | ||
|
|
b19c48c6c8 | ||
|
|
1464742d74 | ||
|
|
4147156707 | ||
|
|
7ad67c8b34 | ||
|
|
23fd80f2b6 | ||
|
|
5b9c07e918 | ||
|
|
fd780d43f5 | ||
|
|
ccee6fa702 | ||
|
|
efd74e6fb5 | ||
|
|
378c29bfe5 | ||
|
|
10923655d6 | ||
|
|
9a990a3591 | ||
|
|
a8b104aa74 | ||
|
|
15f2c37207 | ||
|
|
204a360602 | ||
|
|
f9d861d357 | ||
|
|
48838d5193 | ||
|
|
89fd953cc8 | ||
|
|
7ea76ffdbc | ||
|
|
0e98ab34b3 | ||
|
|
373cbc01d0 | ||
|
|
39e9278ffc | ||
|
|
9b4295b059 | ||
|
|
4528fa49f5 | ||
|
|
4925bdd4d9 | ||
|
|
a8daf2251d | ||
|
|
7eaed436c6 | ||
|
|
a63361f982 | ||
|
|
0958051391 | ||
|
|
350f608256 | ||
|
|
6416474891 | ||
|
|
da34c09128 | ||
|
|
c977616cda | ||
|
|
cafad4969c | ||
|
|
a931baa619 | ||
|
|
41826d5bd9 | ||
|
|
231a71b7fb | ||
|
|
1bcbd44ed3 | ||
|
|
72f5449e4b | ||
|
|
ea3ddc7e4f | ||
|
|
5cff9997c5 | ||
|
|
21c8284233 | ||
|
|
4dcd58724a | ||
|
|
b9522f0e78 | ||
|
|
c102397e9f | ||
|
|
8ed887456d | ||
|
|
789b639a39 | ||
|
|
30f6b1ebbc | ||
|
|
ca7ec066b2 | ||
|
|
adf3a2ce7b | ||
|
|
b3b0ff60c2 | ||
|
|
a74d911412 | ||
|
|
651cb917e7 | ||
|
|
0bb9c5de63 | ||
|
|
c5e51bca0a | ||
|
|
3d4e32bc9a | ||
|
|
53b67960a2 | ||
|
|
3df27e5ce5 | ||
|
|
ba66ccea35 | ||
|
|
7626139950 | ||
|
|
9c2468eee4 | ||
|
|
709fd9d6b4 | ||
|
|
233ab439c7 | ||
|
|
c860600c6a | ||
|
|
624aa80f84 | ||
|
|
23a0704451 | ||
|
|
b7b586ac6b | ||
|
|
cbfa0304f9 | ||
|
|
f34386ee32 | ||
|
|
0ecb96cc1b | ||
|
|
46d13ccc3b | ||
|
|
14f3548ff2 | ||
|
|
75f89c5cb6 | ||
|
|
7d81ab69e1 | ||
|
|
f976af56a4 | ||
|
|
5136270920 | ||
|
|
dd85eebf22 | ||
|
|
85f9734103 | ||
|
|
4c71ca6b5f | ||
|
|
61cba7e0e6 | ||
|
|
591a23ec8d | ||
|
|
e29ed183fc | ||
|
|
a28fdee804 | ||
|
|
71d76b0a74 | ||
|
|
9bbd933eae | ||
|
|
30a17f0bb4 | ||
|
|
f5e028bc46 | ||
|
|
3e58929e62 | ||
|
|
f17bb0cf1e | ||
|
|
ce23eb7e3a | ||
|
|
e170938ae8 | ||
|
|
6dd335ed24 | ||
|
|
fac70d7292 | ||
|
|
a6713a5c62 | ||
|
|
6e1b0ba9ac | ||
|
|
f5b8fecf2e | ||
|
|
55d89826aa | ||
|
|
8c77f7c69c | ||
|
|
265b0a9fca | ||
|
|
4fe5a010c2 | ||
|
|
978a4bb4b4 | ||
|
|
84ca1a9ef0 | ||
|
|
68cea6e952 | ||
|
|
4e477364fd | ||
|
|
9eb2deee06 | ||
|
|
3f05aebe4c | ||
|
|
b840546895 | ||
|
|
1524e3c4aa | ||
|
|
a79945b7a9 | ||
|
|
dda225b7b3 | ||
|
|
6cb7d00a03 | ||
|
|
ea627cc8f6 | ||
|
|
6b48a77141 | ||
|
|
f8e31c2dc1 | ||
|
|
6411b69af9 | ||
|
|
e2598f06fd | ||
|
|
f532c7faf8 | ||
|
|
56504fdd73 | ||
|
|
68b05c5575 | ||
|
|
03f3296046 | ||
|
|
fbcb57baf8 | ||
|
|
0643263d68 | ||
|
|
0b6c73ae83 | ||
|
|
164cb6d04e | ||
|
|
7c7fed0283 | ||
|
|
004c7124c4 | ||
|
|
8a5b25790f | ||
|
|
5a818f71d7 | ||
|
|
ee22f119de | ||
|
|
6a8583ebc4 | ||
|
|
af7cdfd82b | ||
|
|
4e7ec08939 | ||
|
|
490e271290 | ||
|
|
eb6da244cb | ||
|
|
55342151a3 | ||
|
|
bf25d3edf7 | ||
|
|
76c0dcb324 | ||
|
|
647e61cc6d | ||
|
|
104580e0bf | ||
|
|
a24ab3ae38 | ||
|
|
26526a80ea | ||
|
|
72acdac71a | ||
|
|
90465379e5 | ||
|
|
64e5467ca7 | ||
|
|
62d610f2b7 | ||
|
|
3ac5d073dc | ||
|
|
79d515c347 | ||
|
|
0c9a2e99ca | ||
|
|
00fd07336e | ||
|
|
96509c764a | ||
|
|
d7f71e7fe9 | ||
|
|
de8430d3c3 | ||
|
|
060f61ef24 | ||
|
|
5f7791474b | ||
|
|
5ff0317aa3 | ||
|
|
820da73f79 | ||
|
|
dbf69e3625 | ||
|
|
49e286509b | ||
|
|
8a58fb9402 | ||
|
|
57bc9f37c9 | ||
|
|
4df87471ca | ||
|
|
84dfdd4de6 | ||
|
|
4f19ef3cce | ||
|
|
bf4da345ec | ||
|
|
fe629829f4 | ||
|
|
8173e02272 | ||
|
|
101ec4eae1 | ||
|
|
dd673b0b5f | ||
|
|
75f98d1649 | ||
|
|
f2676adb3c | ||
|
|
6d60d22687 | ||
|
|
641919d491 | ||
|
|
d209029ca8 | ||
|
|
1000674d1c | ||
|
|
f6ed7cb271 | ||
|
|
15f15cdddb | ||
|
|
b36db3036c | ||
|
|
597ec356e3 | ||
|
|
8f41f7c7d5 | ||
|
|
e37669c3d0 | ||
|
|
bb4e592b5b | ||
|
|
47c5230c4a | ||
|
|
bb994f53cc | ||
|
|
d6c34316b1 | ||
|
|
a229f21432 | ||
|
|
cee9970c98 | ||
|
|
391e1b0a57 | ||
|
|
7e546bb91f | ||
|
|
dbe008302a | ||
|
|
b1364c5f9c | ||
|
|
f5f33771be | ||
|
|
7bb5f2124b | ||
|
|
7eeb3cfc47 | ||
|
|
c4ee880715 | ||
|
|
146b6462a3 | ||
|
|
a1777c6bcf | ||
|
|
b227b5eb76 | ||
|
|
fac4032d88 | ||
|
|
25828959d3 | ||
|
|
950f7e3cd9 | ||
|
|
8d10b757c0 | ||
|
|
cb97efc46b | ||
|
|
9c96811168 | ||
|
|
0cc7e5b0b7 | ||
|
|
92bae0b1df | ||
|
|
fdf114ab0a | ||
|
|
a3b6236289 | ||
|
|
5f45a3d1df | ||
|
|
41638e0a09 | ||
|
|
8cbb2ae7f4 | ||
|
|
5c1cb131e9 | ||
|
|
4b127e229b | ||
|
|
b33779fbbe | ||
|
|
c8e52f9e15 | ||
|
|
cd0512befd | ||
|
|
0317db97cd | ||
|
|
a2a71fe705 | ||
|
|
b4fbd4abe4 | ||
|
|
8161adafd3 | ||
|
|
f719306f68 | ||
|
|
e86dee3200 | ||
|
|
7e50a39773 | ||
|
|
213368e21f | ||
|
|
4d88c124b1 | ||
|
|
b6f268c113 | ||
|
|
e03658ee07 | ||
|
|
a83583e926 | ||
|
|
6fd394811c | ||
|
|
eb51d4f68b | ||
|
|
7a93100c2d | ||
|
|
03fdabaaac | ||
|
|
1f378efbf0 | ||
|
|
53b7ce5b22 | ||
|
|
ea3e49f4e2 | ||
|
|
832af8c1b0 | ||
|
|
6f449ff098 | ||
|
|
ca3d4db1e3 | ||
|
|
1f84e5ac57 | ||
|
|
caf14c53db | ||
|
|
85ecae2875 | ||
|
|
66add57aa5 | ||
|
|
6cacbd9575 | ||
|
|
e69b222d53 | ||
|
|
2fb13f9b65 | ||
|
|
dee85e5a00 | ||
|
|
1743395250 | ||
|
|
214407d9c7 | ||
|
|
0682afece8 | ||
|
|
39363e4e01 | ||
|
|
c7bbd9ac71 | ||
|
|
c4d172da76 | ||
|
|
8c1ec4f0e1 | ||
|
|
d70dac5e49 | ||
|
|
20f0744f39 | ||
|
|
a975b925ba | ||
|
|
2ae1f18d1f | ||
|
|
01f25b5aeb | ||
|
|
850121f255 | ||
|
|
6f73d44fab | ||
|
|
7d61acebd8 | ||
|
|
851f9b2d6c | ||
|
|
9f9c56d6bc | ||
|
|
d019dcf195 | ||
|
|
0d327e9e40 | ||
|
|
3ccbaf336d | ||
|
|
3368bb5a81 | ||
|
|
ae719b2706 | ||
|
|
5ee99a7e80 | ||
|
|
2f3dc12ad7 | ||
|
|
a8f1307992 | ||
|
|
1de959ca1c | ||
|
|
55c39bae67 | ||
|
|
18b5a88a8a | ||
|
|
abeee8b4c2 | ||
|
|
f1864e3e92 | ||
|
|
154d8241c9 | ||
|
|
c5ad875a79 | ||
|
|
de6d69cc60 | ||
|
|
e8240209fe | ||
|
|
9ba80f08f4 | ||
|
|
5df0a88e01 | ||
|
|
adbe3ac817 | ||
|
|
b2a13907a8 | ||
|
|
a644bc11a5 | ||
|
|
c4ac70570a | ||
|
|
9d5921443c | ||
|
|
88c91b4663 | ||
|
|
bd7d019b56 | ||
|
|
4866c8ed25 | ||
|
|
e784db4fdd | ||
|
|
18fd79e578 | ||
|
|
510ad74ea9 | ||
|
|
1c28cbab02 | ||
|
|
b0d04ab6c6 | ||
|
|
573d9a0368 | ||
|
|
c34a854465 | ||
|
|
60fdeb057a | ||
|
|
70d80bba5a | ||
|
|
b0acd78511 | ||
|
|
dd91692fee | ||
|
|
8f56912fc2 | ||
|
|
39f76220a8 | ||
|
|
773ebb6bba | ||
|
|
4b9f6fcdb7 | ||
|
|
479a65e946 | ||
|
|
447a615dc3 | ||
|
|
002fdcf016 | ||
|
|
843023f9ff | ||
|
|
caf214935a | ||
|
|
fa2fcbe416 | ||
|
|
666167138f | ||
|
|
7372da95be | ||
|
|
2fb843773b | ||
|
|
9b7bd65883 | ||
|
|
90ff84a2dd | ||
|
|
ee8a080cea | ||
|
|
5fbfbec86b | ||
|
|
23de60e6bd | ||
|
|
a247833a5a | ||
|
|
0ebf92b45c | ||
|
|
779c44125a | ||
|
|
f6fd9bc823 | ||
|
|
7395ca92d4 | ||
|
|
efa79144f3 | ||
|
|
f29b2da658 | ||
|
|
2b90372b79 | ||
|
|
6be91c28ca | ||
|
|
0f3ab30087 | ||
|
|
d35a4b005e | ||
|
|
f13f52d303 | ||
|
|
5376bfd21c | ||
|
|
66db8e7bb4 | ||
|
|
97a5e7a608 | ||
|
|
16d497449a | ||
|
|
5b4679618a | ||
|
|
837555ab24 | ||
|
|
48d9f3bbde | ||
|
|
2c89a1ec5f | ||
|
|
e5afb14241 | ||
|
|
605c791cb2 | ||
|
|
dcdf71c21b | ||
|
|
9997362a2a | ||
|
|
09a3cc0980 | ||
|
|
24243b2b7a | ||
|
|
6f7d3c9d5b | ||
|
|
40b806bfe7 | ||
|
|
713854f714 | ||
|
|
5dbf973910 | ||
|
|
4f0bd8e8e1 | ||
|
|
55ebb067d1 | ||
|
|
d2d75efb39 | ||
|
|
81f9e0a0bc | ||
|
|
e6b164c685 | ||
|
|
2710aba701 | ||
|
|
c401b8dd4f | ||
|
|
d1ab0a9698 | ||
|
|
a2c1cbe3e3 | ||
|
|
40580e2d71 | ||
|
|
7989000e09 | ||
|
|
486799e65b | ||
|
|
f1bca5898c | ||
|
|
8ac5bd7030 | ||
|
|
a6f953babc | ||
|
|
a88532bc60 | ||
|
|
7d6b4b42f6 | ||
|
|
dd6912b1e5 | ||
|
|
c1893c416b | ||
|
|
0bba832713 | ||
|
|
13de2d2fef | ||
|
|
cfd1227e34 | ||
|
|
c257228048 | ||
|
|
0bc7d2c692 | ||
|
|
1552562b3a | ||
|
|
ba4e2c43fb | ||
|
|
699d246b1c | ||
|
|
aed582e422 | ||
|
|
47a81338a5 | ||
|
|
9646f21ad8 | ||
|
|
3723558cbd | ||
|
|
d94163afc7 | ||
|
|
8813a9ec16 | ||
|
|
ffb73fe1d6 | ||
|
|
bf41e298c5 | ||
|
|
3725fded17 | ||
|
|
c3d96a3a6e | ||
|
|
f481deb58f | ||
|
|
3f427b90e0 | ||
|
|
9a6c3cc87f | ||
|
|
25047d4980 | ||
|
|
1262735a0c | ||
|
|
c008618be9 | ||
|
|
923293928a | ||
|
|
2b05549d59 | ||
|
|
231b882022 | ||
|
|
03caa01ae5 | ||
|
|
d2189fdfe6 | ||
|
|
f7f37ea289 | ||
|
|
9d3d3297ae | ||
|
|
8a7a9bd17a | ||
|
|
ea4b83332e | ||
|
|
4729bae363 | ||
|
|
bda849d033 | ||
|
|
0cfcd0bc9b | ||
|
|
2b8aa1d058 | ||
|
|
ec0303be34 | ||
|
|
8b7cd9322a | ||
|
|
39423e9856 | ||
|
|
1297f6750d | ||
|
|
0b26e59b01 | ||
|
|
5af8bc1ac4 | ||
|
|
af6d1db2fb | ||
|
|
9f2a76e7b6 | ||
|
|
cf10427caa | ||
|
|
c13924e32c | ||
|
|
ae62743a4c | ||
|
|
8ea1bc666d | ||
|
|
90815705d7 | ||
|
|
cbc1f23758 | ||
|
|
96413087dc | ||
|
|
e841dfc149 | ||
|
|
f593dad542 | ||
|
|
9833ef8580 | ||
|
|
7f1b58a5cd | ||
|
|
a861624233 | ||
|
|
fb59d0fa55 | ||
|
|
b28d1cf0e4 | ||
|
|
e211e4c6d2 | ||
|
|
0a85c3426b | ||
|
|
7a731eb637 | ||
|
|
0f3c9f8f06 | ||
|
|
86c0f4cafc | ||
|
|
a8bd749d4e | ||
|
|
8d772cad7a | ||
|
|
2f184a5008 | ||
|
|
623100d59d | ||
|
|
260daf9d59 | ||
|
|
6853abeb90 | ||
|
|
9f1ba4b34b | ||
|
|
3822831792 | ||
|
|
f8c97a5d2e | ||
|
|
19ce96746d | ||
|
|
10edfff05a | ||
|
|
2e8f1911d6 | ||
|
|
857e9cb076 | ||
|
|
630af1be56 | ||
|
|
58f4bd4a3c | ||
|
|
6874a83fed | ||
|
|
39d80bad9b | ||
|
|
ba9d608df3 | ||
|
|
bde750291a | ||
|
|
bb0d7ab12a | ||
|
|
4d3b6e4163 | ||
|
|
b7593457bc | ||
|
|
2136238908 | ||
|
|
3fb2c6a6dd | ||
|
|
ca8c6cf430 | ||
|
|
2e160c6bad | ||
|
|
e77ae9096a | ||
|
|
725749de20 | ||
|
|
5a90a66aa3 | ||
|
|
6d06c893d1 | ||
|
|
ab9dfffdb5 | ||
|
|
6c0e48248a | ||
|
|
6c39552316 | ||
|
|
ce1a29725f | ||
|
|
51f8b70904 | ||
|
|
64e53c4fd8 | ||
|
|
d5209daeb1 | ||
|
|
6f612fb959 | ||
|
|
a79adf1383 | ||
|
|
4dcad08940 | ||
|
|
44a7b25487 |
65
.gitignore
vendored
Normal file
65
.gitignore
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# stuff "git status" should ignore
|
||||
|
||||
# build output
|
||||
.libs
|
||||
.deps
|
||||
*.o
|
||||
*.a
|
||||
*.lo
|
||||
*.la
|
||||
*.in
|
||||
|
||||
# editor files
|
||||
*.swp
|
||||
|
||||
startup_tcl.c
|
||||
xscale_debug.h
|
||||
|
||||
bin2char
|
||||
bin2char.exe
|
||||
|
||||
doc/openocd.aux
|
||||
doc/openocd.cp
|
||||
doc/openocd.cps
|
||||
doc/openocd.fn
|
||||
doc/openocd.fns
|
||||
doc/openocd.html
|
||||
doc/openocd.info
|
||||
doc/openocd.info-1
|
||||
doc/openocd.info-2
|
||||
doc/openocd.ky
|
||||
doc/openocd.log
|
||||
doc/openocd.pdf
|
||||
doc/openocd.pg
|
||||
doc/openocd.toc
|
||||
doc/openocd.tp
|
||||
doc/openocd.vr
|
||||
doc/texinfo.tex
|
||||
doc/version.texi
|
||||
src/openocd
|
||||
src/openocd.exe
|
||||
|
||||
# configure/autotools output
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
compile
|
||||
config.*
|
||||
configure
|
||||
depcomp
|
||||
doxygen
|
||||
doxygen.log
|
||||
Doxyfile
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
Makefile
|
||||
mdate-sh
|
||||
missing
|
||||
stamp-h1
|
||||
stamp-vti
|
||||
INSTALL
|
||||
NOTES
|
||||
|
||||
# Eclipse stuff
|
||||
.project
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "tools/git2cl"]
|
||||
path = tools/git2cl
|
||||
url = git://repo.or.cz/git2cl.git
|
||||
5
AUTHORS
5
AUTHORS
@@ -5,3 +5,8 @@ Spencer Oliver <spen@spen-soft.co.uk>
|
||||
Carsten Schlote <schlote@vahanus.net>
|
||||
Øyvind Harboe <oyvind.harboe@zylin.com>
|
||||
Duane Ellis <openocd@duaneellis.com>
|
||||
Michael Schwingen <michael@schwingen.org>
|
||||
Rick Altherr <kc8apf@users.berlios.de>
|
||||
David Brownell <dbrownell@users.sourceforge.net>
|
||||
Vincint Palatin <vpalatin@users.berlios.de>
|
||||
Zachary T Welch <zw@superlucidity.net>
|
||||
|
||||
10
AUTHORS.ChangeLog
Normal file
10
AUTHORS.ChangeLog
Normal file
@@ -0,0 +1,10 @@
|
||||
drath:Dominic Rath <Dominic.Rath@gmx.de>
|
||||
mlu:Magnus Lundin <lundin@mlu.mine.nu>
|
||||
mifi:Michael Fischer <fischermi@t-online.de>
|
||||
ntfreak:Spencer Oliver <spen@spen-soft.co.uk>
|
||||
duane:Duane Ellis <openocd@duaneellis.com>
|
||||
oharboe:Øyvind Harboe <oyvind.harboe@zylin.com>
|
||||
kc8apf:Rick Altherr <kc8apf@users.berlios.de>
|
||||
zwelch:Zachary T Welch <zw@superlucidity.net>
|
||||
vpalatin:Vincent Palatin <vpalatin@users.berlios.de>
|
||||
bodylove:Carsten Schlote <schlote@vahanus.net>
|
||||
71
BUGS
71
BUGS
@@ -1,34 +1,67 @@
|
||||
Please report bugs by posting a message to
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
/** @page bugs Bug Reporting
|
||||
|
||||
openocd-development@lists.berlios.de.
|
||||
Please report bugs by subscribing to the OpenOCD mailing list and
|
||||
posting a message with your report:
|
||||
|
||||
To minimize work for OpenOCD developers, you can include
|
||||
all the information below. If you feel that some of the
|
||||
items below are unecessary for a clear bug report, you
|
||||
leave them out.
|
||||
openocd-development@lists.berlios.de
|
||||
|
||||
To minimize work for OpenOCD developers, you should try to include
|
||||
all of the information listed below. If you feel that some of the
|
||||
items below are unnecessary for a clear bug report, you may leave
|
||||
them out; likewise, feel free to include additional information
|
||||
that may be important.
|
||||
|
||||
- Target PCB/board description
|
||||
- Config scripts
|
||||
- Configuration scripts
|
||||
- OpenOCD command line
|
||||
- List of commands issued or GDB operations performed
|
||||
- Expected result
|
||||
- Actual result
|
||||
- debug_level 3 logs
|
||||
- If this is a regression, include logs for working and broken
|
||||
version
|
||||
- If this is a regression, please find out the precise version
|
||||
that caused the regression. This can be done via a binary
|
||||
search. E.g. if version 550 worked and 600 failed, then try
|
||||
575, etc.
|
||||
- Logs using <code>debug_level 3</code> (or with '-d 3' on the command line)
|
||||
- If the report is for a regression:
|
||||
- Include logs for both working and broken versions.
|
||||
- Find the precise version that caused the regression by binary search.
|
||||
You can use "git bisect" to expedite this binary search.
|
||||
|
||||
- If OpenOCD is crashing, you can use GDB to get a trace:
|
||||
If possible, please develop and attach a patch that helps to expose or
|
||||
solve the reported problem. See the PATCHES file for more information
|
||||
for that process.
|
||||
|
||||
gdb --args openocd ....
|
||||
Attach all files directly to your posting. The mailing list knows to
|
||||
transform attachments to links, but attachments must be less than 300KB
|
||||
in total.
|
||||
|
||||
@section bugscrashdump Obtaining Crash Backtraces
|
||||
|
||||
If OpenOCD is crashing, there are two very effective things you can do to
|
||||
improve your chances of getting help on the development mailing list.
|
||||
|
||||
Try to reproduce the problem using the dummy JTAG interface to allow other developers to replicate
|
||||
your problem robustly and use GDB to get a trace:@par
|
||||
@code
|
||||
% OPENOCDSRC/configure --enable-dummy ...
|
||||
% openocd -f interface/dummy.cfg -f target/xxx.cfg
|
||||
=> SEGFAULT
|
||||
% gdb --args openocd ....
|
||||
(gdb) run
|
||||
(gdb) bt
|
||||
=> here a stack trace is dumped.
|
||||
@endcode
|
||||
|
||||
attach files directly to the posting. The mailing list knows to
|
||||
transform attachments to links so you will not be bloating anyones
|
||||
mail box. Keep attachments to <100kBytes.
|
||||
@section bugsintreedebug Running and Debugging In-Tree
|
||||
|
||||
To run or debug the in-tree executable (not recommended), you must
|
||||
use libtool to set up the correct shared library paths:
|
||||
@code
|
||||
libtool gdb --args openocd ....
|
||||
@endcode
|
||||
or the more pedantic (and forward-compatible):
|
||||
@code
|
||||
libtool --mode=execute gdb --args openocd ....
|
||||
@endcode
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref bugs page.
|
||||
*/
|
||||
|
||||
1517
Doxyfile.in
Normal file
1517
Doxyfile.in
Normal file
File diff suppressed because it is too large
Load Diff
73
Makefile.am
73
Makefile.am
@@ -1,6 +1,6 @@
|
||||
# not a GNU package. You can remove this line, if
|
||||
# have all needed files, that a GNU package needs
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
AUTOMAKE_OPTIONS = gnu 1.6
|
||||
|
||||
nobase_dist_pkgdata_DATA = \
|
||||
contrib/libdcc/dcc_stdio.c \
|
||||
@@ -11,13 +11,66 @@ nobase_dist_pkgdata_DATA = \
|
||||
|
||||
SUBDIRS = src doc
|
||||
|
||||
EXTRA_DIST = \
|
||||
Doxyfile.in \
|
||||
tools/logger.pl
|
||||
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
docs: pdf html doxygen
|
||||
|
||||
Doxyfile: $(srcdir)/Doxyfile.in
|
||||
@echo "Creating $@ from $<..."
|
||||
@( \
|
||||
echo "### @@@ -= DO NOT EDIT THIS FILE =- @@@ ###" && \
|
||||
echo "### @@@ Make changes to Doxyfile.in @@@ ###" && \
|
||||
sed -e 's,@srcdir\@,$(srcdir),' $< \
|
||||
) > $@
|
||||
|
||||
doxygen::
|
||||
$(MAKE) Doxyfile
|
||||
doxygen Doxyfile 2>&1 | perl $(srcdir)/tools/logger.pl > doxygen.log
|
||||
|
||||
TCL_PATH = tcl
|
||||
# command to find paths of script files, relative to TCL_PATH
|
||||
TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' | \
|
||||
sed -e 's,^$(srcdir)/$(TCL_PATH),,'
|
||||
|
||||
dist-hook:
|
||||
for i in $$($(TCL_FILES)); do \
|
||||
j="$(distdir)/$(TCL_PATH)/$$i" && \
|
||||
mkdir -p "$$(dirname $$j)" && \
|
||||
$(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \
|
||||
done
|
||||
|
||||
install-data-hook:
|
||||
for i in $$($(TCL_FILES)); do \
|
||||
j="$(DESTDIR)$(pkgdatadir)/scripts/$$i" && \
|
||||
mkdir -p "$$(dirname $$j)" && \
|
||||
$(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \
|
||||
done
|
||||
|
||||
uninstall-hook:
|
||||
rm -rf $(DESTDIR)$(pkgdatadir)/scripts
|
||||
|
||||
|
||||
distclean-local:
|
||||
rm -rf Doxyfile doxygen
|
||||
|
||||
DISTCLEANFILES = doxygen.log
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
configure \
|
||||
Makefile.in \
|
||||
depcomp \
|
||||
config.guess \
|
||||
config.sub \
|
||||
config.h.in \
|
||||
missing \
|
||||
aclocal.m4 \
|
||||
install-sh
|
||||
$(srcdir)/INSTALL \
|
||||
$(srcdir)/configure \
|
||||
$(srcdir)/Makefile.in \
|
||||
$(srcdir)/depcomp \
|
||||
$(srcdir)/config.guess \
|
||||
$(srcdir)/config.sub \
|
||||
$(srcdir)/config.h.in \
|
||||
$(srcdir)/config.h.in~ \
|
||||
$(srcdir)/compile \
|
||||
$(srcdir)/ltmain.sh \
|
||||
$(srcdir)/missing \
|
||||
$(srcdir)/aclocal.m4 \
|
||||
$(srcdir)/install-sh
|
||||
|
||||
59
NEWS
59
NEWS
@@ -1 +1,58 @@
|
||||
This document is not in use. See mailing list - https://lists.berlios.de/pipermail/openocd-development
|
||||
This file should include highlights of the changes made in the
|
||||
OpenOCD openocd-0.3.0 source archive release. See the repository
|
||||
history for details about what changed, including bugfixes and
|
||||
other issues not mentioned here.
|
||||
|
||||
JTAG Layer:
|
||||
FT2232H (high speed USB) support doesn't need separate configuration
|
||||
New reset_config options for SRST gating the JTAG clock (or not)
|
||||
TAP declaration no longer requires ircapture and mask attributes
|
||||
New "post-reset" event handler for TAP-invariant setup code
|
||||
Overridable Tcl "init_reset" and "jtag_init" procedures
|
||||
|
||||
Target Layer:
|
||||
New commands for use with Cortex-M3 processors:
|
||||
"cortex_m3 disassemble" ... Thumb2 disassembly (UAL format)
|
||||
"cortex_m3 vector_catch" ... traps certain hardware faults
|
||||
without tying up breakpoint resources
|
||||
If you're willing to help debug it
|
||||
VERY EARLY Cortex-A8 and ARMv7A support
|
||||
Updated BeagleBoard.org hardware support
|
||||
New commands for use with XScale processors: "xscale vector_table"
|
||||
ARM9
|
||||
name change: "arm9 vector_catch" not "arm9tdmi vector_catch"
|
||||
ARM11
|
||||
single stepping support for i.MX31
|
||||
bugfix for missing "arm11" prefix on "arm11 memwrite ..."
|
||||
ETM support
|
||||
Unavailable registers are not listed
|
||||
|
||||
Flash Layer:
|
||||
The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips
|
||||
New lpc2900 driver for NXP LPC2900 chips (ARM968 based)
|
||||
New "last" flag for NOR "flash erase_sector" and "flash protect"
|
||||
The "nand erase N" command now erases all of bank N
|
||||
|
||||
Board, Target, and Interface Configuration Scripts:
|
||||
Amontec JTAGkey2 support
|
||||
Cleanup and additions for the TI/Luminary Stellaris scripts
|
||||
LPC1768 target (and flash) support
|
||||
Keil MCB1700 eval board
|
||||
Samsung s3c2450
|
||||
Mini2440 board
|
||||
Numeric TAP and Target identifiers now trigger warnings
|
||||
PXA255 partially enumerates
|
||||
|
||||
Documentation:
|
||||
Capture more debugging and setup advice
|
||||
Notes on target source code changes that may help debugging
|
||||
|
||||
Build and Release:
|
||||
|
||||
For more details about what has changed since the last release,
|
||||
see the ChangeLog associated with this source archive. For older NEWS,
|
||||
see the NEWS files associated with each release (i.e. NEWS-<version>).
|
||||
|
||||
For more information about contributing test reports, bug fixes, or new
|
||||
features and device support, please read the new Developer Manual (or
|
||||
the BUGS and PATCHES files in the source archive).
|
||||
|
||||
80
NEWS-0.2.0
Normal file
80
NEWS-0.2.0
Normal file
@@ -0,0 +1,80 @@
|
||||
The OpenOCD 0.2.0 source archive release includes numerous improvements
|
||||
that were made since the initial 0.1.0 source archive release. Many
|
||||
contributors helped make this release a great success, and the community
|
||||
of developers and maintainers look forward to any response.
|
||||
|
||||
In addition to the list of changes below, countless bug fixing and
|
||||
cleaning was performed across the tree. Various TCL command parameters
|
||||
must past stricter value checks, and many more error conditions have
|
||||
been handled correctly. These efforts helped to make the 0.2.0 release
|
||||
more stable and robust, though some changes may expose latent bugs in
|
||||
your existing configuration scripts.
|
||||
|
||||
This release does not maintain backward compatibility in all respects,
|
||||
so some target or configuration scripts may need to be updated. In some
|
||||
cases, you may also see warnings; resolve those, because they indicate
|
||||
commands that will be removed in the future.
|
||||
|
||||
The following areas of OpenOCD functionality changed in this release:
|
||||
|
||||
JTAG Layer:
|
||||
- Improves modularity: core, TCL, driver commands, and interface have
|
||||
been separated, encapsulated, and documented for developers. Mostly.
|
||||
- Improves JTAG TAP transition tables:
|
||||
* Makes TAP paths variable length, rather than being fixed at 7 steps.
|
||||
* Fixes problems with some targets that did not like longer paths.
|
||||
- Improves JTAG driver/minidriver modularity and encapsulation.
|
||||
- New drivers:
|
||||
* Adds stub minidriver for developing new embedded JTAG interfaces.
|
||||
- Improves drivers:
|
||||
* ft2232+ftd2xx:
|
||||
+ Adds initial high-speed device support: --enable-ftd2xx-highspeed
|
||||
+ Supports more types of FTDI-based devices.
|
||||
* jlink:
|
||||
+ Works with more versions of the firmware (v3 and newer)
|
||||
+ Supports dynamically detects device capabilities and limits
|
||||
* vsllink:
|
||||
+ Supports very long scan chains
|
||||
* amtjtagaccel:
|
||||
+ Fixes broken ID code detection problems.
|
||||
|
||||
Target Layer:
|
||||
- New devices: AVR, FA526
|
||||
- Improved support: ARM ADI, ARM11, MIPS
|
||||
- Numerous other bug fixes and improvements
|
||||
|
||||
Flash Layer:
|
||||
- Improved drivers: mflash
|
||||
- New drivers: AT91SAM3, AVR, Davinci NAND
|
||||
|
||||
Board, Interface, and Target Configuration Scripts:
|
||||
- Many new and improved targets and boards are now available.
|
||||
- Better separation of "board" and "target" configuration
|
||||
- Moved all TCL files to top-level "tcl" directory in the source tree
|
||||
- Installation moved from '$pkglibdir/' to '$pkgdatadir/scripts/'.
|
||||
- Site-specific files should be installed under '$pkgdatadir/site/';
|
||||
files that exist this tree will be used in preference to default
|
||||
distribution configurations in '$pkgdatadir/scripts/'.
|
||||
|
||||
Documentation:
|
||||
- Updated User Guide: http://openocd.berlios.de/doc/html/index.html
|
||||
* Partially re-written and re-organized.
|
||||
* Standardized presentation for all commands.
|
||||
* Covers many drivers and commands that were previously omitted.
|
||||
* New index for commands and drivers.
|
||||
- Added Developer Manual: http://openocd.berlios.de/doc/doxygen/index.html
|
||||
* Now includes architecture, technical primers, style guides, and more.
|
||||
* Available in-tree and on-line.
|
||||
|
||||
Build and Release:
|
||||
- Increased configuration and compilation warning coverage.
|
||||
* Use --disable-werror to work around build errors caused by warnings.
|
||||
- Use libtool to produce helper libraries as a step toward "libopenocd".
|
||||
- New processes and scripting to facilitate future source releases.
|
||||
|
||||
For more details about what has changed since 0.1.0, see the ChangeLog
|
||||
associated with this release.
|
||||
|
||||
For more information about contributing test reports, bug fixes, or new
|
||||
features and device support, please read the new Developer Manual (or
|
||||
the BUGS and PATCHES files in the source archive).
|
||||
49
PATCHES
49
PATCHES
@@ -1,28 +1,47 @@
|
||||
Please mail patches to:
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
/** @page patchguide Patch Guidelines
|
||||
|
||||
openocd-development@lists.berlios.de
|
||||
Please mail patches to: @par
|
||||
openocd-development@lists.berlios.de
|
||||
|
||||
The patch should be against svn trunk using an SVN
|
||||
diff.
|
||||
Note that you can't send patches to that list unless
|
||||
you're a member, despite what the list info page says.
|
||||
|
||||
@section Patch Guidelines in a Nutshell
|
||||
|
||||
Your patches should be against git mainline. Submit output
|
||||
of "git diff"; equivalently, quilt patches are OK.
|
||||
|
||||
It should be a "good patch": focus it on a single
|
||||
issue, and make it be easily reviewable. Don't make
|
||||
it so large that it's hard to review; split large
|
||||
patches into smaller ones. (That can also help
|
||||
track down bugs later on.) All patches should
|
||||
be "clean", which includes preserving the existing
|
||||
coding style and updating documentation as needed.j
|
||||
|
||||
Attach the patch to the email as a .txt file and
|
||||
also write a short change log entry that maintainers
|
||||
can copy and paste into the commit message
|
||||
|
||||
Say if it's a bugfix (describe the bug) or a new
|
||||
feature. Don't expect patches to merge immediately
|
||||
for the next release. Be ready to rework patches
|
||||
in response to feedback.
|
||||
|
||||
Add yourself to the GPL copyright for non-trivial changes.
|
||||
|
||||
To create a patch from the command line:
|
||||
@code
|
||||
git diff >mypatch.txt
|
||||
@endcode
|
||||
|
||||
svn diff >mypatch.txt
|
||||
@section More Information on Patching
|
||||
|
||||
http://svnbook.red-bean.com/en/1.0/re09.html
|
||||
|
||||
NB! remember to use "svn add" on new files first!
|
||||
|
||||
http://svnbook.red-bean.com/en/1.0/re01.html
|
||||
|
||||
|
||||
|
||||
If you have a decent SVN GUI, then that should be
|
||||
able to create and apply patches as well...
|
||||
The @ref primerpatches provides a more complete guide to creating,
|
||||
managing, and contributing patches to the OpenOCD project.
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref patchguide page.
|
||||
*/
|
||||
|
||||
422
README
422
README
@@ -1,2 +1,422 @@
|
||||
openocd.texi is the authoritative source of OpenOCD documentation
|
||||
Welcome to OpenOCD!
|
||||
===================
|
||||
|
||||
OpenOCD provides on-chip programming and debugging support with a
|
||||
layered architecture of JTAG interface and TAP support, debug target
|
||||
support (e.g. ARM, MIPS), and flash chip drivers (e.g. CFI, NAND, etc.).
|
||||
Several network interfaces are available for interactiving with OpenOCD:
|
||||
HTTP, telnet, TCL, and GDB. The GDB server enables OpenOCD to function
|
||||
as a "remote target" for source-level debugging of embedded systems
|
||||
using the GNU GDB program.
|
||||
|
||||
This README file contains an overview of the following topics:
|
||||
- how to find and build more OpenOCD documentation,
|
||||
- the build process
|
||||
- packaging tips.
|
||||
- configuration options
|
||||
|
||||
=====================
|
||||
OpenOCD Documentation
|
||||
=====================
|
||||
|
||||
In addition to in-tree documentation, the latest documentation may be
|
||||
viewed on-line at the following URLs:
|
||||
|
||||
OpenOCD User's Guide:
|
||||
http://openocd.berlios.de/doc/html/index.html
|
||||
|
||||
OpenOCD Developer's Manual:
|
||||
http://openocd.berlios.de/doc/doxygen/index.html
|
||||
|
||||
These reflect the latest development versions, so the following section
|
||||
introduces how to build the complete documentation from the package.
|
||||
|
||||
|
||||
For more information, refer to these documents or contact the developers
|
||||
by subscribing to the OpenOCD developer mailing list:
|
||||
|
||||
openocd-development@lists.berlios.de
|
||||
|
||||
Building the OpenOCD Documentation
|
||||
----------------------------------
|
||||
|
||||
The OpenOCD User's Guide can be produced in two different format:
|
||||
|
||||
# If PDFVIEWER is set, this creates and views the PDF User Guide.
|
||||
make pdf && ${PDFVIEWER} doc/openocd.pdf
|
||||
|
||||
# If HTMLVIEWER is set, this creates and views the HTML User Guide.
|
||||
make html && ${HTMLVIEWER} doc/openocd.html/index.html
|
||||
|
||||
The OpenOCD Developer Manual contains information about the internal
|
||||
architecture and other details about the code:
|
||||
|
||||
# NB! make sure doxygen is installed, type doxygen --version
|
||||
make doxygen
|
||||
|
||||
# If HTMLVIEWER is set, this views the HTML Doxygen output.
|
||||
${HTMLVIEWER} doxygen/index.html
|
||||
|
||||
The remaining sections describe how to configure the system such that
|
||||
you can build the in-tree documentation.
|
||||
|
||||
==================
|
||||
Installing OpenOCD
|
||||
==================
|
||||
|
||||
On Linux, you may have permissions problems to address. The best
|
||||
way to do this is to use the contrib/udev.rules file. It probably
|
||||
belongs somewhere in /etc/udev/rules.d, but consult your operating
|
||||
system documentation to be sure. In particular, make sure that it
|
||||
matches the syntax used by your operating system's version of udev.
|
||||
|
||||
A Note to OpenOCD Users
|
||||
-----------------------
|
||||
|
||||
If you would rather be working "with" OpenOCD rather than "on" it, your
|
||||
operating system or JTAG interface supplier may provide binaries for
|
||||
you in a convenient-enough package.
|
||||
|
||||
Such packages may be more stable than git mainline, where bleeding-edge
|
||||
development takes place. These "Packagers" produce binary releases of
|
||||
OpenOCD after the developers produces new "release" versions of the
|
||||
source code. Previous versions of OpenOCD cannot be used to diagnose
|
||||
problems with the current release, so users are encouraged to keep in
|
||||
contact with their distribution package maintainers or interface vendors
|
||||
to ensure suitable upgrades appear regularly.
|
||||
|
||||
Users of these binary versions of OpenOCD must contact their Packager to
|
||||
ask for support or newer versions of the binaries; the OpenOCD
|
||||
developers do not support packages directly.
|
||||
|
||||
A Note to OpenOCD Packagers
|
||||
---------------------------
|
||||
|
||||
You are a PACKAGER of OpenOCD if you:
|
||||
|
||||
- Sell dongles: and include pre-built binaries
|
||||
- Supply tools: A complete development solution
|
||||
- Supply IDEs: like Eclipse, or RHIDE, etc.
|
||||
- Build packages: RPM files, or DEB files for a Linux Distro
|
||||
|
||||
As a PACKAGER, you will experience first reports of most issues.
|
||||
When you fix those problems for your users, your solution may help
|
||||
prevent hundreds (if not thousands) of other questions from other users.
|
||||
|
||||
If something does not work for you, please work to inform the OpenOCD
|
||||
developers know how to improve the system or documentation to avoid
|
||||
future problems, and follow-up to help us ensure the issue will be fully
|
||||
resolved in our future releases.
|
||||
|
||||
That said, the OpenOCD developers would also like you to follow a few
|
||||
suggestions:
|
||||
|
||||
- Send patches, including config files, upstream.
|
||||
- Always build with printer ports enabled.
|
||||
- Use libftdi + libusb for FT2232 support.
|
||||
|
||||
Remember, the FTD2XX library cannot be used in binary distributions, due
|
||||
to restrictions of the GPL v2.
|
||||
|
||||
================
|
||||
Building OpenOCD
|
||||
================
|
||||
|
||||
The INSTALL file contains generic instructions for running 'configure'
|
||||
and compiling the OpenOCD source code. That file is provided by default
|
||||
for all GNU automake packages. If you are not familiar with the GNU
|
||||
autotools, then you should read those instructions first.
|
||||
|
||||
The remainder of this document tries to provide some instructions for
|
||||
those looking for a quick-install.
|
||||
|
||||
OpenOCD Dependencies
|
||||
--------------------
|
||||
|
||||
Presently, GCC is required to build OpenOCD. The developers have begun
|
||||
to enforce strict code warnings (-Wall, -Werror, -Wextra, and more) and
|
||||
use C99-specific features: inline functions, named initializers, mixing
|
||||
declarations with code, and other tricks. While it may be possible to
|
||||
use other compilers, they must be somewhat modern and could require
|
||||
extending support to conditionally remove GCC-specific extensions.
|
||||
|
||||
Also, you need to install the appropriate driver files, if you want to
|
||||
build support for a USB or FTDI-based interface:
|
||||
|
||||
- ft2232, jlink, rlink, vsllink, usbprog, arm-jtag-ew:
|
||||
- libusb: required for portable communication with USB dongles
|
||||
- ft2232 also requires:
|
||||
- libftdi: http://www.intra2net.com/opensource/ftdi/ *OR*
|
||||
- ftd2xx: http://www.ftdichip.com/Drivers/D2XX.htm,
|
||||
or the Amontec version (from http://www.amontec.com), for
|
||||
easier support of JTAGkey's vendor and product IDs.
|
||||
|
||||
Many Linux distributions provide these packages through their automated
|
||||
installation and update mechanisms; however, some Linux versions include
|
||||
older versions of libftdi. In particular, using Ubuntu 8.04 has been
|
||||
problematic, but newer versions of Ubuntu do not have this problem.
|
||||
|
||||
Compiling OpenOCD
|
||||
-----------------
|
||||
|
||||
To build OpenOCD (on both Linux and Cygwin), use the following sequence
|
||||
of commands:
|
||||
|
||||
./configure [with some options listed in the next section]
|
||||
make
|
||||
make install
|
||||
|
||||
The 'configure' step generates the Makefiles required to build OpenOCD,
|
||||
usually with one or more options provided to it. The first 'make' step
|
||||
will build OpenOCD and place the final executable in ./src/. The
|
||||
final (optional) step, ``make install'', places all of the files in the
|
||||
required location.
|
||||
|
||||
Cross-Compiling Options
|
||||
-----------------------
|
||||
|
||||
To cross-compile, you must specify both --build and --host options to
|
||||
the 'configure' script. For example, you can configure OpenOCD to
|
||||
cross-compile on a x86 Linux host to run on Windows (MinGW32), you could
|
||||
use the following configuration options:
|
||||
|
||||
./configure --build=i686-pc-linux-gnu --host=i586-mingw32msvc ...
|
||||
|
||||
Likewise, the following options allow OpenOCD to be cross-compiled for
|
||||
an ARM target on the same x86 host:
|
||||
|
||||
./configure --build=i686-pc-linux-gnu --host=arm-elf ...
|
||||
|
||||
Both must be specified to work around bugs in autoconf.
|
||||
|
||||
Scripts for producing ARM cross-compilers can be found on the web with a
|
||||
little searching. A script to produce an x86 Linux-hosted MinGW32
|
||||
cross-compiler can be downloaded from the following URL:
|
||||
|
||||
http://www.mingw.org/wiki/LinuxCrossMinGW
|
||||
|
||||
Configuration Options
|
||||
---------------------
|
||||
|
||||
The configure script takes numerous options, specifying which JTAG
|
||||
interfaces should be included (among other things). The following list
|
||||
of options was extracted from the output of './configure --help'. Other
|
||||
options may be available there:
|
||||
|
||||
--enable-maintainer-mode enable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer
|
||||
NOTE: This option is *required* for GIT builds!
|
||||
It should *not* be used to build a release.
|
||||
|
||||
--enable-dummy Enable building the dummy JTAG port driver
|
||||
|
||||
--enable-ft2232_libftdi Enable building support for FT2232 based devices
|
||||
using the libftdi driver, opensource alternate of
|
||||
FTD2XX
|
||||
--enable-ft2232_ftd2xx Enable building support for FT2232 based devices
|
||||
using the FTD2XX driver from ftdichip.com
|
||||
|
||||
--enable-gw16012 Enable building support for the Gateworks GW16012
|
||||
JTAG Programmer
|
||||
|
||||
--enable-parport Enable building the pc parallel port driver
|
||||
--disable-parport-ppdev Disable use of ppdev (/dev/parportN) for parport
|
||||
(for x86 only)
|
||||
--enable-parport-giveio Enable use of giveio for parport (for CygWin only)
|
||||
|
||||
--enable-presto_libftdi Enable building support for ASIX Presto Programmer
|
||||
using the libftdi driver
|
||||
--enable-presto_ftd2xx Enable building support for ASIX Presto Programmer
|
||||
using the FTD2XX driver
|
||||
|
||||
--enable-amtjtagaccel Enable building the Amontec JTAG-Accelerator driver
|
||||
--enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW
|
||||
Programmer
|
||||
--enable-jlink Enable building support for the Segger J-Link JTAG
|
||||
Programmer
|
||||
--enable-rlink Enable building support for the Raisonance RLink
|
||||
JTAG Programmer
|
||||
--enable-usbprog Enable building support for the usbprog JTAG
|
||||
Programmer
|
||||
--enable-vsllink Enable building support for the Versaloon-Link JTAG
|
||||
Programmer
|
||||
|
||||
--enable-oocd_trace Enable building support for the OpenOCD+trace ETM
|
||||
capture device
|
||||
|
||||
--enable-ep93xx Enable building support for EP93xx based SBCs
|
||||
--enable-at91rm9200 Enable building support for AT91RM9200 based SBCs
|
||||
|
||||
--enable-ecosboard Enable building support for eCos based JTAG debugger
|
||||
--enable-zy1000 Enable ZY1000 interface
|
||||
|
||||
--enable-minidriver-dummy
|
||||
Enable the dummy minidriver.
|
||||
|
||||
--enable-ioutil Enable ioutil functions - useful for standalone
|
||||
OpenOCD implementations
|
||||
--enable-httpd Enable builtin httpd server - useful for standalone
|
||||
OpenOCD implementations
|
||||
|
||||
Miscellaneous Configure Options
|
||||
-------------------------------
|
||||
|
||||
The following additional options may also be useful:
|
||||
|
||||
--disable-assert turn off assertions
|
||||
|
||||
--enable-verbose Enable verbose JTAG I/O messages (for debugging).
|
||||
--enable-verbose-jtag-io
|
||||
Enable verbose JTAG I/O messages (for debugging).
|
||||
--enable-verbose-usb-io Enable verbose USB I/O messages (for debugging)
|
||||
--enable-verbose-usb-comms
|
||||
Enable verbose USB communication messages (for
|
||||
debugging)
|
||||
--enable-malloc-logging Include free space in logging messages (requires
|
||||
malloc.h).
|
||||
|
||||
--disable-gccwarnings Disable extra gcc warnings during build.
|
||||
--disable-wextra Disable extra compiler warnings
|
||||
--disable-werror Do not treat warnings as errors
|
||||
|
||||
--disable-option-checking
|
||||
Ignore unrecognized --enable and --with options.
|
||||
--disable-dependency-tracking speeds up one-time build
|
||||
--enable-shared[=PKGS] build shared libraries [default=no]
|
||||
--enable-static[=PKGS] build static libraries [default=yes]
|
||||
|
||||
Parallel Port Dongles
|
||||
---------------------
|
||||
|
||||
If you want to access the parallel port using the PPDEV interface you
|
||||
have to specify both --enable-parport AND --enable-parport-ppdev, since the
|
||||
the later option is an option to the parport driver (see
|
||||
http://forum.sparkfun.com/viewtopic.php?t=3795 for more info).
|
||||
|
||||
The same is true for the --enable-parport-giveio option, you
|
||||
have to use both the --enable-parport AND the --enable-parport-giveio
|
||||
option if you want to use giveio instead of ioperm parallel port access
|
||||
method.
|
||||
|
||||
FT2232C Based USB Dongles
|
||||
-------------------------
|
||||
|
||||
There are 2 methods of using the FTD2232, either (1) using the
|
||||
FTDICHIP.COM closed source driver, or (2) the open (and free) driver
|
||||
libftdi.
|
||||
|
||||
Using LIBFTDI
|
||||
-------------
|
||||
|
||||
The libftdi source code can be download from the following website:
|
||||
|
||||
http://www.intra2net.com/en/developer/libftdi/download.php
|
||||
|
||||
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
|
||||
speed (480 Mbps), you need libftdi version 0.16 or newer. Many Linux
|
||||
distributions provide suitable packages for these libraries.
|
||||
|
||||
For Windows, libftdi is supported with versions 0.14 and later.
|
||||
|
||||
With these prerequisites met, configure the libftdi solution like this:
|
||||
|
||||
./configure --prefix=/path/for/your/install --enable-ft2232_libftdi
|
||||
|
||||
Then type ``make'', and perhaps ``make install''.
|
||||
|
||||
Using FTDI's FTD2XX
|
||||
-------------------
|
||||
|
||||
The (closed source) FTDICHIP.COM solution is faster on MS-Windows. That
|
||||
is the motivation for supporting it even though its licensing restricts
|
||||
it to non-redistributable OpenOCD binaries, and it is not available for
|
||||
all operating systems used with OpenOCD. You may, however, build such
|
||||
copies for personal use.
|
||||
|
||||
The FTDICHIP drivers come as either a (win32) ZIP file, or a (Linux)
|
||||
TAR.GZ file. You must unpack them ``some where'' convient. As of this
|
||||
writing FTDICHIP does not supply means to install these files "in an
|
||||
appropriate place."
|
||||
|
||||
If your distribution does not package these, there are several
|
||||
'./configure' options to solve this problem:
|
||||
|
||||
--with-ftd2xx-win32-zipdir
|
||||
Where (CYGWIN/MINGW) the zip file from ftdichip.com
|
||||
was unpacked <default=search>
|
||||
--with-ftd2xx-linux-tardir
|
||||
Where (Linux/Unix) the tar file from ftdichip.com
|
||||
was unpacked <default=search>
|
||||
--with-ftd2xx-lib Use static or shared ftd2xx libs on default static
|
||||
|
||||
If you are using the FTDICHIP.COM driver, download and unpack the
|
||||
Windows or Linux FTD2xx drivers from the following location:
|
||||
|
||||
http://www.ftdichip.com/Drivers/D2XX.htm
|
||||
|
||||
Remember, this library is binary-only, while OpenOCD is licenced
|
||||
according to GNU GPLv2 without any exceptions. That means that
|
||||
_distributing_ copies of OpenOCD built with the FTDI code would violate
|
||||
the OpenOCD licensing terms.
|
||||
|
||||
Linux Notes
|
||||
***********
|
||||
|
||||
The Linux tar.gz archive contains a directory named libftd2xx0.4.16
|
||||
(or similar). Assuming that you have extracted this archive in the same
|
||||
directory as the OpenOCD package, you could configure with options like
|
||||
the following:
|
||||
|
||||
./configure \
|
||||
--enable-ft2232_ftd2xx \
|
||||
--with-ft2xx-linux-tardir=../libftd2xx0.4.16 \
|
||||
... other options ...
|
||||
|
||||
Note that on Linux there is no good reason to use these FTDI binaries;
|
||||
they are no faster (on Linux) than libftdi, and cause licensing issues.
|
||||
|
||||
==========================
|
||||
Obtaining OpenOCD From GIT
|
||||
==========================
|
||||
|
||||
You can download the current GIT version with a GIT client of your
|
||||
choice from the main repository:
|
||||
|
||||
git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
||||
|
||||
You may prefer to use a mirror:
|
||||
|
||||
http://repo.or.cz/r/openocd.git
|
||||
git://repo.or.cz/openocd.git
|
||||
|
||||
Using the GIT command line client, you might use the following command
|
||||
to set up a local copy of the current repository (make sure there is no
|
||||
directory called "openocd" in the current directory):
|
||||
|
||||
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
|
||||
|
||||
Then you can update that at your convenience using
|
||||
|
||||
git pull
|
||||
|
||||
There is also a gitweb interface, which you can use either to browse
|
||||
the repository or to downlad arbitrary snapshots using HTTP:
|
||||
|
||||
http://openocd.git.sourceforge.net/git/gitweb.cgi?p=openocd/openocd
|
||||
http://repo.or.cz/w/openocd.git
|
||||
|
||||
Snapshots are compressed tarballs of the source tree, about 1.3 MBytes
|
||||
each at this writing.
|
||||
|
||||
|
||||
Tips For Building From a GIT Repository
|
||||
---------------------------------------
|
||||
|
||||
Building OpenOCD from a repository requires a recent version of the GNU
|
||||
autotools (autoconf >= 2.59 and automake >= 1.9).
|
||||
|
||||
1) Run './bootstrap' to create the 'configure' script and prepare
|
||||
the build process for your host system.
|
||||
|
||||
2) Run './configure --enable-maintainer-mode' with other options.
|
||||
|
||||
98
README.Win32
Normal file
98
README.Win32
Normal file
@@ -0,0 +1,98 @@
|
||||
Building OpenOCD for Windows
|
||||
----------------------------
|
||||
|
||||
For building on Windows, you have to use CygWin. Make sure that your
|
||||
PATH environment variable contains no other locations with Unix utilities
|
||||
(like UnxUtils). Those tools can't handle the CygWin paths, resulting
|
||||
in obscure dependency errors. This was an observation gathered from the
|
||||
logs of one user; please correct us if this is wrong.
|
||||
|
||||
The following URL is a good reference if you want to build OpenOCD
|
||||
under CygWin:
|
||||
|
||||
http://forum.sparkfun.com/viewtopic.php?t=11221
|
||||
|
||||
Alternatively you can build the Windows binary under Linux using
|
||||
MinGW cross compiler. The following documents some tips of
|
||||
using this cross build option.
|
||||
|
||||
libusb-win32
|
||||
------------
|
||||
|
||||
You can choose to use the libusb-win32 binary distribution from
|
||||
its SourceForge page. As of this writing, the latest version
|
||||
is 0.1.12.2. This is the recommend version to use since it fixed
|
||||
an issue with USB composite device and this is important for FTDI
|
||||
based JTAG debuggers.
|
||||
|
||||
http://sourceforge.net/projects/libusb-win32/
|
||||
|
||||
You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz
|
||||
package. Extract this file into a temp directory.
|
||||
|
||||
Copy the file libusb-win32-device-bin-0.1.12.2\include\usb.h
|
||||
to your MinGW include directory.
|
||||
|
||||
Copy the library libusb-win32-device-bin-0.1.12.2\lib\gcc\libusb.a
|
||||
to your MinGW library directory.
|
||||
|
||||
Take note that different Linux distributions often have different MinGW
|
||||
installation directory. Some of them also put the library and include
|
||||
into a separate sys-root directory.
|
||||
|
||||
When the libusb-win32 repository is more current than its release code,
|
||||
you could build that instead.
|
||||
|
||||
These are the instruction from the libusb-win32 Makefile:
|
||||
|
||||
# If you're cross-compiling and your mingw32 tools are called
|
||||
# i586-mingw32msvc-gcc and so on, then you can compile libusb-win32
|
||||
# by running
|
||||
# make host_prefix=i586-mingw32msvc all
|
||||
|
||||
libftdi
|
||||
-------
|
||||
|
||||
The author does not provide Windows binary. You can build it from a
|
||||
released source tarball or the git tree.
|
||||
|
||||
If you are using the git tree, the following are the instructions from
|
||||
README.mingw. You will need to have the cmake utility installed.
|
||||
|
||||
- Edit Toolchain-mingw32.cmake to point to the correct MinGW
|
||||
installation.
|
||||
- Create a build directory like "mkdir build-win32", e.g in ../libftdi/
|
||||
- cd into that directory and run
|
||||
"cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-mingw32.cmake .."
|
||||
- Copy src/ftdi.h to your MinGW include directory.
|
||||
- Copy build-win32/src/*.a to your MinGW lib directory.
|
||||
|
||||
libftd2xx
|
||||
---------
|
||||
|
||||
The Cygwin/Win32 ZIP file contains a directory named ftd2xx.win32.
|
||||
After being extracted, the directory does not need further preparation.
|
||||
Instead, its path must be provided to the --with-ftd2xx-win32-zipdir
|
||||
configure option, as shown in the next section.
|
||||
|
||||
OpenOCD
|
||||
-------
|
||||
|
||||
Now you can build OpenOCD under Linux using MinGW. You need to use
|
||||
--build and --host configure options.
|
||||
|
||||
To use libftdi:
|
||||
|
||||
./configure --build=i686-pc-linux-gnu --host=i586-mingw32msvc \
|
||||
--enable-ft2232_libftdi \
|
||||
... other options ...
|
||||
|
||||
To use ftd2xx:
|
||||
|
||||
./configure --build=i686-pc-linux-gnu --host=i586-mingw32msvc \
|
||||
--enable-ft2232_ftd2xx \
|
||||
--with-ftd2xx-win32-zipdir=/path/to/libftd2xx-win32 \
|
||||
... other options ...
|
||||
|
||||
If you are using the GIT repository, see the README file for additional
|
||||
instructions about configuring and building OpenOCD.
|
||||
337
TODO
337
TODO
@@ -1,2 +1,337 @@
|
||||
This document is not in use. See mailing list.
|
||||
// This file is part of the Doyxgen Developer Manual
|
||||
/** @page tasks Pending and Open Tasks
|
||||
|
||||
This page lists pending and open tasks being considered or worked upon
|
||||
by the OpenOCD community.
|
||||
|
||||
@section thelist The List
|
||||
|
||||
Most items are open for the taking, but please post to the mailing list
|
||||
before spending much time working on anything lists here. The community
|
||||
may have evolved an idea since it was added here.
|
||||
|
||||
Feel free to send patches to add or clarify items on this list, too.
|
||||
|
||||
@section thelisttcl TCL
|
||||
|
||||
This section provides possible things to improve with OpenOCD's TCL support.
|
||||
|
||||
- Fix problem with incorrect line numbers reported for a syntax
|
||||
error in a reset init event.
|
||||
|
||||
- organize the TCL configurations:
|
||||
- provide more directory structure for boards/targets?
|
||||
- factor configurations into layers (encapsulation and re-use)
|
||||
|
||||
- Fix handling of variables between multiple command line "-c" and "-f"
|
||||
parameters. Currently variables assigned through one such parameter
|
||||
command/script are unset before the next one is invoked.
|
||||
|
||||
- Isolate all TCL command support:
|
||||
- Pure C CLI implementations using --disable-builtin-tcl.
|
||||
- Allow developers to build new dongles using OpenOCD's JTAG core.
|
||||
- At first, provide only low-level JTAG support; target layer and
|
||||
above rely heavily on scripting event mechanisms.
|
||||
- Allow full TCL support? add --with-tcl=/path/to/installed/tcl
|
||||
- Move TCL support out of foo.[ch] and into foo_tcl.[ch] (other ideas?)
|
||||
- See src/jtag/core.c and src/jtag/tcl.c for an example.
|
||||
- allow some of these TCL command modules to be dynamically loadable?
|
||||
|
||||
@section thelistjtag JTAG
|
||||
|
||||
This section list issues that need to be resolved in the JTAG layer.
|
||||
|
||||
@subsection thelistjtagcore JTAG Core
|
||||
|
||||
The following tasks have been suggested for cleaning up the JTAG layer:
|
||||
|
||||
- use tap_set_state everywhere to allow logging TAP state transitions
|
||||
- Encapsulate cmd_queue_cur_state and related varaible handling.
|
||||
- add slick 32 bit versions of jtag_add_xxx_scan() that avoids
|
||||
buf_set_u32() calls and other evidence of poor impedance match between
|
||||
API and calling code. New API should cut down # of lines in calling
|
||||
code by 100's and make things clearer. Also potentially be supported
|
||||
directly in minidriver API for better embedded host performance.
|
||||
|
||||
The following tasks have been suggested for adding new core JTAG support:
|
||||
|
||||
- Improve autodetection of TAPs by supporting tcl escape procedures that
|
||||
can configure discovered TAPs based on IDCODE value ... they could:
|
||||
- Remove guessing for irlen
|
||||
- Allow non-default irmask/ircapture values
|
||||
- SPI/UART emulation:
|
||||
- (ab)use bit-banging JTAG interfaces to emulate SPI/UART
|
||||
- allow SPI to program flash, MCUs, etc.
|
||||
|
||||
@subsection thelistjtaginterfaces JTAG Interfaces
|
||||
|
||||
There are some known bugs to fix in JTAG adapter drivers:
|
||||
|
||||
- For JTAG_STATEMOVE to TAP_RESET, all drivers must ignore the current
|
||||
recorded state. The tap_get_state() call won't necessarily return
|
||||
the correct value, especially at server startup. Fix is easy: in
|
||||
that case, always issue five clocks with TMS high.
|
||||
- amt_jtagaccel.c
|
||||
- arm-jtag-ew.c
|
||||
- bitbang.c
|
||||
- bitq.c
|
||||
- gw16012.c
|
||||
- jlink.c
|
||||
- usbprog.c
|
||||
- vsllink.c
|
||||
- rlink/rlink.c
|
||||
- bug: USBprog is broken with new tms sequence; it needs 7-clock cycles.
|
||||
Fix promised from Peter Denison openwrt at marshadder.org
|
||||
Workaround: use "tms_sequence long" @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-July/009426.html
|
||||
|
||||
The following tasks have been suggeted for improving OpenOCD's JTAG
|
||||
interface support:
|
||||
|
||||
- rework USB communication to be more robust. Two possible options are:
|
||||
-# use libusb-1.0.1 with libusb-compat-0.1.1 (non-blocking I/O wrapper)
|
||||
-# rewrite implementation to use non-blocking I/O
|
||||
- J-Link driver:
|
||||
- fix to work with long scan chains, such as R.Doss's svf test.
|
||||
- FT2232 (libftdi):
|
||||
- make performance comparable to alternatives (on Win32, D2XX is faster)
|
||||
- make usability comparable to alternatives
|
||||
- Autodetect USB based adapters; this should be easy on Linux. If there's
|
||||
more than one, list the options; otherwise, just select that one.
|
||||
|
||||
The following tasks have been suggested for adding new JTAG interfaces:
|
||||
|
||||
- TCP driver: allow client/server for remote JTAG interface control.
|
||||
This requires a client and a server. The server is built into the
|
||||
normal OpenOCD and takes commands from the client and executes
|
||||
them on the interface returning the result of TCP/IP. The client
|
||||
is an OpenOCD which is built with a TCP/IP minidriver. The use
|
||||
of a minidriver is required to capture all the jtag_add_xxx()
|
||||
fn's at a high enough level and repackage these cmd's as
|
||||
TCP/IP packets handled by the server.
|
||||
|
||||
@section thelistswd Serial Wire Debug
|
||||
|
||||
- implement Serial Wire Debug interface
|
||||
|
||||
@section thelistbs Boundary Scan Support
|
||||
|
||||
- add STAPL support?
|
||||
- add BSDL support?
|
||||
|
||||
A few possible options for the above:
|
||||
-# Fake a TCL equivalent?
|
||||
-# Integrate an existing library?
|
||||
-# Write a new C implementation a la Jim?
|
||||
|
||||
Once the above are completed:
|
||||
- add support for programming flash using boundary scan techniques
|
||||
- add integration with a modified gerber view program:
|
||||
- provide means to view the PCB and select pins and traces
|
||||
- allow use-cases such as the following:
|
||||
- @b Stimulus
|
||||
-# Double-click on a pin (or trace) with the mouse.
|
||||
- @b Effects
|
||||
-# The trace starts blinking, and
|
||||
-# OpenOCD toggles the pin(s) 0/1.
|
||||
|
||||
@section thelisttargets Target Support
|
||||
|
||||
- Many common ARM cores could be autodetected using IDCODE
|
||||
- general layer cleanup: @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
|
||||
- regression: "reset halt" between 729(works) and 788(fails): @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-July/009206.html
|
||||
- ARM7/9:
|
||||
- clean up "arm9tdmi vector_catch". Available for some arm7 cores? @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-October/011488.html
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
|
||||
- add reset option to allow programming embedded ice while srst is asserted.
|
||||
Some CPUs will gate the JTAG clock when srst is asserted and in this case,
|
||||
it is necessary to program embedded ice and then assert srst afterwards.
|
||||
- ARM926EJS:
|
||||
- reset run/halt/step is not robust; needs testing to map out problems.
|
||||
- ARM11 improvements (MB?)
|
||||
- add support for asserting srst to reset the core.
|
||||
- Single stepping works, but should automatically
|
||||
use hardware stepping if available.
|
||||
- mdb can return garbage data if read byte operation fails for
|
||||
a memory region(16 & 32 byte access modes may be supported). Is this
|
||||
a bug in the .MX31 PDK init script? Try on i.MX31 PDK:
|
||||
mdw 0xb80005f0 0x8, mdh 0xb80005f0 0x10, mdb 0xb80005f0 0x20. mdb returns
|
||||
garabage.
|
||||
- implement missing functionality (grep FNC_INFO_NOTIMPLEMENTED ...)
|
||||
- thumb support is missing: ISTR ARMv6 requires Thumb.
|
||||
ARM1156 has Thumb2; ARM1136 doesn't.
|
||||
- Cortex A8 support (ML)
|
||||
- add target implementation (ML)
|
||||
- Generic ARM run_algorithm() interface
|
||||
- tagged struct wrapping ARM instructions and metadata
|
||||
- not revision-specific (current: ARMv4+ARMv5 -or- ARMv6 -or- ARMv7)
|
||||
- usable with at least arm_nandwrite() and generic CFI drivers
|
||||
- MC1322x support (JW/DE?)
|
||||
- integrate and test support from JW (and DE?)
|
||||
- get working with a known good interface (i.e. not today's jlink)
|
||||
- AT91SAM92xx:
|
||||
- improvements for unknown-board-atmel-at91sam9260.cfg (RD)
|
||||
- STR9x: (ZW)
|
||||
- improvements to str912.cfg to be more general purpose
|
||||
- AVR: (SQ)
|
||||
- independently verify implementation
|
||||
- incrementally improve working prototype in trunk. (SQ)
|
||||
- work out how to debug this target
|
||||
- AVR debugging protocol.
|
||||
- FPGA:
|
||||
- Altera Nios Soft-CPU support
|
||||
- Coldfire (suggested by NC)
|
||||
- can we draw from the BDM project? @par
|
||||
http://bdm.sourceforge.net/
|
||||
|
||||
or the OSBDM package @par
|
||||
http://forums.freescale.com/freescale/board/message?board.id=OSBDM08&thread.id=422
|
||||
|
||||
@section thelistsvf SVF/XSVF
|
||||
|
||||
- develop SVF unit tests
|
||||
- develop XSVF unit tests
|
||||
|
||||
@section thelistflash Flash Support
|
||||
|
||||
- finish documentation for the following flash drivers:
|
||||
- avr
|
||||
- ecosflash
|
||||
- pic32mx
|
||||
- ocl
|
||||
- str9xpec
|
||||
|
||||
@subsection thelistflashcfi CFI
|
||||
|
||||
- finish implementing bus width/chip width handling (suggested by NC)
|
||||
- factor vendor-specific code into separate source files
|
||||
- add new callback interface for vendor-specific code
|
||||
- investigate/implement "thin wrapper" to use eCos CFI drivers (ØH)
|
||||
|
||||
@section thelistdebug Debugger Support
|
||||
|
||||
- add support for masks in watchpoints? @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-October/011507.html
|
||||
- breakpoints can get lost in some circumstances: @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-June/008853.html
|
||||
- add support for masks in watchpoints. The trick is that GDB does not
|
||||
support a breakpoint mask in the remote protocol. One way to work around
|
||||
this is to add a separate command "watchpoint_mask add/rem <addr> <mask>", that
|
||||
is run to register a list of masks that the gdb_server knows to use with
|
||||
a particular watchpoint address.
|
||||
- integrate Keil AGDI interface to OpenOCD? (submitted by Dario Vecchio)
|
||||
|
||||
@section thelisttesting Testing Suite
|
||||
|
||||
This section includes several related groups of ideas:
|
||||
- @ref thelistunittests
|
||||
- @ref thelistsmoketests
|
||||
- @ref thelisttestreports
|
||||
- @ref thelisttestgenerichw
|
||||
|
||||
@subsection thelistunittests Unit Tests
|
||||
|
||||
- add testing skeleton to provide frameworks for adding tests
|
||||
- implement server unit tests
|
||||
- implement JTAG core unit tests
|
||||
- implement JTAG interface unit tests
|
||||
- implement flash unit tests
|
||||
- implement target unit tests
|
||||
|
||||
@subsection thelistsmoketests Smoke Test Tools
|
||||
|
||||
-# extend 'make check' with a smoketest app
|
||||
- checks for OOCD_TEST_CONFIG, etc. in environment (or config file)
|
||||
- if properly set, runs the smoke test with specified parameters
|
||||
- openocd -f ${OOCD_TEST_CONFIG}
|
||||
- implies a modular test suite (see below)
|
||||
- should be able to run some minimal tests with dummy interface:
|
||||
- compare results of baseline sanity checks with expected results
|
||||
|
||||
-# builds a more complete test suite:
|
||||
- existing testing/examples/ look like a great start
|
||||
- all targets should be tested fully and for all capabilities
|
||||
- we do NOT want a "lowest common denominator" test suite
|
||||
- ... but can we start with one to get going?
|
||||
- probably requires one test configuration file per board/target
|
||||
- modularization can occur here, just like with targets/boards/chips
|
||||
- coverage can increase over time, building up bundles of tests
|
||||
|
||||
-# add new 'smoketest' Makefile target:
|
||||
- calls 'make check' (and the smoketest app)
|
||||
- gather inputs and output into a report file
|
||||
|
||||
@subsection thelisttestreports Test Feedback Tools
|
||||
|
||||
These ideas were first introduced here: @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006358.html
|
||||
|
||||
- provide report submission scripts for e-mail and web forms
|
||||
- add new Makefile targets to post the report:
|
||||
- 'checkreportsend' -- send to list via e-mail (via sendmail)
|
||||
- 'checkreportpost' -- send web form (via curl or other script)
|
||||
|
||||
@subsection thelisttestgenerichw Generic Hardware Tester
|
||||
|
||||
- implement VHDL to use for FPGA-based JTAG TAP testing device
|
||||
- develop test suite that utilizes this testing device
|
||||
|
||||
@section thelistautotools Autotools Build System
|
||||
|
||||
- make entire configure process require less user consideration:
|
||||
- automatically detect the features that are available, unless
|
||||
options were specifically provided to configure
|
||||
- provide a report of the drivers that will be build at the end of
|
||||
running configure, so the users can verify which driverswill be
|
||||
built during 'make' (and their options) .
|
||||
- eliminate sources of confusion in @c bootstrap script:
|
||||
-# Make @c bootstrap call 'configure --enable-maintainer-mode \<opts\>'?
|
||||
-# Add @c buildstrap script to assist with boostrap and configure steps.
|
||||
- automatically build tool-chains required for cross-compiling
|
||||
- produce mingw32, arm-elf, others using in-tree scripts
|
||||
- build all required target code from sources
|
||||
- make JTAG and USB debug output a run-time configuration option
|
||||
|
||||
@section thelistarchitecture Architectural Tasks
|
||||
|
||||
The following architectural tasks need to be accomplished and should be
|
||||
fairly easy to complete:
|
||||
|
||||
- clean-up code to match style guides
|
||||
- factor code to eliminate duplicated functionality
|
||||
- rewrite code that uses casts to access 16-bit and larger types
|
||||
from unaligned memory addresses
|
||||
- libopenocd support: @par
|
||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006405.html
|
||||
- review and clean up interface/target/flash APIs
|
||||
|
||||
The following strategic tasks will require ambition, knowledge, and time
|
||||
to complete:
|
||||
|
||||
- overhaul use of types to improve 32/64-bit portability
|
||||
- types for both host and target word sizes?
|
||||
- can we use GDB's CORE_TYPE support?
|
||||
- Allow N:M:P mapping of servers, targets, and interfaces
|
||||
- loadable module support for interface/target/flash drivers and commands
|
||||
- support both static and dynamic modules.
|
||||
- should probably use libltdl for dynamic library handing.
|
||||
|
||||
@section thelistadmin Documentation Tasks
|
||||
|
||||
- Develop milestone and release guidelines, processes, and scripts.
|
||||
- Develop "style" guidelines (and scripts) for maintainers:
|
||||
- reviewing patches
|
||||
- committing to Subversion
|
||||
- Review The Guide for OpenOCD Users for documentation errors or omissions
|
||||
- Update The Manual for OpenOCD Developerrs:
|
||||
- Add documentation describing the architecture of each module
|
||||
- Provide more Technical Primers to bootstrap contributor knowledge
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref thelist page.
|
||||
*/
|
||||
|
||||
|
||||
30
bootstrap
30
bootstrap
@@ -1,4 +1,26 @@
|
||||
aclocal \
|
||||
&& autoheader \
|
||||
&& automake --foreign --add-missing --copy \
|
||||
&& autoconf
|
||||
#!/bin/sh -e
|
||||
# Run the autotools bootstrap sequence to create the configure script
|
||||
|
||||
if libtoolize --version >/dev/null 2>&1; then
|
||||
libtoolize="libtoolize"
|
||||
elif glibtoolize --version >/dev/null 2>&1; then
|
||||
libtoolize="glibtoolize"
|
||||
else
|
||||
echo "libtool is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# bootstrap the autotools
|
||||
(
|
||||
set -x
|
||||
aclocal
|
||||
${libtoolize} --automake --copy
|
||||
autoconf
|
||||
autoheader
|
||||
automake --gnu --add-missing --copy
|
||||
)
|
||||
|
||||
# AM_MAINTAINER_MODE requires --enable-maintainer-mode from everyone using
|
||||
# current source snapshots (working from GIT, or some source snapshot, etc)
|
||||
# otherwise the documentation will fail to build due to missing version.texi
|
||||
echo "Bootstrap complete; you can './configure --enable-maintainer-mode ....'"
|
||||
|
||||
852
configure.in
852
configure.in
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
libftdi can be built to work under win32 (cygwin/mingw) after applying the patch in this directory.
|
||||
|
||||
The issue is caused by windows requiring usb_set_configuration to be called before the usb_claim_interface.
|
||||
|
||||
Spen
|
||||
spen@spen-soft.co.uk
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
--- src/ftdi.c.orig Wed Apr 16 16:24:30 2008
|
||||
+++ src/ftdi.c Thu May 01 20:19:46 2008
|
||||
@@ -358,6 +358,17 @@
|
||||
if (usb_detach_kernel_driver_np(ftdi->usb_dev, ftdi->interface) != 0 && errno != ENODATA)
|
||||
detach_errno = errno;
|
||||
#endif
|
||||
+
|
||||
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
|
||||
+ if (usb_set_configuration(ftdi->usb_dev, 1) != 0) {
|
||||
+ usb_close (ftdi->usb_dev);
|
||||
+ if (detach_errno == EPERM) {
|
||||
+ ftdi_error_return(-8, "inappropriate permissions on device!");
|
||||
+ } else {
|
||||
+ ftdi_error_return(-5, "unable to set configuration");
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
if (usb_claim_interface(ftdi->usb_dev, ftdi->interface) != 0) {
|
||||
usb_close (ftdi->usb_dev);
|
||||
@@ -6,20 +6,55 @@ SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0003", MODE="664", GROUP="plugdev"
|
||||
# Olimex ARM-USB-OCD-TINY
|
||||
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0004", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Olimex ARM-JTAG-EW
|
||||
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="001e", MODE="664", GROUP="plugdev"
|
||||
|
||||
# USBprog with OpenOCD firmware
|
||||
SYSFS{idVendor}=="1781", SYSFS{idProduct}=="0c63", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Amontec JTAGkey
|
||||
# Amontec JTAGkey and JTAGkey-tiny
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Amontec JTAGkey-HiSpeed
|
||||
SYSFS{idVendor}=="0fbb", SYSFS{idProduct}=="1000", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Axiom AXM-0432 Link (Symphony SoundBite?)
|
||||
# Calao Systems USB-A9260-C01
|
||||
# TinCanTools Flyswatter
|
||||
# OOCD-Link
|
||||
# Marvell Sheevaplug (early development versions)
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6010", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Calao Systems USB-A9260-C02
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6001", MODE="664", GROUP="plugdev"
|
||||
|
||||
# IAR J-Link USB
|
||||
SYSFS{idVendor}=="1366", SYSFS{idProduct}=="0101", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Raisonance RLink
|
||||
SYSFS{idVendor}=="138e", SYSFS{idProduct}=="9000", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Hitex STR9-comStick
|
||||
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002c", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Hitex STM32-PerformanceStick
|
||||
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002d", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Luminary Micro Stellaris/LM3S811
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Xverve Signalyzer Tool (DT-USB-ST)
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
|
||||
|
||||
# egnite Turtelizer 2
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Marvell Sheevaplug
|
||||
SYSFS{idVendor}=="9e88", SYSFS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
|
||||
|
||||
# Section5 ICEbear
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c140", MODE="664", GROUP="plugdev"
|
||||
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c141", MODE="664", GROUP="plugdev"
|
||||
|
||||
LABEL="openocd_rules_end"
|
||||
|
||||
|
||||
@@ -3,4 +3,17 @@ openocd_TEXINFOS = fdl.texi
|
||||
man_MANS = openocd.1
|
||||
EXTRA_DIST = openocd.1
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in mdate-sh texinfo.tex
|
||||
dist-hook:
|
||||
mkdir $(distdir)/manual
|
||||
cp -p $(srcdir)/manual/*.txt $(distdir)/manual
|
||||
for i in $$(cd $(srcdir)/manual/ && ls -d */); do \
|
||||
mkdir $(distdir)/manual/$$i; \
|
||||
cp -p $(srcdir)/manual/$$i/* $(distdir)/manual/$$i/; \
|
||||
done
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
$(srcdir)/Makefile.in \
|
||||
$(srcdir)/mdate-sh \
|
||||
$(srcdir)/stamp-vti \
|
||||
$(srcdir)/version.texi \
|
||||
$(srcdir)/texinfo.tex
|
||||
|
||||
9
doc/manual/app.txt
Normal file
9
doc/manual/app.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
/** @page appdocs OpenOCD Application APIs
|
||||
|
||||
The top-level APIs in the OpenOCD library allow applications to integrate
|
||||
all of the low-level functionality using a set of simple function calls.
|
||||
|
||||
These function calls do not exist in a re-usable form, but
|
||||
contributions to create and document them will be welcome.
|
||||
|
||||
*/
|
||||
35
doc/manual/flash.txt
Normal file
35
doc/manual/flash.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
/** @page flashdocs OpenOCD Flash APIs
|
||||
|
||||
OpenOCD provides its Flash APIs for developers to support different
|
||||
types of flash devices, some of which are built-in to target devices
|
||||
while others may be connected via standard memory interface (e.g. CFI,
|
||||
FMI, etc.).
|
||||
|
||||
The Flash module provides the following APIs:
|
||||
|
||||
- @subpage flashcfi
|
||||
- @subpage flashnand
|
||||
- @subpage flashtarget
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @page flashcfi OpenOCD CFI Flash API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's CFI Flash API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page flashnand OpenOCD NAND Flash API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's NAND Flash API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page flashtarget OpenOCD Target Flash API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Target Flash API.
|
||||
|
||||
*/
|
||||
48
doc/manual/helper.txt
Normal file
48
doc/manual/helper.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
/** @page helperdocs OpenOCD Helper APIs
|
||||
|
||||
OpenOCD uses several low-level APIs as the foundation for high-level APIs:
|
||||
|
||||
- @subpage helperporting
|
||||
- @subpage helperjim
|
||||
- @subpage helpercommand
|
||||
- @subpage helperlogging
|
||||
- @subpage helperbuffers
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page helperporting OpenOCD Types/Portability APIs
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's type and
|
||||
portability API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page helperjim OpenOCD Jim API
|
||||
|
||||
The Jim API provides access to a small-footprint TCL implementation.
|
||||
|
||||
Visit http://jim.berlios.de/ for more information on Jim.
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Jim API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page helpercommand OpenOCD Command API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Command API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page helperlogging OpenOCD Logging API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Logging API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page helperbuffers OpenOCD Byte Buffer API
|
||||
|
||||
This section needs to be expanded to describe OpenOCD's Byte Buffer API.
|
||||
|
||||
*/
|
||||
73
doc/manual/jtag.txt
Normal file
73
doc/manual/jtag.txt
Normal file
@@ -0,0 +1,73 @@
|
||||
/** @page jtagdocs JTAG APIs
|
||||
|
||||
For new developers unfamiliar with the technology, @ref primerjtag provides
|
||||
a brief introduction to the IEEE JTAG interface.
|
||||
|
||||
The OpenOCD JTAG library API covers several functional areas. The jtag
|
||||
@b core communicates through the @b minidriver API with either its full
|
||||
@a driver implementation (src/jtag/jtag_driver.c) or a @a minidriver .
|
||||
Internally, the @b command API is used by the JTAG driver for managing
|
||||
asynchronous transactions.
|
||||
|
||||
- @subpage jtagcore
|
||||
- @b public API routines
|
||||
- declared in @c src/jtag/jtag.h
|
||||
- used by other modules
|
||||
|
||||
- @subpage jtagtcl
|
||||
- @b private TCL handling routines
|
||||
- defined in @c src/jtag/tcl.c
|
||||
- registers and handles Jim commands that configure and use the JTAG core
|
||||
|
||||
- @subpage jtagcmd
|
||||
- @b private command queue API
|
||||
- declared in @c src/jtag/commands.h
|
||||
- provides routines used internally by the full JTAG drivers.
|
||||
|
||||
- @subpage jtagiface
|
||||
- @b private interface driver API
|
||||
- declared in @c src/jtag/interface.h
|
||||
- used by the core, minidrivers, and the full interface device drivers.
|
||||
- allows implementing new interface device drivers.
|
||||
- includes the Cable/TAP API (commands starting with @c tap_)
|
||||
|
||||
- @subpage jtagdriver
|
||||
- @b private minidriver API
|
||||
- declared in @c src/jtag/minidriver.h
|
||||
- used @a only by the core and minidriver implementations:
|
||||
- @c jtag_driver.c (in-tree OpenOCD drivers)
|
||||
- @c zy1000/build/include/jtag_minidriver.h (ZY1000 minidriver)
|
||||
- future implementations (on other embedded hosts)
|
||||
- interface device drivers do @b not need this API.
|
||||
|
||||
*/
|
||||
|
||||
/** @page jtagcore JTAG Core API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page jtagtcl JTAG TCL API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page jtagcmd JTAG Command API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page jtagiface JTAG Interface API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page jtagdriver JTAG Minidriver API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
99
doc/manual/main.txt
Normal file
99
doc/manual/main.txt
Normal file
@@ -0,0 +1,99 @@
|
||||
/** @mainpage OpenOCD Reference Manual
|
||||
|
||||
Welcome to the OpenOCD Reference Manual -- the developer's resource for
|
||||
learning about the internal architecture of the OpenOCD project. @par
|
||||
|
||||
In addition, this document contains the tactical and strategic plans
|
||||
and processes that have been developed by and for the OpenOCD community.
|
||||
|
||||
Developers that want to contribute to OpenOCD should read the following
|
||||
sections before starting work:
|
||||
|
||||
- The List of @subpage thelist enumerates opportunities for improving or
|
||||
extending the OpenOCD platform. If your ideas are on The List, you might
|
||||
check the mailing list archives to find the status of your feature (or bug).
|
||||
- The @subpage styleguide provides rules that developers should
|
||||
follow when writing new code for OpenOCD.
|
||||
- The @subpage patchguide provides policies that developers should
|
||||
follow when submitting patches to the project.
|
||||
- The @subpage bugs page contains the content of the BUGS file, which
|
||||
provides instructions for submitting bug reports to the maintainers.
|
||||
- The @subpage releases page describes the project's release process.
|
||||
|
||||
@ref primer provide introductory materials for new developers on various
|
||||
specific topics.
|
||||
|
||||
Finally, the @ref oocd pages explain how the code has been organized
|
||||
into layers of APIs, providing an overview of how they fit together.
|
||||
These pages attempt to give developers a high-level perspective of the
|
||||
various code modules provided by OpenOCD.
|
||||
|
||||
*/
|
||||
|
||||
/** @page primer OpenOCD Technical Primers
|
||||
|
||||
This pages lists Technical Primers available for OpenOCD Developers.
|
||||
They seek to provide information to pull novices up the learning curves
|
||||
associated with the fundamental technologies used by OpenOCD.
|
||||
|
||||
- @subpage primerpatches
|
||||
- @subpage primerdocs
|
||||
- @subpage primerautotools
|
||||
- @subpage primertcl
|
||||
- @subpage primerjtag
|
||||
|
||||
These documents should bridge any "ancillary" gaps in contributor
|
||||
knowledge, without having to learn the complete languages or technology.
|
||||
They should provide enough information for experienced developers to
|
||||
learn how to make "correct" changes when creating patches.
|
||||
|
||||
In all cases, these Primers should use idiomatic conventions that the
|
||||
community has agreed are the "right way of doing things". In this
|
||||
respect, these documents typically assume some familiarity with the
|
||||
information contained in one or more @ref styleguide, or they will
|
||||
directly refer to specific style guides as supplemental reading.
|
||||
|
||||
Contributions or suggestions for new Technical Primers are welcome.
|
||||
|
||||
*/
|
||||
|
||||
/** @page oocd OpenOCD Architecture
|
||||
|
||||
The OpenOCD library consists of several APIs that build together to
|
||||
provide the support functionality. The following list shows how these
|
||||
modules are stacked in the current implementation (from bottom to top):
|
||||
|
||||
- @subpage helperdocs
|
||||
- @ref helperporting
|
||||
- @ref helperjim
|
||||
- @ref helpercommand
|
||||
- @ref helperlogging
|
||||
- @subpage jtagdocs
|
||||
- @ref jtagcore
|
||||
- @ref jtagtcl
|
||||
- @ref jtagcmd
|
||||
- @ref jtagiface
|
||||
- @ref jtagdriver
|
||||
- @subpage targetdocs
|
||||
- @ref targetarm
|
||||
- @ref targetnotarm
|
||||
- @ref targetregister
|
||||
- @ref targetimage
|
||||
- @ref targettrace
|
||||
- @subpage flashdocs
|
||||
- @ref flashcfi
|
||||
- @ref flashnand
|
||||
- @ref flashtarget
|
||||
- @subpage serverdocs
|
||||
- @ref servergdb
|
||||
- @ref servertelnet
|
||||
- @ref serverhttp
|
||||
- @subpage appdocs
|
||||
|
||||
Obviously, there are some nuances to the stack that are not shown by
|
||||
this linear list of layers.
|
||||
|
||||
The List of @ref thelist enumerates opportunities for improving or
|
||||
extending the OpenOCD platform.
|
||||
|
||||
*/
|
||||
167
doc/manual/primer/autotools.txt
Normal file
167
doc/manual/primer/autotools.txt
Normal file
@@ -0,0 +1,167 @@
|
||||
/** @page primerautotools OpenOCD Autotools Primer
|
||||
|
||||
This page provides an overview to OpenOCD's use of the GNU autotool suite:
|
||||
- @ref primerautoconf
|
||||
- @ref primerautomake
|
||||
- @ref primerlibtool
|
||||
|
||||
Most developers do not need to concern themselves with these tools, as
|
||||
the @ref primerbootstrap script runs these tools in the required sequence.
|
||||
|
||||
@section primerbootstrap Autotools Bootstrap
|
||||
|
||||
The @c bootstrap script should be used by developers to run the
|
||||
autotools in the correct sequence.
|
||||
|
||||
When run after a fresh checkout, this script generates the build files
|
||||
required to compile the project, producing the project configure script.
|
||||
After running @c configure, the @ref primermaintainermode settings will
|
||||
handle most situations that require running these tools again. In some
|
||||
cases, a fresh bootstrap may be still required.
|
||||
|
||||
@subsection primerbootstrapcures Problems Solved By Bootstrap
|
||||
|
||||
For example, the build system can fail in unexpected ways after running
|
||||
<code>git pull</code>. Here, the <code>make maintainer-clean</code>
|
||||
should be used to remove all of the files generated by the @c bootstrap
|
||||
script and subsequent build processes.
|
||||
|
||||
In this particular case, one may also need to remove stray files by hand
|
||||
after running this command to ensure everything is rebuilt properly.
|
||||
This step should be necessary only if the @c maintainer-clean was run
|
||||
@b after altering the build system files with git. If it is run
|
||||
@b before any updates, the build system should never leave artifacts
|
||||
in the tree.
|
||||
|
||||
Without such precautions, changes can be introduced that leave the tree
|
||||
timestamps in an inconsistent state, producing strange compile errors
|
||||
that are resolve after such diligence.
|
||||
|
||||
@subsection primermaintainerclean Autotools Cleaning
|
||||
|
||||
Normally, all files generated by the bootstrap script, configure
|
||||
process, and build system should be removed after running <code>make
|
||||
maintainer-clean</code>. Automatically generated files that remain
|
||||
after this should be listed in @c MAINTAINERCLEANFILES,
|
||||
@c DISTCLEANFILES, or @c CLEANFILES, depending on which stage of the
|
||||
build process they are produced.
|
||||
|
||||
@section primerautoconf Autoconf Configuration Script
|
||||
|
||||
The @c autoconf program generates the @c configure script from
|
||||
@c configure.in, using serious Perl voodoo. The resulting script is
|
||||
included in the project distribution packages and run by users to
|
||||
configure the build process for their system.
|
||||
|
||||
@subsection primermaintainermode Maintainer Mode
|
||||
|
||||
After a fresh checkout, @c bootstrap, and a simple @c configure, you may
|
||||
experience errors when running @c make that some files cannot be found
|
||||
(e.g. @c version.texi), and a second @c make will "mysteriously" solve
|
||||
the problems. The isssue is well-known and expected, if unfortunate.
|
||||
|
||||
The OpenOCD project requires that all developers building from the
|
||||
git repository use the @c --enable-maintainer-mode option when
|
||||
running the @c configure script. This option ensures that certain files
|
||||
are created during the build process that would normally be packaged in
|
||||
the distribution tarball. The @c bootstrap script will remind you of
|
||||
this requirement when it runs.
|
||||
|
||||
In addition to solving these problems, this option enables Makefile
|
||||
rules (provided by automake) that allow the normal @c make process to
|
||||
rebuild the autotools outputs, included the automake-generated Makefiles
|
||||
themselves. This avoids the heavy-handed approach of running the
|
||||
@c bootstrap script after changing one of these files.
|
||||
|
||||
@section primerautomake Automake Makefiles
|
||||
|
||||
The @c automake program generates @c Makefile.in files (from @c
|
||||
Makefile.am files). These files are later processed by the configure
|
||||
script produced by @c autoconf.
|
||||
|
||||
@subsection primerautomakenewfiles Creating Makefile.am Files
|
||||
|
||||
This section shows how to add a @c Makefile.am in a new directory (or
|
||||
one that lacks one).
|
||||
-# The new directory must be listed in the @c SUBDIRS variable in the
|
||||
parent directory's Makefile.am:
|
||||
@code
|
||||
$ echo 'SUBDIRS += directory' >>../Makefile.am
|
||||
@endcode
|
||||
-# Create an bare-bones Makefile.am file in directory that needs it:
|
||||
@code
|
||||
$ echo "MAINTAINERCLEANFILES = Makefile.in" >Makefile.am
|
||||
@endcode
|
||||
-# The @c configure.in script must be updated, so it generates the required
|
||||
Makefile when the @a configure script is run by the user:
|
||||
@verbatim
|
||||
AC_OUTPUT([
|
||||
...
|
||||
path/to/new/Makefile
|
||||
])
|
||||
@endverbatim
|
||||
|
||||
Note: these instructions are @b not meant to be used literally, rather
|
||||
they are shown for demonstration purposes.
|
||||
|
||||
The default MAINTAINERCLEANFILES rule ensures that the
|
||||
automake-generated @c Makefile.in file will be removed when developers
|
||||
run <code>make maintainer-clean</code>. Additional rules may be added
|
||||
after this; however, the project should bootstrap and tear down cleanly
|
||||
after taking these minimal steps, with the new directory being visited
|
||||
during the @c make sequence.
|
||||
|
||||
@subsection primerautomaketweaks Updating Makefile.am Files
|
||||
|
||||
Adding, removing, and renaming files from the project tree usually
|
||||
requires updating the autotools inputs. This section will help describe
|
||||
how to do this as questions arise.
|
||||
|
||||
@section primerlibtool Libtool and Libraries
|
||||
|
||||
The @c libtool program provides the means of generating libraries in a
|
||||
portable and painless manner (relatively speaking).
|
||||
|
||||
This section will contain an answer to "what does libtool give OpenOCD?"
|
||||
and "what do developers need to consider in new code?"
|
||||
|
||||
@section primerautotoolsmation Autotools Automation
|
||||
|
||||
This section outlines three ways the autotools provides automation to
|
||||
assist with testing and distribution:
|
||||
- @ref primerautocheck -- automatic unit and smoke tests
|
||||
- @ref primerautodistcheck -- automatic distribution and packaging tests
|
||||
|
||||
@subsection primerautocheck make check
|
||||
|
||||
The <code>make check</code> command will run the OpenOCD test suite,
|
||||
once it has been integrated as such. This section will contain
|
||||
information about how to extend the testing build system components to
|
||||
implement new checks.
|
||||
|
||||
@subsection primerautodistcheck make distcheck
|
||||
|
||||
The <code>make distcheck</code> command produces an archive of the
|
||||
project deliverables (using <code>make dist</code>) and verifies its
|
||||
integrity for distribution by attemptng to use the package in the same
|
||||
manner as a user.
|
||||
|
||||
These checks includes the following steps:
|
||||
-# Unpack the project archive into its expected directory.
|
||||
-# Configure and build the project in a temporary out-of-tree directory.
|
||||
-# Run <code>make check</code> to ensure the distributed code passes all tests.
|
||||
-# Run <code>make install</code> into a temporary installation directory.
|
||||
-# Check that <code>make uninstall</code> removes all files that were installed.
|
||||
-# Check that <code>make distclean</code> removes all files created
|
||||
during all other steps (except the first).
|
||||
|
||||
If all of these steps complete successfully, the @c make process will
|
||||
output a friendly message indicating the archive is ready to be
|
||||
distributed.
|
||||
|
||||
*/
|
||||
/** @file
|
||||
|
||||
This file contains the @ref primerautotools page.
|
||||
|
||||
*/
|
||||
124
doc/manual/primer/docs.txt
Normal file
124
doc/manual/primer/docs.txt
Normal file
@@ -0,0 +1,124 @@
|
||||
/** @page primerdocs OpenOCD Documentation Primers
|
||||
|
||||
This page provides an introduction to OpenOCD's documentation processes.
|
||||
|
||||
OpenOCD presently produces several kinds of documentation:
|
||||
- The User's Guide:
|
||||
- Focuses on using the OpenOCD software.
|
||||
- Details the installation, usage, and customization.
|
||||
- Provides descriptions of public Jim/TCL script commands.
|
||||
- Written using GNU texinfo.
|
||||
- Created with 'make pdf' or 'make html'.
|
||||
- See @subpage primertexinfo and @ref styletexinfo.
|
||||
- The References: (as proposed)
|
||||
- Focuses on using specific hardware with OpenOCD.
|
||||
- Details the supported interfaces, chips, boards, and targets.
|
||||
- Provides overview, usage, reference, and FAQ for each device.
|
||||
- Written using LaTeX language with custom macros.
|
||||
- Created with 'make references'.
|
||||
- See @subpage primerlatex and @ref stylelatex.
|
||||
- The Manual:
|
||||
- Focuses on developing the OpenOCD software.
|
||||
- Details the architecutre, driver interfaces, and processes.
|
||||
- Provides "full" coverage of C source code (work-in-progress).
|
||||
- Written using Doxygen C language conventions (i.e. in comments).
|
||||
- Created with 'make doxygen'.
|
||||
- See @subpage primerdoxygen and @ref styledoxygen.
|
||||
|
||||
The following sections provide more information for anyone that wants to
|
||||
contribute new or updated documentation to the OpenOCD project.
|
||||
|
||||
*/
|
||||
/** @page primertexinfo Texinfo Primer
|
||||
|
||||
The OpenOCD User's Guide presently exists entirely within the
|
||||
doc/openocd.texi document. That file contains documentation with
|
||||
mark-up suitable for being parsed by the GNU Texinfo utilities
|
||||
(http://www.gnu.org/software/texinfo/).
|
||||
|
||||
When you add a new command, driver, or driver option, it needs to be
|
||||
documented in the User's Guide. Use the existing documentation for
|
||||
models, but feel free to make better use of Texinfo mechanisms. See
|
||||
the Texinfo web site for the Texinfo manual and more information.
|
||||
|
||||
OpenOCD style guidelines for Texinfo documentation can be found on the
|
||||
@ref styletexinfo page.
|
||||
|
||||
*/
|
||||
/** @page primerlatex LaTeX Primer
|
||||
|
||||
The OpenOCD project provides a number of reference guides using the
|
||||
LaTeX typesetting language.
|
||||
|
||||
- OpenOCD Quick Reference Sheets
|
||||
- OpenOCD Hardware Reference Guides
|
||||
|
||||
These documents have not yet been produced, so this Primer serves as
|
||||
a placeholder to describe how they are created and can be extended.
|
||||
The same holds true for the @ref stylelatex page.
|
||||
|
||||
*/
|
||||
/** @page primerdoxygen Doxygen Primer
|
||||
|
||||
Doxygen-style comments are used to provide documentation in-line with
|
||||
the OpenOCD source code. These comments are used to document functions,
|
||||
variables, structs, enums, fields, and everything else that might need
|
||||
to be documented for developers. Additional files containing comments
|
||||
that supplement the code comments in order to provide complete developer
|
||||
documentation.
|
||||
|
||||
Even if you already know Doxygen, please read this Primer to learn
|
||||
how OpenOCD developers already use Doxygen features in the project tree.
|
||||
For more information about OpenOCD's required style for using Doxygen,
|
||||
see the @ref styledoxygen page and look at existing documentation in the
|
||||
@c doc/manual tree.
|
||||
|
||||
@section primerdoxytext Doxygen Input Files
|
||||
|
||||
Doxygen has been configured parse all of the C source code files (*.c
|
||||
and *.h) in @c src/ in order to produce a complete reference of all
|
||||
OpenOCD project symbols. In addition to the source code files, other
|
||||
files will also be scanned for comment blocks; some are referenced
|
||||
explicitly by the @c INPUT variable in the Doxygen configuration file.
|
||||
|
||||
By default, the Doxygen configuration enables a "full" set of features,
|
||||
including generation of dependency graphs (using the GraphViz package).
|
||||
These features may be disabled by editing the @c Doxyfile.in file at the
|
||||
top of the project tree; the configuration file includes comments that
|
||||
provide detailed documentation for each option.
|
||||
|
||||
To support out-of-tree building of the documentation, the @c Doxyfile.in
|
||||
@c INPUT values will have all instances of the string @c "@srcdir@"
|
||||
replaced with the current value of the make variable
|
||||
<code>$(srcdir)</code>. The Makefile uses a rule to convert
|
||||
@c Doxyfile.in into the @c Doxyfile used by <code>make doxygen</code>.
|
||||
|
||||
@section primerdoxyoocd OpenOCD Input Files
|
||||
|
||||
OpenOCD uses the @c INPUT mechanism to include additional documentation to
|
||||
provide The Manual for OpenOCD Developers. These extra files contain
|
||||
high-level information intended to supplement the relatively low-level
|
||||
documentation that gets extracted from the source code comments.
|
||||
|
||||
OpenOCD's Doxygen configuration file will search for all @c .txt files
|
||||
that can be found under the @c doc/manual directory in the project tree.
|
||||
New files containing valid Doxygen markup that are placed in or under
|
||||
that directory will be detected and included in The Manual automatically.
|
||||
|
||||
@section primerdoxyman Doxygen Reference Manual
|
||||
|
||||
The full documentation for Doxygen can be referenced on-line at the project
|
||||
home page: http://www.doxygen.org/index.html. In HTML versions of this
|
||||
document, an image with a link to this site appears in the page footer.
|
||||
|
||||
*/
|
||||
/** @file
|
||||
|
||||
This file contains the Doxygen source code for the @ref primerdocs.
|
||||
The @ref primerdocs page also contains the following sections:
|
||||
|
||||
- @ref primertexinfo
|
||||
- @ref primerlatex
|
||||
- @ref primerdoxygen
|
||||
|
||||
*/
|
||||
174
doc/manual/primer/jtag.txt
Normal file
174
doc/manual/primer/jtag.txt
Normal file
@@ -0,0 +1,174 @@
|
||||
/** @page primerjtag OpenOCD JTAG Primer
|
||||
|
||||
JTAG is unnecessarily confusing, because JTAG is often confused with
|
||||
boundary scan, which is just one of its possible functions.
|
||||
|
||||
JTAG is simply a communication interface designed to allow communication
|
||||
to functions contained on devices, for the designed purposes of
|
||||
initialisation, programming, testing, debugging, and anything else you
|
||||
want to use it for (as a chip designer).
|
||||
|
||||
Think of JTAG as I2C for testing. It doesn't define what it can do,
|
||||
just a logical interface that allows a uniform channel for communication.
|
||||
|
||||
See @par
|
||||
http://en.wikipedia.org/wiki/Joint_Test_Action_Group
|
||||
|
||||
and @par
|
||||
http://www.inaccessnetworks.com/projects/ianjtag/jtag-intro/jtag-state-machine-large.png
|
||||
|
||||
The first page (among other things) shows a logical representation
|
||||
describing how multiple devices are wired up using JTAG. JTAG does not
|
||||
specify, data rates or interface levels (3.3V/1.8V, etc) each device can
|
||||
support different data rates/interface logic levels. How to wire them
|
||||
in a compatible way is an exercise for an engineer.
|
||||
|
||||
Basically TMS controls which shift register is placed on the device,
|
||||
between TDI and TDO. The second diagram shows the state transitions on
|
||||
TMS which will select different shift registers.
|
||||
|
||||
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
|
||||
to clock TMS as 1, at least 7 times. This will put you into "Test Logic
|
||||
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
|
||||
machine is in.
|
||||
|
||||
There are 2 "types" of shift registers. The Instruction shift register
|
||||
and the data shift register. The sizes of these are undefined, and can
|
||||
change from chip to chip. The Instruction register is used to select
|
||||
which Data register/data register function is used, and the data
|
||||
register is used to read data from that function or write data to it.
|
||||
|
||||
Each of the states control what happens to either the data register or
|
||||
instruction register.
|
||||
|
||||
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
|
||||
chip. Assume we have 3 identical chips, wired up like the picture
|
||||
and each has a 3 bit instruction register, and there are 2 known
|
||||
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
|
||||
the other chips we would do the following transitions.
|
||||
|
||||
From Test Logic Reset, TMS goes:
|
||||
|
||||
0 1 1 0 0
|
||||
|
||||
which puts every chip in the chain into the "Shift IR state"
|
||||
Then (while holding TMS as 0) TDI goes:
|
||||
|
||||
0 1 1 0 1 0 0 1 1
|
||||
|
||||
which puts the following values in the instruction shift register for
|
||||
each chip [110] [010] [110]
|
||||
|
||||
The order is reversed, because we shift out the least significant bit
|
||||
first. Then we transition TMS:
|
||||
|
||||
1 1 1 1 0 0
|
||||
|
||||
which puts us in the "Shift DR state".
|
||||
|
||||
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
|
||||
registers we selected (some other function has 8 bits in its data
|
||||
register), our total data register in the chain looks like this:
|
||||
|
||||
0 00000000 0
|
||||
|
||||
The first and last bit are in the "bypassed" chips, so values read from
|
||||
them are irrelevant and data written to them is ignored. But we need to
|
||||
write bits for those registers, because they are in the chain.
|
||||
|
||||
If we wanted to write 0xF5 to the data register we would clock out of
|
||||
TDI (holding TMS to 0):
|
||||
|
||||
0 1 0 1 0 1 1 1 1 0
|
||||
|
||||
Again, we are clocking the least-significant bit first. Then we would
|
||||
clock TMS:
|
||||
|
||||
1 1 0
|
||||
|
||||
which updates the selected data register with the value 0xF5 and returns
|
||||
us to run test idle.
|
||||
|
||||
If we needed to read the data register before over-writing it with F5,
|
||||
no sweat, that's already done, because the TDI/TDO are set up as a
|
||||
circular shift register, so if you write enough bits to fill the shift
|
||||
register, you will receive the "captured" contents of the data registers
|
||||
simultaneously on TDO.
|
||||
|
||||
That's JTAG in a nutshell. On top of this, you need to get specs for
|
||||
target chips and work out what the various instruction registers/data
|
||||
registers do, so you can actually do something useful. That's where it
|
||||
gets interesting. But in and of itself, JTAG is actually very simple.
|
||||
|
||||
@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
|
||||
developers that want to extend OpenOCD for such purposes.
|
||||
|
||||
*/
|
||||
/** @page primerjtagbs JTAG Boundary Scan Primer
|
||||
|
||||
The following page provides an introduction on JTAG that focuses on its
|
||||
boundary scan capabilities: @par
|
||||
http://www.engr.udayton.edu/faculty/jloomis/ece446/notes/jtag/jtag1.html
|
||||
|
||||
OpenOCD does not presently have clear means of using JTAG for boundary
|
||||
scan testing purposes; however, some developers have explored the
|
||||
possibilities. The page contains information that may be useful to
|
||||
those wishing to implement boundary scan capabilities in OpenOCD.
|
||||
|
||||
@section primerbsdl The BSDL Language
|
||||
|
||||
For more information on the Boundary Scan Description Language (BSDL),
|
||||
the following page provides a good introduction: @par
|
||||
http://www.radio-electronics.com/info/t_and_m/boundaryscan/bsdl.php
|
||||
|
||||
@section primerbsdlvendors Vendor BSDL Files
|
||||
|
||||
NXP LPC: @par
|
||||
http://www.standardics.nxp.com/support/models/lpc2000/
|
||||
|
||||
Freescale PowerPC: @par
|
||||
http://www.freescale.com/webapp/sps/site/overview.jsp?code=DRPPCBSDLFLS
|
||||
|
||||
Freescale i.MX1 (too old): @par
|
||||
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=i.MX1&nodeId=0162468rH311432973ZrDR&fpsp=1&tab=Design_Tools_Tab
|
||||
|
||||
Renesas R32C/117: @par
|
||||
http://sg.renesas.com/fmwk.jsp?cnt=r32c116_7_8_root.jsp&fp=/products/mpumcu/m16c_family/r32c100_series/r32c116_7_8_group/
|
||||
- The device page does not come with BSDL file; you have to register to
|
||||
download them. @par
|
||||
http://www.corelis.com/support/BSDL.htm
|
||||
|
||||
TI links theirs right off the generic page for each chip;
|
||||
this may be the case for other vendors as well. For example:
|
||||
|
||||
- DaVinci DM355 -- http://www.ti.com/litv/zip/sprm262b
|
||||
- DaVinci DM6446
|
||||
- 2.1 silicon -- http://www.ti.com/litv/zip/sprm325a
|
||||
- older silicon -- http://www.ti.com/litv/zip/sprm203
|
||||
- OMAP 3530
|
||||
- CBB package -- http://www.ti.com/litv/zip/sprm315b
|
||||
- 515 ball s-PGBA, POP, 0.4mm pitch
|
||||
- CUS package -- http://www.ti.com/litv/zip/sprm314a
|
||||
- 515 ball s-PGBA, POP, 0.5mm pitch
|
||||
- CBC package -- http://www.ti.com/litv/zip/sprm346
|
||||
- 423 ball s-PGBA, 0.65mm pitch
|
||||
|
||||
Many other files are available in the "Semiconductor Manufacturer's BSDL
|
||||
files" section of the following site: @par
|
||||
http://www.freelabs.com/~whitis/electronics/jtag/
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref primerjtag and @ref primerjtagbs page.
|
||||
*/
|
||||
172
doc/manual/primer/patches.txt
Normal file
172
doc/manual/primer/patches.txt
Normal file
@@ -0,0 +1,172 @@
|
||||
/** @page primerpatches Patch Primer
|
||||
|
||||
This page provides an introduction to patching that may be useful
|
||||
for OpenOCD contributors who are unfamiliar with the process.
|
||||
|
||||
@section primerpatchintro Introduction to Patching
|
||||
|
||||
The standard method for creating patches requires developers to:
|
||||
- checkout the git repository (or bring a copy up-to-date),
|
||||
- make the necessary modifications to a working copy,
|
||||
- check with 'git status' to see which files will be modified/added, and
|
||||
- use 'git diff' to review the changes and produce a patch.
|
||||
|
||||
It is important to minimize the changes to only those lines that contain
|
||||
important differences; do not allow stray whitespace changes into your
|
||||
patches, and keep the focus to a single logical change.
|
||||
|
||||
@section primerpatchcreate Creating Patches
|
||||
|
||||
You can create a patch (from the root of your working copy) with a
|
||||
command like the following example: @par
|
||||
@verbatim
|
||||
git diff > patch-name.patch
|
||||
@endverbatim
|
||||
|
||||
where @a patch-name should be something that is descriptive and unique.
|
||||
|
||||
The above command will create a patch containing all of the changes in
|
||||
the working copy; if you want to obtain a subset, simply provide the
|
||||
list of files to the command: @par
|
||||
@verbatim
|
||||
git diff doc > <patch-name>-doc.patch
|
||||
git diff src > <patch-name>-src.patch
|
||||
@endverbatim
|
||||
|
||||
This will create two patches, each containing only those changes present
|
||||
in the subdirectory specified.
|
||||
|
||||
@subsection primerpatchcreate Naming Patches
|
||||
|
||||
One developer has evolved an informal standard for naming his patches: @par
|
||||
@verbatim
|
||||
<project>-<lod>-<action>-<task>.patch
|
||||
@endverbatim
|
||||
|
||||
where @a project is @c openocd, @a lod (line-of-development) could be a
|
||||
subsystem (e.g. @c jtag, @c jlink, etc.) or other group identifier,
|
||||
@a action is @c add, @c change, @c fix, @c update, etc., and @a task is
|
||||
whatever the patch will accomplish (in 2-4 words).
|
||||
|
||||
This scheme does not need to be followed, but it is helpful for
|
||||
maintainers that receive many patches. You do not want your own
|
||||
@c openocd.patch file to be accidentally overwritten by another
|
||||
submission, sending your patch to the bit bucket on accident.
|
||||
|
||||
@section primerpatchpreflight Developer Review
|
||||
|
||||
Before sending in patches, please make sure you have updated to the
|
||||
latest version of the trunk (using <code>git pull</code>) before creating
|
||||
your patch. This helps to increase the chances that it will apply
|
||||
cleanly to the trunk. However, the content matters most.
|
||||
|
||||
When creating a patch using "<code>git diff</code>", git will
|
||||
produce a patch that contains all of the changes in your working copy.
|
||||
To manage multiple changes at once, you either need one working copy per
|
||||
patch, or you can specified specific files and directories when using
|
||||
<code>git diff</code>. Overlapping patches will be discussed in the
|
||||
next section.
|
||||
|
||||
@todo Does git's treatment of line-endings behave sanely?
|
||||
Basically, the repository should use newlines internally,
|
||||
and convert to/from CRLF on Windows etc.
|
||||
|
||||
@section primerpatchseries Patch Series
|
||||
|
||||
As was mentioned above, each patch should contain one logical @c task,
|
||||
and multiple logical tasks should be split into a series of patches.
|
||||
There are no hard guidelines for how that is to be done; it's an art
|
||||
form. Many simple changes should not have to worry about being split,
|
||||
as they will naturally represent a single task.
|
||||
|
||||
When working on several different non-intersecting lines of development,
|
||||
a combination of multiple working copies and patch series management
|
||||
techniques can become critical to efficiently managing change. This
|
||||
again is an area where developers have favorite methodologies that are
|
||||
simply a matter of taste or familiarity; your mileage may vary.
|
||||
|
||||
Packages such as @c patchutils, @c diffutils, and @c quilt are among
|
||||
those that have proved themselves invaluable for these type of tasks.
|
||||
Others take their patch management a step further, using stkgit or
|
||||
some other framework on top of git.
|
||||
|
||||
@subsection primerpatchseriesinterdiff Using @c interdiff
|
||||
|
||||
The @c patchutils package includes the @c interdiff command, which
|
||||
produces a patch that contains the changes made between two other
|
||||
patches. This command can be used to manage the creation of trivial
|
||||
patch series. For example, the following sequence of commands will
|
||||
produce three patches: @par
|
||||
@verbatim
|
||||
$ cd openocd/
|
||||
$ git pull
|
||||
...
|
||||
$ <<<start changes for patch #1>>>
|
||||
...
|
||||
$ <<<finish changes for patch #1>>>
|
||||
$ git diff > series-1.patch # patch #1 is easy
|
||||
$ <<<start changes for patch #2>>>
|
||||
...
|
||||
$ <<<finish changes for patch #2>>>
|
||||
$ git diff > series-1+2.patch # create patch 1+2
|
||||
$ interdiff series-1{,+2}.patch > series-2.patch # 1 ~ 1+2 => #2
|
||||
$ <<<start changes for patch #3>>>
|
||||
...
|
||||
$ <<<finish changes for patch #3>>>
|
||||
$ git diff > series-1+2+3.patch # create patch 1+2+3
|
||||
$ interdiff series-1+2{,+3}.patch > series-3.patch # 1+2 ~ 1+2+3 => 3
|
||||
@endverbatim
|
||||
|
||||
This technique falls apart when the repository changes, but this may be
|
||||
suitable for small series of patches.
|
||||
|
||||
@subsection primerpatchseriesquilt Using @c quilt
|
||||
|
||||
The @c quilt package provides scripts to manage series of patches more
|
||||
efficiently than can be managed by hand. For out-of-tree work projects
|
||||
that require such patch management, @c quilt provides an indispensable
|
||||
tool for solving the problem.
|
||||
|
||||
@section primerpatchsubmit Submitting Patches
|
||||
|
||||
Write access to the OpenOCD git repository is limited to
|
||||
contributors that have demonstrated the ability to produce clear,
|
||||
consistent, and frequent patches. These individuals are responsible
|
||||
for maintaining the integrity of the repository for the community.
|
||||
|
||||
Thus, commits to the git repository must be handled by one of
|
||||
these maintainers.
|
||||
|
||||
Patches must be sent to the OpenOCD developer mailing list:
|
||||
@par
|
||||
openocd-development@lists.berlios.de
|
||||
|
||||
They will be reviewed and committed if the changes are found to be
|
||||
acceptable. If there are problems, you will receive feedback via the
|
||||
mailing list; in general, the maintainers prefer all communication to go
|
||||
through the list, as the entire community needs to judge contributions
|
||||
for possible merits and mistakes.
|
||||
|
||||
Contributors may be asked to address certain issues and submit a new
|
||||
patch. In the event that it gets overlooked, you may need to resubmit
|
||||
it or prompt for feedback. Please have patience, as many maintainers
|
||||
work on the project voluntarily and without compensation for the time
|
||||
that they spend doing these tasks.
|
||||
|
||||
@section primerpatchguide Guidelines for Submitting Patches
|
||||
|
||||
- Each patch file should contain:
|
||||
- A commit description that describes all of the changes.
|
||||
- A separator line that contains three hyphens: <code>---</code>
|
||||
- A summary of the changes produced by diffstat (optional)
|
||||
- Another separator line (optional)
|
||||
- The actual patch contents, containing a single change.
|
||||
|
||||
- Each patch series should include:
|
||||
- A summary of the patches in the series.
|
||||
- Logically-related patches that contain incremental changes.
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref primerpatches page.
|
||||
*/
|
||||
@@ -1,3 +1,9 @@
|
||||
/** @page primertcl OpenOCD TCL Primer
|
||||
|
||||
The @subpage scripting page provides additional TCL Primer material.
|
||||
|
||||
@verbatim
|
||||
|
||||
****************************************
|
||||
****************************************
|
||||
|
||||
@@ -215,8 +221,8 @@ All memory regions must have 2 things:
|
||||
LEN
|
||||
HUMAN
|
||||
TYPE
|
||||
RWX - the access ablity.
|
||||
WIDTH - the accessable width.
|
||||
RWX - the access ability.
|
||||
WIDTH - the accessible width.
|
||||
|
||||
ie: Some regions of memory are not 'word'
|
||||
accessible.
|
||||
@@ -428,3 +434,7 @@ END of the Tcl Intro and Walk Through
|
||||
FUTURE PLANS
|
||||
|
||||
Some "GPIO" functions...
|
||||
|
||||
@endverbatim
|
||||
|
||||
*/
|
||||
353
doc/manual/release.txt
Normal file
353
doc/manual/release.txt
Normal file
@@ -0,0 +1,353 @@
|
||||
/** @page releases Release Processes
|
||||
|
||||
This page provides an introduction to the OpenOCD Release Processes:
|
||||
|
||||
- @ref releasewhy - Explain the motivations for producing
|
||||
releases on a regular basis.
|
||||
- @ref releasewho - Describes the responsibilities and
|
||||
authority required to produce official OpenOCD releases.
|
||||
- @ref releasewhen - Provides guidelines for scheduling
|
||||
activities for each release cycle.
|
||||
- @ref releasehow - Outlines all of the steps for the
|
||||
processes used to produce and release the package source archives.
|
||||
- @ref releasescript - Introduces the automated @c release.sh script.
|
||||
|
||||
@section releasewhy Why Produce Releases?
|
||||
|
||||
The OpenOCD maintainers produce <i>releases</i> periodically for many
|
||||
reasons. This section provides the key reasons for making releases on a
|
||||
regular basis and why a set of <i>release processes</i> should be used
|
||||
to produce them.
|
||||
|
||||
At any time, <i>source archives</i> can be produced by running
|
||||
<code>make dist</code> in the OpenOCD project tree. With the 0.2.0
|
||||
release, this command will package the tree into several popular archive
|
||||
formats: <code>openocd-\<version\>.{tar.gz,tar.bz2,zip}</code>. If
|
||||
produced properly, these files are suitable for release to the public.
|
||||
|
||||
When released for users, these archives present several important
|
||||
advantages when contrasted to using the git repository:
|
||||
|
||||
-# They allow others to package and distribute the code.
|
||||
-# They build easier for developers, because they contain
|
||||
a working configure script that was produced by the Release Manager.
|
||||
-# They prevent users from trying a random work-in-process revision.
|
||||
-# They free developers from answering questions about mainline breakage.
|
||||
|
||||
Hopefully, this shows several good reasons to produce regular releases,
|
||||
but the release processes were developed with some additional design
|
||||
goals in mind. Specifically, the releases processes should have the
|
||||
following properties:
|
||||
|
||||
-# Produce successive sets of archives cleanly and consistently.
|
||||
-# Implementable as a script that automates the critical steps.
|
||||
-# Prevent human operators from producing broken packages, when possible.
|
||||
-# Allow scheduling and automation of building and publishing milestones.
|
||||
|
||||
The current release processes are documented in the following sections.
|
||||
They attempt to meet these design goals, but there may improvements
|
||||
remaining to be made toward automating the process.
|
||||
|
||||
@section releaseversions Release Versions
|
||||
|
||||
The OpenOCD version string is composed of three numeric components
|
||||
separated by two decimal points: @c x.y.z, where @c x is the @a major
|
||||
version number, @c y is the @a minor number, and @c z is the @a micro.
|
||||
|
||||
For a <i>bug-fix</i> release, the micro version number will be non-zero
|
||||
(<code>z > 0</code>). For a <i>minor release</i>, the micro version
|
||||
number will be zero (<code>z = 0</code>). For a <i>major releases</i>,
|
||||
the minor version will @a also be zero (<code>y = 0, z = 0</code>).
|
||||
|
||||
@subsection releaseversiontags Version Tags
|
||||
|
||||
After these required numeric components, the version string may contain
|
||||
one or more <i>version tags</i>, such as '-rc1' or '-dev'.
|
||||
|
||||
Mainline and all branches should have the tag '-dev' in
|
||||
their version number. This tag helps developers identify reports
|
||||
created from the git repository, and it can be detected and
|
||||
manipulated by the release script. Specifically, this tag will be
|
||||
removed and re-added during the release process; it should never be
|
||||
manipulated by developers in submitted patches.
|
||||
|
||||
The 'rc' tags indicate a "release candidate" version of the package.
|
||||
This tag will also be manipulated by the automated release process.
|
||||
|
||||
Additional tags may be used as necessary.
|
||||
|
||||
@subsection releaseversionsdist Packager Versions
|
||||
|
||||
Distributors of patched versions of OpenOCD are encouraged to extend the
|
||||
version string with a unique version tag when producing external
|
||||
releases, as this helps to identify your particular distribution series.
|
||||
|
||||
For example, the following command will add a 'foo1' tag to the
|
||||
configure.in script of a local copy of the source tree:
|
||||
|
||||
@code
|
||||
tools/release.sh version bump tag foo
|
||||
@endcode
|
||||
|
||||
This command will modify the configure.in script in your working copy
|
||||
only. After running the @c bootstrap sequence, the tree can be patched
|
||||
and used to produce your own derived versions. The same command can be
|
||||
used each time the derived package is released, incrementing the tag's
|
||||
version to facilitate tracking the changes you have distributed.
|
||||
|
||||
@subsection releaseversionhow Version Processes
|
||||
|
||||
The release process includes version number manipulations to the tree
|
||||
being released, ensuring that all numbers are incremented at the right
|
||||
time and in the proper locations of the repository.
|
||||
|
||||
The version numbers for any branch should increase monotonically
|
||||
to the next successive integer, except when reset to zero
|
||||
during major or minor releases. The community should decide when
|
||||
major and minor milestones will be released.
|
||||
|
||||
@section releasewho Release Manager
|
||||
|
||||
OpenOCD archive releases will be produced by an individual filling the
|
||||
role of <i>Release Manager</i>, hereafter abbreviated as <i>RM</i>. This
|
||||
individual determines the schedule and executes the release processes
|
||||
for the community.
|
||||
|
||||
@subsection releasewhohow RM Authority
|
||||
|
||||
Each release requires one individual to fulfill the RM role; however,
|
||||
graceful transitions of this authority may take place at any time. The
|
||||
current RM may transfer their authority to another contributor in a post
|
||||
to the OpenOCD development mailing list. Such delegation of authority
|
||||
must be approved by the individual that will receive it and the
|
||||
community of maintainers. Initial arrangements with the new RM should
|
||||
be made off-list, as not every contributor wants these responsibilities.
|
||||
|
||||
@subsection releasewhowhat RM Responsibilities
|
||||
|
||||
In addition to the actual process of producing the releases, the RM is
|
||||
responsible for keeping the community informed of all progress through
|
||||
the release cycle(s) being managed. The RM is responsible for managing
|
||||
the changes to the package version, though the release tools should
|
||||
manage the tasks of adding or removing any required development branch
|
||||
tags and incrementing the version.
|
||||
|
||||
@section releasewhen Release Schedule
|
||||
|
||||
The OpenOCD release process must be carried out on a periodic basis, so
|
||||
the project can realize the benefits presented in answer to the question,
|
||||
@ref releasewhy.
|
||||
|
||||
Starting with the 0.2.0 release, the OpenOCD project should produce a
|
||||
new minor release every month or two, with a major release once a year.
|
||||
Bug fix releases could be provided more frequently. These release
|
||||
schedule goals may be adjusted in the future, after the project
|
||||
maintainers and distributors receive feedback and experience.
|
||||
|
||||
More importantly, the statements made in this section do not create an
|
||||
obligation by any member of the OpenOCD community to produce new
|
||||
releases on regular schedule, now or in the future.
|
||||
|
||||
@subsection releasewhenexample Sample Schedule
|
||||
|
||||
The RM must pro-actively communicate with the community from the
|
||||
beginning of the development cycle through the delivery of the new
|
||||
release. This section presents guidelines for scheduling key points
|
||||
where the community must be informed of changing conditions.
|
||||
|
||||
If T is the time of the next release, then the following schedule
|
||||
might describe some of the key milestones of the new release cycle:
|
||||
|
||||
- T minus one month: start of new development cycle
|
||||
- T minus two weeks: announce pending mainline closure to new work
|
||||
- T minus one week: close mainline to new work, begin testing phase
|
||||
- T minus two days: call for final bug fixes
|
||||
- T minus one day: produce -rc packages and distribute to testers
|
||||
- T minus one hour: produce final packages and post on-line
|
||||
- T minus zero: Announce the release to our mailing list and the world.
|
||||
|
||||
Some additional supplemental communication will be desirable. The above
|
||||
list omits the step-by-step instructions to daily release management.
|
||||
Individuals performing release management need to have the ability to
|
||||
interact proactively with the community as a whole, anticipating when
|
||||
such interaction will be required and giving ample notification.
|
||||
|
||||
The next section explains why the OpenOCD project allows significant
|
||||
flexibility in the part of the development that precedes the release
|
||||
process.
|
||||
|
||||
@note The OpenOCD project does not presently produce -rc packages. As
|
||||
such, the step suggested in the list above should be read as trying to
|
||||
stimulate others to test the project build and packaging on as many
|
||||
platforms as possible. This proposition will be palatable once release
|
||||
management tools have been committed to the tree.
|
||||
|
||||
@subsection releasewhenflex Schedule Flexibility
|
||||
|
||||
The Release Manager should attempt to follow the guidelines in this
|
||||
document, but the process of scheduling each release milestone should be
|
||||
community driven at the start. By the end, missing features that were
|
||||
scheduled for a release must be dropped by the Release Manager, rather
|
||||
than allowing the release cycle to be delayed while waiting for them.
|
||||
|
||||
Despite any assurances this schedule may appear to give, the Release
|
||||
Manager cannot schedule the work that will be done on the project,
|
||||
when it will be submitted, reviewed, and deemed suitable to be committed.
|
||||
In this way, the RM cannot act as a priest in a cathedral; OpenOCD uses
|
||||
the bazaar development model. The release schedule must adapt
|
||||
continuously in response to changes in the rate of churn.
|
||||
|
||||
In particular, the suggested period of "one or two month" reflects some
|
||||
expectation of a fairly high rate of development. Fewer releases may be
|
||||
required if developers contribute less patches, and more releases may be
|
||||
desirable if the project continues to grow and experience high rates of
|
||||
community contribution. During each cycle, the RM should be tracking
|
||||
the situation and gathering feedback from the community.
|
||||
|
||||
@section releasehow Release Process: Step-by-Step
|
||||
|
||||
The release process may require a few iterations to work out any bugs.
|
||||
Even with the release script, some steps require clear user intervention
|
||||
-- and not only by the Release Manager.
|
||||
|
||||
The following steps should be followed to produce each release:
|
||||
|
||||
-# Produce final manual patches to mainline (or release branch):
|
||||
-# Finalize @c NEWS file to describe the changes in the release
|
||||
- This file is Used to automatically post "blurbs" about the project.
|
||||
- This material should be produced during the development cycle.
|
||||
- Add a new item for each @c NEWS-worthy contribution, when committed.
|
||||
-# Bump library version if our API changed (not yet required)
|
||||
-# Produce and tag the final revision in the git repository:
|
||||
- Update and commit the final package version in @c configure.in :
|
||||
-# Remove @c -dev tag.
|
||||
-# Remove @c -rc tag, if producing the final release from an -rc series.
|
||||
- Tags must be named consistently:
|
||||
@verbatim
|
||||
@endverbatim
|
||||
- Tag the final commit with a consistent GIT tag name and message:
|
||||
@verbatim
|
||||
PACKAGE_VERSION="x.y.z"
|
||||
PACKAGE_TAG="v${PACKAGE_VERSION}"
|
||||
git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
|
||||
@endverbatim
|
||||
-# Prepare to resume normal development on the branch:
|
||||
- Restore @c -dev and -@c -rc0 version tags.
|
||||
- To start a new major (or minor) release cycle on the @c master branch:
|
||||
- Bump major (or minor) package version, zeroing sub-components.
|
||||
- Add -rc0 version tag:
|
||||
- This insures casual releases from GIT always increase monotonically.
|
||||
- For example, a major increment after releasing 1.2.3 starts 2.0.0-rc0-dev.
|
||||
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
|
||||
- Create a new @c NEWS file for the next release
|
||||
- To start a bug-fix release on a non-master branch:
|
||||
-# Bump bug-fix version.
|
||||
- To start another release candidate on a major or minor branch:
|
||||
-# Bump rc tag.
|
||||
-# Produce the package source archives:
|
||||
-# Start with a clean working copy, used for producing releases only.
|
||||
-# Checkout the appropriate tag:
|
||||
<code>git checkout $(git tag ) "${PACKAGE_VERSION}"</code>
|
||||
-# Produce a ChangeLog for the release (using @c git2cl).
|
||||
-# @c bootstrap, @c configure, and @c make the package.
|
||||
-# Run <code>make distcheck</code> to produce the distribution archives.
|
||||
-# Run <code>make maintainer-clean</code> verify the repository is empty.
|
||||
-# Create signature files using @c md5sum, @c sha1sum, etc.
|
||||
-# 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
|
||||
- @c ChangeLog: to show exactly what has been changed
|
||||
- User 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 and ChangeLog files, 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.).
|
||||
|
||||
@section releasescript The Release Script
|
||||
|
||||
Many of the processes described in the last section are no longer
|
||||
entrusted to humans. Instead, the @c release.sh script provides
|
||||
automation of the mechanical steps.
|
||||
|
||||
Presently, the @c release.sh script automates steps 2 through 4,
|
||||
allowing the Release Manager from perform these tasks in easy steps.
|
||||
|
||||
The following task still need to be automated:
|
||||
|
||||
- Step 5: produce documentation for website using released source archive.
|
||||
- Step 6(a): package archive upload process.
|
||||
- Step 6(b): package announcement e-mail process.
|
||||
- Step 6(c): post files and announce them using releaseforge.
|
||||
|
||||
@subsection releasescriptcmds Release Script Commands
|
||||
|
||||
The release script can be used for two tasks:
|
||||
- Creating releases and starting a new release cycle:
|
||||
@code
|
||||
git checkout master
|
||||
tools/release.sh --type=minor --final --start-rc release
|
||||
@endcode
|
||||
- Creating a development branch from a tagged release:
|
||||
@code
|
||||
git checkout 'v0.2.0'
|
||||
tools/release.sh --type=micro branch
|
||||
@endcode
|
||||
|
||||
Both of these variations make automatic commits and tags in your
|
||||
repository, so you should be sure to run it on a cloned copy before
|
||||
proceding with a live release.
|
||||
|
||||
@subsection releasescriptopts Release Script Options
|
||||
|
||||
The @c release.sh script recognizes some command-line options that
|
||||
affect its behavior:
|
||||
|
||||
- The @c --start-rc indicates that the new development release cycle
|
||||
should start with @c -rc0. Without this, the @c -rc tag will be omitted,
|
||||
leading to non-monotonic versioning of the in-tree version numbers.
|
||||
- The @c --final indicates that the release should drop the @c -rc tag,
|
||||
to going from @c x.y.z-rcN-dev to x.y.z.
|
||||
|
||||
@subsection releasescriptenv Release Script Environment
|
||||
|
||||
The @c release.sh script recognizes some environment variables which
|
||||
affect its behavior:
|
||||
|
||||
- @c CONFIG_OPTS : Passed as options to the configure script.
|
||||
- @c MAKE_OPTS : Passed as options to the 'make' processes.
|
||||
|
||||
@section releasetutorial Release Tutorials
|
||||
|
||||
This section should contain a brief tutorial for using the Release
|
||||
Script to perform release tasks, but the new script needs to be
|
||||
used for 0.3.0.
|
||||
|
||||
@section releasetodo Release Script Shortcomings
|
||||
|
||||
Improved automated packaging and distribution of OpenOCD requires more
|
||||
patching of the configure script. The final release script should be
|
||||
able to manage most steps of the processes. The steps requiring user
|
||||
input could be guided by an "assistant" that walks the Release Manager
|
||||
through the process from beginning to end, performing basic sanity
|
||||
checks on their various inputs (e.g. the @c NEWS blurb).
|
||||
|
||||
*/
|
||||
/** @file
|
||||
This file contains the @ref releases page.
|
||||
*/
|
||||
@@ -1,14 +1,12 @@
|
||||
Plan for hosted scripting support in OpenOCD
|
||||
============================================
|
||||
/** @page scripting Scripting Overview
|
||||
|
||||
What scripting will not do
|
||||
==========================
|
||||
@section scriptingisnt What scripting will not do
|
||||
|
||||
The scripting support is intended for developers of OpenOCD.
|
||||
It is not the intention that normal OpenOCD users will
|
||||
use tcl scripting extensively, write lots of clever scripts,
|
||||
or contribute back to OpenOCD.
|
||||
|
||||
The scripting support is intended for developers of OpenOCD.
|
||||
|
||||
Target scripts can contain new procedures that end users may
|
||||
tinker to their needs without really understanding tcl.
|
||||
|
||||
@@ -17,21 +15,21 @@ language, the choice of language is not terribly important
|
||||
to those same end users.
|
||||
|
||||
Jim Tcl was chosen as it was easy to integrate, works
|
||||
great in an embedded environment and Øyvind Harboe
|
||||
great in an embedded environment and Øyvind Harboe
|
||||
had experience with it.
|
||||
|
||||
Uses of scripting
|
||||
=================
|
||||
@section scriptinguses Uses of scripting
|
||||
|
||||
Default implementation of procedures in tcl/procedures.tcl.
|
||||
|
||||
- Polymorphic commands for target scripts.
|
||||
- there will be added some commands in Tcl that the target
|
||||
scripts can replace.
|
||||
- produce <productionfile> <serialnumber>. Default implementation
|
||||
- produce \<productionfile\> \<serialnumber\>. Default implementation
|
||||
is to ignore serial number and write a raw binary file
|
||||
to beginning of first flash. Target script can dictate
|
||||
file format and structure of serialnumber. Tcl allows
|
||||
an argument to consit of e.g. a list so the structure of
|
||||
an argument to consist of e.g. a list so the structure of
|
||||
the serial number is not limited to a single string.
|
||||
- reset handling. Precise control of how srst, trst &
|
||||
tms is handled.
|
||||
@@ -54,8 +52,8 @@ Default implementation of procedures in tcl/procedures.tcl.
|
||||
be simpler.
|
||||
|
||||
|
||||
External scripting
|
||||
==================
|
||||
@section scriptingexternal External scripting
|
||||
|
||||
The embedded Jim Tcl interpreter in OpenOCD is very limited
|
||||
compared to any full scale PC hosted scripting language.
|
||||
|
||||
@@ -78,3 +76,5 @@ unknown commands to OpenOCD.
|
||||
|
||||
Basically a PC version of startup.tcl. Patches most
|
||||
gratefully accepted! :-)
|
||||
|
||||
*/
|
||||
325
doc/manual/server.txt
Normal file
325
doc/manual/server.txt
Normal file
@@ -0,0 +1,325 @@
|
||||
/** @page serverdocs OpenOCD Server APIs
|
||||
|
||||
OpenOCD provides support for implementing different types of servers.
|
||||
Presently, the following servers have APIs that can be used.
|
||||
|
||||
- @subpage servergdb
|
||||
- @subpage servertelnet
|
||||
- @subpage serverhttp
|
||||
|
||||
@section serverdocsoverview Overview
|
||||
|
||||
What follows is a development history, and describes some of the intent
|
||||
of why certain features exist within OpenOCD along with the reasoning
|
||||
behind them.
|
||||
|
||||
This roadmap section was written May 2009 - about 9 to 12 months
|
||||
after some of this work had started, it attempts to document some of
|
||||
the reasons why certain features exist within OpenOCD at that time.
|
||||
|
||||
@section serverdocsbg Background
|
||||
|
||||
In early 2008, Oyvind Harboe and Duane Ellis had talked about how to
|
||||
create a reasonable GUI for OpenOCD - something that is non-invasive,
|
||||
simple to use and maintain, and does not tie OpenOCD to many other
|
||||
packages. It would be wrong to "spider web" requirements into other
|
||||
external external packages. That makes it difficult for developers to
|
||||
write new code and creates a support nightmare.
|
||||
|
||||
In many ways, people had talked about the need for some type of
|
||||
high-level interface to OpenOCD, because they only had two choices:
|
||||
- the ability to script: via an external program the actions of OpenOCD.
|
||||
- the ablity to write a complex internal commands: native 'commands'
|
||||
inside of OpenOCD was complicated.
|
||||
|
||||
Fundamentally, the basic problem with both of those would be solved
|
||||
with a script language:
|
||||
|
||||
-# <b>Internal</b>: simple, small, and self-contained.
|
||||
-# <b>Cross Language</b>: script friendly front-end
|
||||
-# <b>Cross Host</b>: GUI Host interface
|
||||
-# <b>Cross Debugger</b>: GUI-like interface
|
||||
|
||||
What follows hopefully shows how the plans to solve these problems
|
||||
materialized and help to explain the grand roadmap plan.
|
||||
|
||||
@subsection serverdocsjim Why JimTCL? The Internal Script Language
|
||||
|
||||
At the time, the existing "command context schema" was proving itself
|
||||
insufficient. However, the problem was also considered from another
|
||||
direction: should OpenOCD be first class and the script second class?
|
||||
Which one rules?
|
||||
|
||||
In the end, OpenOCD won, the conclusion was that simpler will be better.
|
||||
Let the script language be "good enough"; it would not need numerous
|
||||
features. Imagine debugging an embedded Perl module while debugging
|
||||
OpenOCD. Yuck. OpenOCD already has a complex enough build system, why
|
||||
make it worse?
|
||||
|
||||
The goal was to add a simple language that would be moderately easy to
|
||||
work with and be self-contained. JimTCL is a single C and single H
|
||||
file, allowing OpenOCD to avoid the spider web of dependent packages.
|
||||
|
||||
@section serverdocstcl TCL Server Port
|
||||
|
||||
The TCL Server port was added in mid-2008. With embedded TCL, we can
|
||||
write scripts internally to help things, or we can write "C" code that
|
||||
interfaces well with TCL.
|
||||
|
||||
From there, the developers wanted to create an external front-end that
|
||||
would be @a very usable and that that @a any language could utilize,
|
||||
allowing simple front-ends to be (a) cross-platform (b) languag
|
||||
agnostic, and (c) easy to develop and use.
|
||||
|
||||
Simple ASCII protocols are easy. For example, HTTP, FTP (control), and
|
||||
SMTP are all text-based. All of these examples are widely and
|
||||
well-known, and they do not require high-speed or high-volume. They
|
||||
also support a high degree of interoperability with multiple systems.
|
||||
They are not human-centric protocols; more correctly, they are rigid,
|
||||
terse, simple ASCII protocols that are emensely parsable by a script.
|
||||
|
||||
Thus, the TCL server -- a 'machine' type socket interface -- was added
|
||||
with the hope was it would output simple "name-value" pair type
|
||||
data. At the time, simple name/value pairs seemed reasonably easier to
|
||||
do at the time, though Maybe it should output JSON;
|
||||
|
||||
See here:
|
||||
|
||||
http://www.mail-archive.com/openocd-development%40lists.berlios.de/msg00248.html
|
||||
|
||||
The hope was that one could write a script in what ever language you want
|
||||
and do things with it!
|
||||
|
||||
@section serverdocsgui GUI Like Interfaces
|
||||
|
||||
A lot has been said about various "widigit-foo-gui-library is so
|
||||
wonderful". Please refer back to the domino and spider web problem of
|
||||
dependencies. Sure, you may well know the WhatEver-GUI library, but
|
||||
most others will not (including the next contributer to OpenOCD).
|
||||
How do we solve that problem?
|
||||
|
||||
For example, Cygwin can be painful, Cygwin GUI packages want X11
|
||||
to be present, crossing the barrier between MinGW and Cygwin is
|
||||
painful, let alone getting the GUI front end to work on MacOS, and
|
||||
Linux, yuck yuck yuck. Painful. very very painful.
|
||||
|
||||
What works easier and is less work is what is already present in every
|
||||
platform? The answer: A web browser. In other words, OpenOCD could
|
||||
serve out embedded web pages via "localhost" to your browser.
|
||||
|
||||
Long before OpenOCD had a TCL command line, Zylin AS built their ZY1000
|
||||
devince with a built-in HTTP server. Later, they were willing to both
|
||||
contribute and integrate most of that work into the main tree.
|
||||
|
||||
@subsection serverdocsother Other Options Considered
|
||||
|
||||
What if a web browser is not acceptable ie: You want to write your own
|
||||
front gadget in Eclipse, or KDevelop, or PerlTK, Ruby, or what ever
|
||||
the latest and greatest Script De Jour is.
|
||||
|
||||
- Option 1: Can we transport this extra data through the GDB server
|
||||
protocol? In other words, can we extend the GDB server protocol?
|
||||
No, Eclipse wants to talk to GDB directly and control the GDB port.
|
||||
|
||||
- Option 2: SWIG front end (libopenocd): Would that work?
|
||||
|
||||
That's painful - unless you design your api to be very simplistic -
|
||||
every language has it's own set of wack-ness, parameter marshaling is
|
||||
painful.
|
||||
|
||||
What about "callbacks" and structures, and other mess. Imagine
|
||||
debugging that system. When JimTCL was introduced Spencer Oliver had
|
||||
quite a few well-put concerns (Summer 2008) about the idea of "TCL"
|
||||
taking over OpenOCD. His concern is and was: how do you debug
|
||||
something written in 2 different languages? A "SWIG" front-end is
|
||||
unlikely to help that situation.
|
||||
|
||||
@subsection serverdoccombined Combined: Socket & WebServer Benifits
|
||||
|
||||
Seriously think about this question: What script language (or compiled
|
||||
language) today cannot talk directly to a socket? Every thing in the
|
||||
OpenOCD world can work a socket interface. Any host side tool can talk
|
||||
to Localhost or remote host, however one might want to make it work.
|
||||
|
||||
A socket interface is very simple. One could write a Java application
|
||||
and serve it out via the embedded web server, could it - or something
|
||||
like it talk to the built in TCL server? Yes, absolutely! We are on to
|
||||
something here.
|
||||
|
||||
@subsection serverdocplatforms Platform Permuntations
|
||||
|
||||
Look at some permutations where OpenOCD can run; these "just work" if
|
||||
the Socket Approach is used.
|
||||
|
||||
|
||||
- Linux/Cygwin/MinGw/MacOSx/FreeBSD development Host Locally
|
||||
- OpenOCD with some dongle on that host
|
||||
|
||||
|
||||
- Linux/Cygwin/MingW/MacOS/FreeBSD development host
|
||||
- DONGLE: tcpip based ARM-Linux perhaps at91rm9200 or ep93xx.c, running openocd.
|
||||
|
||||
|
||||
- Windows cygwin/X desktop environment.
|
||||
- Linux development host (via remote X11)
|
||||
- Dongle: "eb93xx.c" based linux board
|
||||
|
||||
|
||||
@subsection serverdocfuture Development Scale Out
|
||||
|
||||
During 2008, Duane Ellis created some TCL scripts to display peripheral
|
||||
register contents. For example, look at the sam7 TCL scripts, and the
|
||||
stm32 TCL scripts. The hope was others would create more.
|
||||
|
||||
|
||||
A good example of this is display/view the peripheral registers on
|
||||
your embedded target. Lots of commercial embedded debug tools have
|
||||
this, some can show the TIMER registers, the interrupt controller.
|
||||
|
||||
What if the chip companies behind STM32, or PIC32, AT91SAM chips -
|
||||
wanted to write something that makes working with their chip better,
|
||||
easier, faster, etc.
|
||||
|
||||
@a Question: How can we (the OpenOCD group) make that really fancy
|
||||
stuff across multiple different host platforms?
|
||||
|
||||
Remember: OpenOCD runs on:
|
||||
-# Linux via USB,
|
||||
-# ARM Linux - bit-banging GPIO pins
|
||||
-# MacOSX
|
||||
-# FreeBSD
|
||||
-# Cygwin
|
||||
-# MinGW32
|
||||
-# Ecos
|
||||
|
||||
How can we get that to work?
|
||||
|
||||
@subsection serverdocdebug What about Debugger Plugins?
|
||||
|
||||
Really GDB is nice, it works, but it is not a good embedded debug tool.
|
||||
OpenOCD cannot work in a GUI when one cannot get to its command line.
|
||||
Some GDB front-end developers have pedantic designs that refuse any and
|
||||
all access to the GDB command line (e.g. http://www.kdbg.org/todo.php).
|
||||
|
||||
The TELNET interface to OpenOCD works, but the intent of that interface
|
||||
is <b>human interaction</b>. It must remain available, developers depend
|
||||
upon it, sometimes that is the only scheme available.
|
||||
|
||||
As a small group of developers, supporting all the platforms and
|
||||
targets in the debugger will be difficult, as there are enough problem
|
||||
with the plethora of Dongles, Chips, and different target boards.
|
||||
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.
|
||||
|
||||
One reason might be, this adds one more host side requirement to make
|
||||
use of the feature. In other words, one could write a Python/TK
|
||||
front-end, but it is only useable if you have Python/TK installed.
|
||||
Maybe this can be done via Ecllipse, but not all developers use Ecplise.
|
||||
Many devlopers use Emacs (possibly with GUD mode) or vim and will not
|
||||
accept such an interface. The next developer reading this might be
|
||||
using Insight (GDB-TK) - and somebody else - DDD..
|
||||
|
||||
There is no common host-side GDB front-end method.
|
||||
|
||||
@section serverdocschallenge Front-End Scaling
|
||||
|
||||
Maybe we are wrong - ie: OpenOCD + some TK tool
|
||||
|
||||
Remember: OpenOCD is often (maybe 99.9%) of the time used with
|
||||
GDB-REMOTE. There is always some front-end package - be it command-line
|
||||
GDB under DDD, Eclipse, KDevelop, Emacs, or some other package
|
||||
(e.g. IAR tools can talk to GDB servers). How can the OpenOCD
|
||||
developers make that fancy target display GUI visible under 5 to 10
|
||||
different host-side GDB..
|
||||
|
||||
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.
|
||||
That is a development support nightmare for reasons described
|
||||
above. We have enough support problems as it is with targets, dongles,
|
||||
etc.
|
||||
|
||||
@section serverdocshttpbg HTTP Server Background
|
||||
|
||||
OpenOCD includes an HTTP server because most development environments
|
||||
are likely contain a web browser. The web browser can talk to OpenOCD's
|
||||
HTTP server and provide a high-level interfaces to the program.
|
||||
Altogether, it provides a universally accessible GUI for OpenOCD.
|
||||
|
||||
@section serverdocshtml Simple HTML Pages
|
||||
|
||||
There is (or could be) a simple "Jim TCL" function to read a memory
|
||||
location. If that can be tied into a TCL script that can modify the
|
||||
HTTP text, then we have a simple script-based web server with a JTAG
|
||||
engine under the hood.
|
||||
|
||||
Imagine a web page - served from a small board with two buttons:
|
||||
"LED_ON" and "LED_OFF", each click - turns the LED on or OFF, a very
|
||||
simplistic idea. Little boards with web servers are great examples of
|
||||
this: Ethernut is a good example and Contiki (not a board, an embedded
|
||||
OS) is another example.
|
||||
|
||||
One could create a simple: <b>Click here to display memory</b> or maybe
|
||||
<b>click here to display the UART REGISTER BLOCK</b>; click again and see
|
||||
each register explained in exquisit detail.
|
||||
|
||||
For an STM32, one could create a simple HTML page, with simple
|
||||
substitution text that the simple web server use to substitute the
|
||||
HTML text JIMTCL_PEEK32( 0x12345678 ) with the value read from
|
||||
memory. We end up with an HTML page that could list the contents of
|
||||
every peripheral register on the target platform.
|
||||
|
||||
That also is transportable, regardless of the OpenOCD host
|
||||
platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX.
|
||||
You could even port OpenOCD to an Google Android and use it as a
|
||||
bit-bang dongle JTAG serving web pages.
|
||||
|
||||
@subsection serverdocshtmladv Advanced HTML Pages
|
||||
|
||||
Java or JavaScript could be used to talk back to the TCL port. One
|
||||
could write a Java, AJAX, FLASH, or some other developer friendly
|
||||
toolbox and get a real cross-platform GUI interface. Sure, the interface
|
||||
is not native - but it is 100% cross-platform!
|
||||
|
||||
OpenOCD current uses simple HTML pages; others might be an Adobe FLASH
|
||||
expert, or a Java Expert. These possibilities could allow the pages
|
||||
remain cross-platform but still provide a rich user-interface
|
||||
experience.
|
||||
|
||||
Don't forget it can also be very simple, exactly what one developer
|
||||
can contribute, a set of very simple web pages.
|
||||
|
||||
@subsection serverdocshtmlstatus HTTP/HTML Status
|
||||
|
||||
As of May 2009, much of the HTML pages were contributed by Zylin AS,
|
||||
hence they continue to retain some resemblance to the ZY1000 interface.
|
||||
|
||||
Patches would be welcome to move these parts of the system forward.
|
||||
|
||||
*/
|
||||
|
||||
/** @page servergdb OpenOCD GDB Server API
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page servertelnet OpenOCD Telnet Server API
|
||||
|
||||
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/
|
||||
|
||||
|
||||
|
||||
*/
|
||||
399
doc/manual/style.txt
Normal file
399
doc/manual/style.txt
Normal file
@@ -0,0 +1,399 @@
|
||||
/** @page styleguide Style Guides
|
||||
|
||||
The goals for each of these guides are:
|
||||
- to produce correct code that appears clean, consistent, and readable,
|
||||
- to allow developers to create patches that conform to a standard, and
|
||||
- to eliminate these issues as points of future contention.
|
||||
|
||||
Some of these rules may be ignored in the spirit of these stated goals;
|
||||
however, such exceptions should be fairly rare.
|
||||
|
||||
The following style guides describe a formatting, naming, and other
|
||||
conventions that should be followed when writing or changing the OpenOCD
|
||||
code:
|
||||
|
||||
- @subpage styletcl
|
||||
- @subpage stylec
|
||||
- @subpage styleperl
|
||||
- @subpage styleautotools
|
||||
|
||||
In addition, the following style guides provide information for
|
||||
providing documentation, either as part of the C code or stand-alone.
|
||||
|
||||
- @subpage styledoxygen
|
||||
- @subpage styletexinfo
|
||||
- @subpage stylelatex
|
||||
|
||||
Feedback would be welcome to improve the OpenOCD guidelines.
|
||||
|
||||
*/
|
||||
/** @page styletcl TCL Style Guide
|
||||
|
||||
OpenOCD needs to expand its Jim/TCL Style Guide.
|
||||
|
||||
Many of the guidelines listed on the @ref stylec page should apply to
|
||||
OpenOCD's Jim/TCL code as well.
|
||||
|
||||
*/
|
||||
/** @page stylec C Style Guide
|
||||
|
||||
This page contains guidelines for writing new C source code for the
|
||||
OpenOCD project.
|
||||
|
||||
@section styleformat Formatting Guide
|
||||
|
||||
- remove any trailing white space at the end of lines.
|
||||
- use TAB characters for indentation; do NOT use spaces.
|
||||
- displayed TAB width is 4 characters.
|
||||
- use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n')
|
||||
- limit adjacent empty lines to at most two (2).
|
||||
- remove any trailing empty lines at the end of source files
|
||||
- do not "comment out" code from the tree; instead, one should either:
|
||||
-# remove it entirely (git can retrieve the old version), or
|
||||
-# use an @c \#if/\#endif block.
|
||||
|
||||
Finally, try to avoid lines of code that are longer than than 72-80 columns:
|
||||
|
||||
- long lines frequently indicate other style problems:
|
||||
- insufficient use of static functions, macros, or temporary variables
|
||||
- poor flow-control structure; "inverted" logical tests
|
||||
- a few lines may be wider than this limit (typically format strings), but:
|
||||
- all C compilers will concatenate series of string constants.
|
||||
- all long string constants should be split across multiple lines.
|
||||
|
||||
@section stylenames Naming Rules
|
||||
|
||||
- most identifiers must use lower-case letters (and digits) only.
|
||||
- macros must use upper-case letters (and digits) only.
|
||||
- OpenOCD identifiers should NEVER use @c MixedCaps.
|
||||
- structure names must end with the '_s' suffix.
|
||||
- typedef names must end with the '_t' suffix.
|
||||
- use underline characters between consecutive words in identifiers
|
||||
(e.g. @c more_than_one_word).
|
||||
|
||||
@section stylec99 C99 Rules
|
||||
|
||||
- inline functions
|
||||
- @c // comments -- in new code, prefer these for single-line comments
|
||||
- trailing comma allowed in enum declarations
|
||||
- designated initializers (@{ .field = value @})
|
||||
- variables declarations may be mixed with code
|
||||
- new block scopes for selection and iteration statements
|
||||
|
||||
@section styletypes Type Guidelines
|
||||
- use native types (@c int or @c unsigned) if the type is not important
|
||||
- if size matters, use the types from \<stdint.h\> or \<inttypes.h\>:
|
||||
- @c int8_t, @c int16_t, @c int32_t, or @c int64_t: signed types of specified size
|
||||
- @c uint8_t, @c uint16_t, @c uint32_t, or @c uint64_t: unsigned types of specified size
|
||||
- do @b NOT redefine @c uN types from "types.h"
|
||||
|
||||
@section stylefunc Functions
|
||||
|
||||
- static inline functions should be prefered over macros:
|
||||
@code
|
||||
/** do NOT define macro-like functions like this... */
|
||||
#define CUBE(x) ((x) * (x) * (x))
|
||||
/** instead, define the same expression using a C99 inline function */
|
||||
static inline int cube(int x) { return x * x * x; }
|
||||
@endcode
|
||||
- Functions should be declared static unless required by other modules
|
||||
- define static functions before first usage to avoid forward declarations.
|
||||
- Functions should have no space between its name and its parameter list:
|
||||
@code
|
||||
int f(int x1, int x2)
|
||||
{
|
||||
...
|
||||
int y = f(x1, x2 - x1);
|
||||
...
|
||||
}
|
||||
@endcode
|
||||
- Separate assignment and logical test statements. In other words, you
|
||||
should write statements like the following:
|
||||
@code
|
||||
// separate statements should be preferred
|
||||
result = foo();
|
||||
if (ERROR_OK != result)
|
||||
...
|
||||
@endcode
|
||||
More directly, do @b not combine these kinds of statements:
|
||||
@code
|
||||
// Combined statements should be avoided
|
||||
if (ERROR_OK != (result = foo()))
|
||||
return result;
|
||||
@endcode
|
||||
|
||||
*/
|
||||
/** @page styledoxygen Doxygen Style Guide
|
||||
|
||||
The following sections provide guidelines for OpenOCD developers
|
||||
who wish to write Doxygen comments in the code or this manual.
|
||||
For an introduction to Doxygen documentation,
|
||||
see the @ref primerdoxygen.
|
||||
|
||||
@section styledoxyblocks Doxygen Block Selection
|
||||
|
||||
Several different types of Doxygen comments can be used; often,
|
||||
one style will be the most appropriate for a specific context.
|
||||
The following guidelines provide developers with heuristics for
|
||||
selecting an appropriate form and writing consistent documentation
|
||||
comments.
|
||||
|
||||
-# use @c /// to for one-line documentation of instances.
|
||||
-# for documentation requiring multiple lines, use a "block" style:
|
||||
@verbatim
|
||||
/**
|
||||
* @brief First sentence is short description. Remaining text becomes
|
||||
* the full description block, where "empty" lines start new paragraphs.
|
||||
*
|
||||
* One can make text appear in @a italics, @b bold, @c monospace, or
|
||||
* in blocks such as the one in which this example appears in the Style
|
||||
* Guide. See the Doxygen Manual for the full list of commands.
|
||||
*
|
||||
* @param foo For a function, describe the parameters (e.g. @a foo).
|
||||
* @returns The value(s) returned, or possible error conditions.
|
||||
*/
|
||||
@endverbatim
|
||||
-# The block should start on the line following the opening @c /**.
|
||||
-# The end of the block, \f$*/\f$, should also be on its own line.
|
||||
-# Every line in the block should have a @c '*' in-line with its start:
|
||||
- A leading space is required to align the @c '*' with the @c /** line.
|
||||
- A single "empty" line should separate the function documentation
|
||||
from the block of parameter and return value descriptions.
|
||||
- Except to separate paragraphs of documentation, other extra
|
||||
"empty" lines should be removed from the block.
|
||||
-# Only single spaces should be used; do @b not add mid-line indentation.
|
||||
-# If the total line length will be less than 72-80 columns, then
|
||||
- The @c /**< form can be used on the same line.
|
||||
- This style should be used sparingly; the best use is for fields:
|
||||
@code int field; /**< field description */ @endcode
|
||||
|
||||
@section styledoxyall Doxygen Style Guide
|
||||
|
||||
The following guidelines apply to all Doxygen comment blocks:
|
||||
|
||||
-# Use the @c '\@cmd' form for all doxygen commands (do @b not use @c '\\cmd').
|
||||
-# Use symbol names such that Doxygen automatically creates links:
|
||||
-# @c function_name() can be used to reference functions
|
||||
(e.g. flash_set_dirty()).
|
||||
-# @c struct_name::member_name should be used to reference structure
|
||||
fields in the documentation (e.g. @c flash_driver_s::name).
|
||||
-# URLS get converted to markup automatically, without any extra effort.
|
||||
-# new pages can be linked into the heirarchy by using the @c \@subpage
|
||||
command somewhere the page(s) under which they should be linked:
|
||||
-# use @c \@ref in other contexts to create links to pages and sections.
|
||||
-# Use good Doxygen mark-up:
|
||||
-# '\@a' (italics) should be used to reference parameters (e.g. <i>foo</i>).
|
||||
-# '\@b' (bold) should be used to emphasizing <b>single</b> words.
|
||||
-# '\@c' (monospace) should be used with <code>file names</code> and
|
||||
<code>code symbols</code>, so they appear visually distinct from
|
||||
surrounding text.
|
||||
-# To mark-up multiple words, the HTML alternatives must be used.
|
||||
-# Two spaces should be used when nesting lists; do @b not use '\\t' in lists.
|
||||
-# Code examples provided in documentation must conform to the Style Guide.
|
||||
|
||||
@section styledoxytext Doxygen Text Inputs
|
||||
|
||||
In addition to the guidelines in the preceding sections, the following
|
||||
additional style guidelines should be considered when writing
|
||||
documentation as part of standalone text files:
|
||||
|
||||
-# Text files must contain Doxygen at least one comment block:
|
||||
-# Documentation should begin in the first column (except for nested lists).
|
||||
-# Do NOT use the @c '*' convention that must be used in the source code.
|
||||
-# Each file should contain at least one @c \@page block.
|
||||
-# Each new page should be listed as a \@subpage in the \@page block
|
||||
of the page that should serve as its parent.
|
||||
-# Large pages should be structure in parts using meaningful \@section
|
||||
and \@subsection commands.
|
||||
-# Include a @c \@file block at the end of each Doxygen @c .txt file to
|
||||
document its contents:
|
||||
- Doxygen creates such pages for files automatically, but no content
|
||||
will appear on them for those that only contain manual pages.
|
||||
- The \@file block should provide useful meta-documentation to assist
|
||||
techincal writers; typically, a list of the pages that it contains.
|
||||
- For example, the @ref styleguide exists in @c doc/manual/style.txt,
|
||||
which contains a reference back to itself.
|
||||
-# The \@file and \@page commands should begin on the same line as
|
||||
the start of the Doxygen comment:
|
||||
@verbatim
|
||||
/** @page pagename Page Title
|
||||
|
||||
Documentation for the page.
|
||||
|
||||
*/
|
||||
/** @file
|
||||
|
||||
This file contains the @ref pagename page.
|
||||
|
||||
*/
|
||||
@endverbatim
|
||||
|
||||
For an example, the Doxygen source for this Style Guide can be found in
|
||||
@c doc/manual/style.txt, alongside other parts of The Manual.
|
||||
|
||||
*/
|
||||
/** @page styletexinfo Texinfo Style Guide
|
||||
|
||||
The User's Guide is there to provide two basic kinds of information. It
|
||||
is a guide for how and why to use each feature or mechanism of OpenOCD.
|
||||
It is also the reference manual for all commands and options involved
|
||||
in using them, including interface, flash, target, and other drivers.
|
||||
At this time, it is the only user-targetted documentation; everything
|
||||
else is addressing OpenOCD developers.
|
||||
|
||||
There are two key audiences for the User's Guide, both developer based.
|
||||
The primary audience is developers using OpenOCD as a tool in their
|
||||
work, or who may be starting to use it that way. A secondary audience
|
||||
includes developers who are supporting those users by packaging or
|
||||
customizing it for their hardware, installing it as part of some software
|
||||
distribution, or by evolving OpenOCD itself. There is some crossover
|
||||
between those audiences. We encourage contributions from users as the
|
||||
fundamental way to evolve and improve OpenOCD. In particular, creating
|
||||
a board or target specific configuration file is something that many
|
||||
users will end up doing at some point, and we like to see such files
|
||||
become part of the mainline release.
|
||||
|
||||
General documentation rules to remember include:
|
||||
|
||||
- Be concise and clear. It's work to remove those extra words and
|
||||
sentences, but such "noise" doesn't help readers.
|
||||
- Make it easy to skim and browse. "Tell what you're going to say,
|
||||
then say it". Help readers decide whether to dig in now, or
|
||||
leave it for later.
|
||||
- Make sure the chapters flow well. Presentations should not jump
|
||||
around, and should move easily from overview down to details.
|
||||
- Avoid using the passive voice.
|
||||
- Address the reader to clarify roles ("your config file", "the board you
|
||||
are debugging", etc.); "the user" (etc) is artificial.
|
||||
- Use good English grammar and spelling. Remember also that English
|
||||
will not be the first language for many readers. Avoid complex or
|
||||
idiomatic usage that could create needless barriers.
|
||||
- Use examples to highlight fundamental ideas and common idioms.
|
||||
- Don't overuse list constructs. This is not a slide presentation;
|
||||
prefer paragraphs.
|
||||
|
||||
When presenting features and mechanisms of OpenOCD:
|
||||
|
||||
- Explain key concepts before presenting commands using them.
|
||||
- Tie examples to common developer tasks.
|
||||
- When giving instructions, you can \@enumerate each step both
|
||||
to clearly delineate the steps, and to highlight that this is
|
||||
not explanatory text.
|
||||
- When you provide "how to use it" advice or tutorials, keep it
|
||||
in separate sections from the reference material.
|
||||
- Good indexing is something of a black art. Use \@cindex for important
|
||||
concepts, but don't overuse it. In particular, rely on the \@deffn
|
||||
indexing, and use \@cindex primarily with significant blocks of text
|
||||
such as \@subsection. The \@dfn of a key term may merit indexing.
|
||||
- Use \@xref (and \@anchor) with care. Hardcopy versions, from the PDF,
|
||||
must make sense without clickable links (which don't work all that well
|
||||
with Texinfo in any case). If you find you're using many links,
|
||||
read that as a symptom that the presentation may be disjointed and
|
||||
confusing.
|
||||
- Avoid font tricks like \@b, but use \@option, \@file, \@dfn, \@emph
|
||||
and related mechanisms where appropriate.
|
||||
|
||||
For technical reference material:
|
||||
|
||||
- It's OK to start sections with explanations and end them with
|
||||
detailed lists of the relevant commands.
|
||||
- Use the \@deffn style declarations to define all commands and drivers.
|
||||
These will automatically appear in the relevant index, and those
|
||||
declarations help promote consistent presentation and style.
|
||||
- It's a "Command" if it can be used interactively.
|
||||
- Else it's a "Config Command" if it must be used before the
|
||||
configuration stage completes.
|
||||
- For a "Driver", list its name.
|
||||
- Use BNF style regular expressions to define parameters:
|
||||
brackets around zero-or-one choices, parentheses around
|
||||
exactly-one choices.
|
||||
- Use \@option, \@file, \@var and other mechanisms where appropriate.
|
||||
- Say what output it displays, and what value it returns to callers.
|
||||
- Explain clearly what the command does. Sometimes you will find
|
||||
that it can't be explained clearly. That usually means the command
|
||||
is poorly designed; replace it with something better, if you can.
|
||||
- Be complete: document all commands, except as part of a strategy
|
||||
to phase something in or out.
|
||||
- Be correct: review the documentation against the code, and
|
||||
vice versa.
|
||||
- Alphabetize the \@defn declarations for all commands in each
|
||||
section.
|
||||
- Keep the per-command documentation focussed on exactly what that
|
||||
command does, not motivation, advice, suggestions, or big examples.
|
||||
When commands deserve such expanded text, it belongs elsewhere.
|
||||
Solutions might be using a \@section explaining a cluster of related
|
||||
commands, or acting as a mini-tutorial.
|
||||
- Details for any given driver should be grouped together.
|
||||
|
||||
The User's Guide is the first place most users will start reading,
|
||||
after they begin using OpenOCD. Make that investment of their time
|
||||
be as productive as possible. Needing to look at OpenOCD source code,
|
||||
to figure out how to use it is a bad sign, though it's OK to need to
|
||||
look at the User's guide to figure out what a config script is doing.
|
||||
|
||||
*/
|
||||
/** @page stylelatex LaTeX Style Guide
|
||||
|
||||
This page needs to provide style guidelines for using LaTeX, the
|
||||
typesetting language used by The References for OpenOCD Hardware.
|
||||
Likewise, the @ref primerlatex for using this guide needs to be completed.
|
||||
|
||||
*/
|
||||
/** @page styleperl Perl Style Guide
|
||||
|
||||
This page provides some style guidelines for using Perl, a scripting
|
||||
language used by several small tools in the tree:
|
||||
|
||||
-# Ensure all Perl scripts use the proper suffix (@c .pl for scripts, and
|
||||
@c .pm for modules)
|
||||
-# Pass files as script parameters or piped as input:
|
||||
- Do NOT code paths to files in the tree, as this breaks out-of-tree builds.
|
||||
- If you must, then you must also use an automake rule to create the script.
|
||||
-# use @c '#!/usr/bin/perl' as the first line of Perl scripts.
|
||||
-# always <code>use strict</code> and <code>use warnings</code>
|
||||
-# invoke scripts indirectly in Makefiles or other scripts:
|
||||
@code
|
||||
perl script.pl
|
||||
@endcode
|
||||
|
||||
Maintainers must also be sure to follow additional guidelines:
|
||||
-# Ensure that Perl scripts are committed as executables:
|
||||
Use "<code>chmod +x script.pl</code>"
|
||||
@a before using "<code>git add script.pl</code>"
|
||||
|
||||
*/
|
||||
/** @page styleautotools Autotools Style Guide
|
||||
|
||||
This page contains style guidelines for the OpenOCD autotools scripts.
|
||||
|
||||
The following guidelines apply to the @c configure.in file:
|
||||
- Better guidelines need to be developed, but until then...
|
||||
- Use good judgement.
|
||||
|
||||
The following guidelines apply to @c Makefile.am files:
|
||||
-# When assigning variables with long lists of items:
|
||||
-# Separate the values on each line to make the files "patch friendly":
|
||||
@code
|
||||
VAR = \
|
||||
value1 \
|
||||
value2 \
|
||||
...
|
||||
value9 \
|
||||
value10
|
||||
@endcode
|
||||
*/
|
||||
/** @file
|
||||
|
||||
This file contains the @ref styleguide pages. The @ref styleguide pages
|
||||
include the following Style Guides for their respective code and
|
||||
documentation languages:
|
||||
|
||||
- @ref styletcl
|
||||
- @ref stylec
|
||||
- @ref styledoxygen
|
||||
- @ref styletexinfo
|
||||
- @ref stylelatex
|
||||
- @ref styleperl
|
||||
- @ref styleautotools
|
||||
|
||||
*/
|
||||
45
doc/manual/target.txt
Normal file
45
doc/manual/target.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
/** @page targetdocs OpenOCD Target APIs
|
||||
|
||||
OpenOCD provides its Target APIs to allow developers to provide trace and
|
||||
debugging support for specific device targets. These primarily consist of
|
||||
ARM cores, but other types have been supported. New targets should be
|
||||
developed by following or using these APIs.
|
||||
|
||||
The Target Support module contains APIs that cover several functional areas:
|
||||
|
||||
- @subpage targetarm
|
||||
- @subpage targetnotarm
|
||||
- @subpage targetregister
|
||||
- @subpage targetimage
|
||||
- @subpage targettrace
|
||||
|
||||
This section needs to be expanded.
|
||||
|
||||
*/
|
||||
|
||||
/** @page targetarm OpenOCD ARM Targets
|
||||
|
||||
This section needs to describe OpenOCD's ARM target support.
|
||||
|
||||
*/
|
||||
|
||||
/** @page targetregister OpenOCD Target Register API
|
||||
|
||||
This section needs to describe OpenOCD's Target Register API, as
|
||||
provided by 'src/target/register.h'.
|
||||
|
||||
*/
|
||||
|
||||
/** @page targetimage OpenOCD Target Image API
|
||||
|
||||
This section needs to describe OpenOCD's Target Image API, as provided
|
||||
by 'src/target/image.h'.
|
||||
|
||||
*/
|
||||
|
||||
/** @page targettrace OpenOCD Target Trace API
|
||||
|
||||
This section needs to describe OpenOCD's Target Trace API, as provided
|
||||
by 'src/target/trace.h'.
|
||||
|
||||
*/
|
||||
@@ -1,15 +1,9 @@
|
||||
Some outstanding issues w.r.t. non-ARM32 targets
|
||||
================================================
|
||||
This file describes outstanding issues w.r.t.
|
||||
non-ARM32 targets.
|
||||
/** @page targetnotarm OpenOCD Non-ARM Targets
|
||||
|
||||
Ideas & patches welcome!
|
||||
This page describes outstanding issues w.r.t. non-ARM targets.
|
||||
|
||||
@section targetnotarmflash Flash drivers
|
||||
|
||||
|
||||
|
||||
Flash drivers
|
||||
-------------
|
||||
The flash drivers contain ARM32 code that is used
|
||||
to execute code on the target.
|
||||
|
||||
@@ -26,23 +20,22 @@ compile the target flash drivers. Perhaps
|
||||
using automake?
|
||||
|
||||
|
||||
|
||||
eCos has CFI driver that could probably be compiled
|
||||
for all targets. The trick is to figure out a
|
||||
way to make the compiled flash drivers work
|
||||
on all target memory maps + sort out all the
|
||||
little details
|
||||
|
||||
32 vs. 64 bit
|
||||
-------------
|
||||
@section targetnotarm32v64 32 vs. 64 bit
|
||||
|
||||
Currently OpenOCD only supports 32 bit targets.
|
||||
|
||||
Adding 64 bit support would be nice but there
|
||||
hasn't been any call for it in the openocd development
|
||||
mailing list
|
||||
|
||||
target support
|
||||
--------------
|
||||
@section targetnotarmsupport Target Support
|
||||
|
||||
target.h is relatively CPU agnostic and
|
||||
the intention is to move in the direction of less
|
||||
instruction set specific.
|
||||
@@ -53,8 +46,8 @@ An example is FPGA programming support via JTAG,
|
||||
but also flash chips can be programmed directly
|
||||
using JTAG.
|
||||
|
||||
non-JTAG physical layer
|
||||
-----------------------
|
||||
@section targetnotarmphy non-JTAG physical layer
|
||||
|
||||
JTAG is not the only physical protocol used to talk to
|
||||
CPUs.
|
||||
|
||||
@@ -64,13 +57,15 @@ The actual physical layer is a relatively modest part
|
||||
of the total OpenOCD system.
|
||||
|
||||
|
||||
PowerPC
|
||||
-------
|
||||
@section targetnotarmppc PowerPC
|
||||
|
||||
there exists open source implementations of powerpc
|
||||
target manipulation, but there hasn't been a lot
|
||||
of activity in the mailing list.
|
||||
|
||||
MIPS
|
||||
----
|
||||
@section targetnotarmmips MIPS
|
||||
|
||||
Currently OpenOCD has a MIPS target defined. This is the
|
||||
first non-ARM example of a CPU target
|
||||
|
||||
*/
|
||||
7901
doc/openocd.texi
7901
doc/openocd.texi
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#####ECOSGPLCOPYRIGHTBEGIN####
|
||||
## -------------------------------------------
|
||||
## This file is part of eCos, the Embedded Configurable Operating System.
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
## Copyright (C) 2008 Øyvind Harboe
|
||||
##
|
||||
## eCos is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free
|
||||
|
||||
82
guess-rev.sh
82
guess-rev.sh
@@ -1,9 +1,83 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
#
|
||||
# This scripts adds local version information from the version
|
||||
# control systems git, mercurial (hg) and subversion (svn).
|
||||
#
|
||||
# Copied from Linux 2.6.32 scripts/setlocalversion and modified
|
||||
# slightly to work better for OpenOCD.
|
||||
#
|
||||
|
||||
REV=unknown
|
||||
usage() {
|
||||
echo "Usage: $0 [srctree]" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
which svnversion > /dev/null 2>&1 && REV=`svnversion -n`
|
||||
cd "${1:-.}" || usage
|
||||
|
||||
echo -n $REV
|
||||
# Check for git and a git repo.
|
||||
if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
|
||||
|
||||
# If we are at a tagged commit (like "v2.6.30-rc6"), we ignore it,
|
||||
# because this version is defined in the top level Makefile.
|
||||
if [ -z "`git describe --exact-match 2>/dev/null`" ]; then
|
||||
|
||||
# If we are past a tagged commit (like "v2.6.30-rc5-302-g72357d5"),
|
||||
# we pretty print it.
|
||||
if atag="`git describe 2>/dev/null`"; then
|
||||
echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
|
||||
|
||||
# If we don't have a tag at all we print -g{commitish}.
|
||||
else
|
||||
printf '%s%s' -g $head
|
||||
fi
|
||||
fi
|
||||
|
||||
# Is this git on svn?
|
||||
if git config --get svn-remote.svn.url >/dev/null; then
|
||||
printf -- '-svn%s' "`git svn find-rev $head`"
|
||||
fi
|
||||
|
||||
# Update index only on r/w media
|
||||
[ -w . ] && git update-index --refresh --unmerged > /dev/null
|
||||
|
||||
# Check for uncommitted changes
|
||||
if git diff-index --name-only HEAD | grep -v "^scripts/package" \
|
||||
| read dummy; then
|
||||
printf '%s' -dirty
|
||||
fi
|
||||
|
||||
# All done with git
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check for mercurial and a mercurial repo.
|
||||
if hgid=`hg id 2>/dev/null`; then
|
||||
tag=`printf '%s' "$hgid" | cut -d' ' -f2`
|
||||
|
||||
# Do we have an untagged version?
|
||||
if [ -z "$tag" -o "$tag" = tip ]; then
|
||||
id=`printf '%s' "$hgid" | sed 's/[+ ].*//'`
|
||||
printf '%s%s' -hg "$id"
|
||||
fi
|
||||
|
||||
# Are there uncommitted changes?
|
||||
# These are represented by + after the changeset id.
|
||||
case "$hgid" in
|
||||
*+|*+\ *) printf '%s' -dirty ;;
|
||||
esac
|
||||
|
||||
# All done with mercurial
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check for svn and a svn repo.
|
||||
if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then
|
||||
rev=`echo $rev | awk '{print $NF}'`
|
||||
printf -- '-svn%s' "$rev"
|
||||
|
||||
# All done with svn
|
||||
exit
|
||||
fi
|
||||
|
||||
# There's no reecognized repository; we must be a snapshot.
|
||||
printf -- '-snapshot'
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
SUBDIRS = helper jtag xsvf svf target server flash pld
|
||||
|
||||
lib_LTLIBRARIES = libopenocd.la
|
||||
bin_PROGRAMS = openocd
|
||||
|
||||
if ECOSBOARD
|
||||
@@ -6,33 +9,41 @@ else
|
||||
MAINFILE = main.c
|
||||
endif
|
||||
|
||||
openocd_SOURCES = $(MAINFILE) openocd.c
|
||||
openocd_SOURCES = $(MAINFILE)
|
||||
openocd_LDADD = libopenocd.la
|
||||
|
||||
libopenocd_la_SOURCES = openocd.c
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target -I$(top_srcdir)/src/xsvf -I$(top_srcdir)/src/svf \
|
||||
-I$(top_srcdir)/src/server -I$(top_srcdir)/src/flash -I$(top_srcdir)/src/pld $(all_includes)
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag \
|
||||
-I$(top_srcdir)/src/target \
|
||||
-I$(top_srcdir)/src/xsvf \
|
||||
-I$(top_srcdir)/src/svf \
|
||||
-I$(top_srcdir)/src/server \
|
||||
-I$(top_srcdir)/src/flash \
|
||||
-I$(top_srcdir)/src/pld
|
||||
|
||||
# pass path to prefix path
|
||||
openocd_CPPFLAGS = \
|
||||
-DPKGLIBDIR=\"$(pkglibdir)\" \
|
||||
-DPKGBLDDATE=\"`date +%F-%R`\"
|
||||
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
|
||||
|
||||
# banner output includes RELSTR appended to $VERSION from the configure script
|
||||
# guess-rev.sh returns either a repository version ID or "-snapshot"
|
||||
if RELEASE
|
||||
openocd_CPPFLAGS += -DRELSTR=\"Release\" -DPKGBLDREV=\"\"
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
|
||||
else
|
||||
openocd_CPPFLAGS += -DRELSTR=\"svn:\" -DPKGBLDREV=\"`$(top_srcdir)/guess-rev.sh`\"
|
||||
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
|
||||
endif
|
||||
|
||||
# add default CPPFLAGS
|
||||
openocd_CPPFLAGS += @CPPFLAGS@
|
||||
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
|
||||
|
||||
# the library search path.
|
||||
openocd_LDFLAGS = $(all_libraries)
|
||||
SUBDIRS = helper jtag xsvf svf target server flash pld
|
||||
libopenocd_la_LDFLAGS = $(all_libraries)
|
||||
|
||||
if IS_MINGW
|
||||
MINGWLDADD = -lwsock32
|
||||
MINGWLDADD = -lws2_32
|
||||
else
|
||||
MINGWLDADD =
|
||||
endif
|
||||
@@ -65,36 +76,29 @@ endif
|
||||
endif
|
||||
endif
|
||||
|
||||
openocd_LDADD = $(top_builddir)/src/xsvf/libxsvf.a $(top_builddir)/src/svf/libsvf.a \
|
||||
$(top_builddir)/src/target/libtarget.a $(top_builddir)/src/jtag/libjtag.a \
|
||||
$(top_builddir)/src/helper/libhelper.a \
|
||||
$(top_builddir)/src/server/libserver.a $(top_builddir)/src/helper/libhelper.a \
|
||||
$(top_builddir)/src/flash/libflash.a $(top_builddir)/src/target/libtarget.a \
|
||||
$(top_builddir)/src/pld/libpld.a \
|
||||
libopenocd_la_LIBADD = \
|
||||
$(top_builddir)/src/xsvf/libxsvf.la \
|
||||
$(top_builddir)/src/svf/libsvf.la \
|
||||
$(top_builddir)/src/pld/libpld.la \
|
||||
$(top_builddir)/src/jtag/libjtag.la \
|
||||
$(top_builddir)/src/flash/libflash.la \
|
||||
$(top_builddir)/src/target/libtarget.la \
|
||||
$(top_builddir)/src/server/libserver.la \
|
||||
$(top_builddir)/src/helper/libhelper.la \
|
||||
$(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB)
|
||||
|
||||
if HTTPD
|
||||
openocd_LDADD += -lmicrohttpd
|
||||
libopenocd_la_LIBADD += -lmicrohttpd
|
||||
endif
|
||||
|
||||
nobase_dist_pkglib_DATA = \
|
||||
tcl/bitsbytes.tcl \
|
||||
tcl/chip/atmel/at91/aic.tcl \
|
||||
tcl/chip/atmel/at91/at91sam7x128.tcl \
|
||||
tcl/chip/atmel/at91/at91sam7x256.tcl \
|
||||
tcl/chip/atmel/at91/pmc.tcl \
|
||||
tcl/chip/atmel/at91/rtt.tcl \
|
||||
tcl/chip/atmel/at91/usarts.tcl \
|
||||
tcl/chip/st/stm32/stm32.tcl \
|
||||
tcl/chip/st/stm32/stm32_rcc.tcl \
|
||||
tcl/chip/st/stm32/stm32_regs.tcl \
|
||||
tcl/cpu/arm/arm7tdmi.tcl \
|
||||
tcl/cpu/arm/arm920.tcl \
|
||||
tcl/cpu/arm/arm946.tcl \
|
||||
tcl/cpu/arm/arm966.tcl \
|
||||
tcl/cpu/arm/cortex_m3.tcl \
|
||||
tcl/memory.tcl \
|
||||
tcl/mmr_helpers.tcl \
|
||||
tcl/readable.tcl
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
# The "quick" target builds executables & reinstalls the executables
|
||||
# Primary use: developer types to quicken the edit/compile/debug
|
||||
# cycle. by not requiring a "full build and full install". Note the
|
||||
# assumption is: You are only rebuilding the EXE.... and everything
|
||||
# else is/was previously installed.
|
||||
#
|
||||
# use at your own risk
|
||||
quick: all install-binPROGRAMS
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
179
src/ecosboard.c
179
src/ecosboard.c
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2008 by Øyvind Harboe *
|
||||
* Copyright (C) 2007-2008 by Øyvind Harboe *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
@@ -39,8 +39,6 @@
|
||||
|
||||
#include <time_support.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <strings.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -84,6 +82,8 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define MAX_IFS 64
|
||||
#if defined(CYGPKG_NET_FREEBSD_STACK)
|
||||
#include <tftp_support.h>
|
||||
@@ -93,7 +93,7 @@ struct tftpd_fileops fileops =
|
||||
(int (*)(const char *, int))open,
|
||||
close,
|
||||
(int (*)(int, const void *, int))write,
|
||||
( int (*)(int, void *, int))read
|
||||
(int (*)(int, void *, int))read
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -148,7 +148,6 @@ void start_profile(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int eth0_up;
|
||||
static FILE *log;
|
||||
|
||||
static char reboot_stack[2048];
|
||||
@@ -156,8 +155,8 @@ static char reboot_stack[2048];
|
||||
static void zylinjtag_reboot(cyg_addrword_t data)
|
||||
{
|
||||
serialLog = true;
|
||||
diag_printf("Rebooting in 100 ticks..\n");
|
||||
cyg_thread_delay(100);
|
||||
diag_printf("Rebooting in 500 ticks..\n");
|
||||
cyg_thread_delay(500);
|
||||
diag_printf("Unmounting /config..\n");
|
||||
umount("/config");
|
||||
diag_printf("Rebooting..\n");
|
||||
@@ -174,6 +173,62 @@ void reboot(void)
|
||||
cyg_thread_resume(zylinjtag_thread_handle);
|
||||
}
|
||||
|
||||
static char zylinjtag_reboot_port_stack[2048];
|
||||
static cyg_thread zylinjtag_reboot_port_thread_object;
|
||||
static cyg_handle_t zylinjtag_reboot_port_thread_handle;
|
||||
|
||||
static void zylinjtag_reboot_port_task(cyg_addrword_t data)
|
||||
{
|
||||
int so_reuseaddr_option = 1;
|
||||
|
||||
int fd;
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
LOG_ERROR("error creating socket: %s", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*) &so_reuseaddr_option,
|
||||
sizeof(int));
|
||||
|
||||
struct sockaddr_in sin;
|
||||
unsigned int address_size;
|
||||
address_size = sizeof(sin);
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
sin.sin_port = htons(1234);
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1)
|
||||
{
|
||||
LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (listen(fd, 1) == -1)
|
||||
{
|
||||
LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
// socket_nonblock(fd);
|
||||
|
||||
|
||||
accept(fd, (struct sockaddr *) &sin, &address_size);
|
||||
|
||||
diag_printf("Got reboot signal on port 1234");
|
||||
|
||||
reboot();
|
||||
|
||||
}
|
||||
|
||||
void reboot_port(void)
|
||||
{
|
||||
cyg_thread_create(1, zylinjtag_reboot_port_task, (cyg_addrword_t) 0, "wait for reboot signal on port 1234",
|
||||
(void *) zylinjtag_reboot_port_stack, sizeof(zylinjtag_reboot_port_stack),
|
||||
&zylinjtag_reboot_port_thread_handle, &zylinjtag_reboot_port_thread_object);
|
||||
cyg_thread_resume(zylinjtag_reboot_port_thread_handle);
|
||||
}
|
||||
|
||||
int configuration_output_handler(struct command_context_s *context,
|
||||
const char* line)
|
||||
{
|
||||
@@ -191,7 +246,6 @@ int zy1000_configuration_output_handler_log(struct command_context_s *context,
|
||||
}
|
||||
|
||||
#ifdef CYGPKG_PROFILE_GPROF
|
||||
extern void start_profile(void);
|
||||
|
||||
int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
@@ -255,11 +309,11 @@ void copyfile(char *name2, char *name1);
|
||||
void copydir(char *name, char *destdir);
|
||||
|
||||
#if 0
|
||||
MTAB_ENTRY( romfs_mte1,
|
||||
MTAB_ENTRY(romfs_mte1,
|
||||
"/rom",
|
||||
"romfs",
|
||||
"",
|
||||
(CYG_ADDRWORD) &filedata[0] );
|
||||
(CYG_ADDRWORD) &filedata[0]);
|
||||
#endif
|
||||
|
||||
void openocd_sleep_prelude(void)
|
||||
@@ -274,6 +328,7 @@ void openocd_sleep_postlude(void)
|
||||
|
||||
void format(void)
|
||||
{
|
||||
#ifdef CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1
|
||||
diag_printf("Formatting JFFS2...\n");
|
||||
|
||||
cyg_io_handle_t handle;
|
||||
@@ -297,22 +352,21 @@ void format(void)
|
||||
}
|
||||
|
||||
cyg_io_flash_getconfig_erase_t e;
|
||||
void *err_addr;
|
||||
len = sizeof(e);
|
||||
|
||||
e.offset = 0;
|
||||
e.len = ds.dev_size;
|
||||
e.err_address = &err_addr;
|
||||
|
||||
diag_printf("Formatting 0x%08x bytes\n", ds.dev_size);
|
||||
diag_printf("Formatting 0x%08x bytes\n", (int)ds.dev_size);
|
||||
err = cyg_io_get_config(handle, CYG_IO_GET_CONFIG_FLASH_ERASE, &e, &len);
|
||||
if (err != ENOERR)
|
||||
{
|
||||
diag_printf("Flash erase error %d offset 0x%p\n", err, err_addr);
|
||||
diag_printf("Flash erase error %d offset 0x%08x\n", err, e.err_address);
|
||||
reboot();
|
||||
}
|
||||
|
||||
diag_printf("Flash formatted successfully\n");
|
||||
#endif
|
||||
|
||||
reboot();
|
||||
}
|
||||
@@ -421,8 +475,6 @@ static int zylinjtag_Jim_Command_reboot(Jim_Interp *interp, int argc,
|
||||
}
|
||||
|
||||
|
||||
extern Jim_Interp *interp;
|
||||
|
||||
static void zylinjtag_startNetwork(void)
|
||||
{
|
||||
// Bring TCP/IP up immediately before we're ready to accept commands.
|
||||
@@ -438,6 +490,10 @@ static void zylinjtag_startNetwork(void)
|
||||
diag_printf("Network not up and running\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* very first thing we want is a reboot capability */
|
||||
reboot_port();
|
||||
|
||||
#if defined(CYGPKG_NET_FREEBSD_STACK)
|
||||
/*start TFTP*/
|
||||
tftpd_start(69, &fileops);
|
||||
@@ -449,7 +505,7 @@ static void zylinjtag_startNetwork(void)
|
||||
|
||||
Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log,
|
||||
NULL, NULL);
|
||||
Jim_CreateCommand(httpstate.jim_interp, "reboot",
|
||||
Jim_CreateCommand(httpstate.jim_interp, "zy1000_reboot",
|
||||
zylinjtag_Jim_Command_reboot, NULL, NULL);
|
||||
Jim_CreateCommand(httpstate.jim_interp, "threads",
|
||||
zylinjtag_Jim_Command_threads, NULL, NULL);
|
||||
@@ -569,6 +625,9 @@ void setNoDelay(int session, int flag)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TEST_TCPIP() 0
|
||||
|
||||
#if TEST_TCPIP
|
||||
struct
|
||||
{
|
||||
int req;
|
||||
@@ -577,6 +636,7 @@ struct
|
||||
int actual2;
|
||||
} tcpipSent[512 * 1024];
|
||||
int cur;
|
||||
#endif
|
||||
|
||||
static void zylinjtag_uart(cyg_addrword_t data)
|
||||
{
|
||||
@@ -636,12 +696,14 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
#ifdef CYGPKG_PROFILE_GPROF
|
||||
start_profile();
|
||||
#endif
|
||||
int actual = 0;
|
||||
int actual2 = 0;
|
||||
int pos, pos2;
|
||||
size_t actual = 0;
|
||||
size_t actual2 = 0;
|
||||
size_t pos, pos2;
|
||||
pos = 0;
|
||||
pos2 = 0;
|
||||
#if TEST_TCPIP
|
||||
cur = 0;
|
||||
#endif
|
||||
for (;;)
|
||||
{
|
||||
fd_set write_fds;
|
||||
@@ -671,9 +733,11 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
if (actual2 <= 0)
|
||||
{
|
||||
memset(backwardBuffer, 's', sizeof(backwardBuffer));
|
||||
actual2 = read(serHandle, backwardBuffer,
|
||||
int t;
|
||||
t = read(serHandle, backwardBuffer,
|
||||
sizeof(backwardBuffer));
|
||||
if (actual2 < 0)
|
||||
actual2 = t;
|
||||
if (t < 0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
@@ -684,8 +748,8 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
pos2 = 0;
|
||||
}
|
||||
|
||||
int x = actual2;
|
||||
int y = 0;
|
||||
size_t x = actual2;
|
||||
size_t y = 0;
|
||||
if (actual2 > 0)
|
||||
{
|
||||
int written = write(session, backwardBuffer + pos2, actual2);
|
||||
@@ -740,6 +804,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
}
|
||||
y2 = written;
|
||||
}
|
||||
#if TEST_TCPIP
|
||||
if (cur < 1024)
|
||||
{
|
||||
tcpipSent[cur].req = x;
|
||||
@@ -748,11 +813,12 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
tcpipSent[cur].actual2 = y2;
|
||||
cur++;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
closeSession: close(session);
|
||||
close(serHandle);
|
||||
|
||||
#if TEST_TCPIP
|
||||
int i;
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
@@ -760,6 +826,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
|
||||
tcpipSent[i].req2, tcpipSent[i].actual2);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
close(fd);
|
||||
|
||||
@@ -860,9 +927,9 @@ int boolParam(char *var);
|
||||
|
||||
command_context_t *setup_command_handler(void);
|
||||
|
||||
extern const char *zylin_config_dir;
|
||||
static const char *zylin_config_dir="/config/settings";
|
||||
|
||||
int add_default_dirs(void)
|
||||
static int add_default_dirs(void)
|
||||
{
|
||||
add_script_search_dir(zylin_config_dir);
|
||||
add_script_search_dir("/rom/lib/openocd");
|
||||
@@ -979,10 +1046,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
mkdir(zylin_config_dir, 0777);
|
||||
char *dirname=alloc_printf("%s/target", zylin_config_dir);
|
||||
char *dirname = alloc_printf("%s/target", zylin_config_dir);
|
||||
mkdir(dirname, 0777);
|
||||
free(dirname);
|
||||
dirname=alloc_printf("%s/event", zylin_config_dir);
|
||||
dirname = alloc_printf("%s/board", zylin_config_dir);
|
||||
mkdir(dirname, 0777);
|
||||
free(dirname);
|
||||
dirname = alloc_printf("%s/event", zylin_config_dir);
|
||||
mkdir(dirname, 0777);
|
||||
free(dirname);
|
||||
|
||||
@@ -1037,12 +1107,15 @@ int main(int argc, char *argv[])
|
||||
if (logAllToSerial)
|
||||
{
|
||||
diag_printf(
|
||||
"%s/logserial=1 => sending log output to serial port using \"debug_level 3\" as default.\n", zylin_config_dir);
|
||||
"%s/logserial = 1 => sending log output to serial port using \"debug_level 3\" as default.\n", zylin_config_dir);
|
||||
command_run_line(cmd_ctx, "debug_level 3");
|
||||
}
|
||||
|
||||
command_run_linef(cmd_ctx, "script /rom/openocd.cfg");
|
||||
|
||||
/* we MUST always run the init command as it will launch telnet sessions */
|
||||
command_run_line(cmd_ctx, "init");
|
||||
|
||||
// FIX!!! Yuk!
|
||||
// diag_printf() is really invoked from many more places than we trust it
|
||||
// not to cause instabilities(e.g. invoking fputc() from an interrupt is *BAD*).
|
||||
@@ -1094,20 +1167,7 @@ CYG_HTTPD_MIME_TABLE_ENTRY(bin_mime_label, "bin", "application/octet-stream");
|
||||
#include <cyg/kernel/ktypes.h> // base kernel types
|
||||
#include <cyg/infra/cyg_trac.h> // tracing macros
|
||||
#include <cyg/infra/cyg_ass.h> // assertion macros
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cyg/fileio/fileio.h>
|
||||
|
||||
#include <cyg/kernel/kapi.h>
|
||||
#include <cyg/infra/diag.h>
|
||||
|
||||
@@ -1141,7 +1201,7 @@ static int tftpfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence);
|
||||
// For simplicity we use _FILESYSTEM synchronization for all accesses since
|
||||
// we should never block in any filesystem operations.
|
||||
#if 1
|
||||
FSTAB_ENTRY( tftpfs_fste, "tftpfs", 0,
|
||||
FSTAB_ENTRY(tftpfs_fste, "tftpfs", 0,
|
||||
CYG_SYNCMODE_NONE,
|
||||
tftpfs_mount,
|
||||
tftpfs_umount,
|
||||
@@ -1162,12 +1222,12 @@ FSTAB_ENTRY( tftpfs_fste, "tftpfs", 0,
|
||||
// mtab entry.
|
||||
// This defines a single ROMFS loaded into ROM at the configured address
|
||||
//
|
||||
// MTAB_ENTRY( rom_mte, // structure name
|
||||
// MTAB_ENTRY(rom_mte, // structure name
|
||||
// "/rom", // mount point
|
||||
// "romfs", // FIlesystem type
|
||||
// "", // hardware device
|
||||
// (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS // Address in ROM
|
||||
// );
|
||||
//);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -1470,8 +1530,8 @@ static int logfs_fo_close(struct CYG_FILE_TAG *fp);
|
||||
// This defines the entry in the filesystem table.
|
||||
// For simplicity we use _FILESYSTEM synchronization for all accesses since
|
||||
// we should never block in any filesystem operations.
|
||||
FSTAB_ENTRY( logfs_fste, "logfs", 0,
|
||||
CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
|
||||
FSTAB_ENTRY(logfs_fste, "logfs", 0,
|
||||
CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
|
||||
logfs_mount,
|
||||
logfs_umount,
|
||||
logfs_open,
|
||||
@@ -1558,3 +1618,26 @@ static int logfs_fo_close(struct CYG_FILE_TAG *fp)
|
||||
return ENOERR;
|
||||
}
|
||||
|
||||
int loadFile(const char *fileName, void **data, int *len);
|
||||
|
||||
/* boolean parameter stored on config */
|
||||
int boolParam(char *var)
|
||||
{
|
||||
bool result = false;
|
||||
char *name = alloc_printf("%s/%s", zylin_config_dir, var);
|
||||
if (name == NULL)
|
||||
return result;
|
||||
|
||||
void *data;
|
||||
int len;
|
||||
if (loadFile(name, &data, &len) == ERROR_OK)
|
||||
{
|
||||
if (len > 1)
|
||||
len = 1;
|
||||
result = strncmp((char *) data, "1", len) == 0;
|
||||
free(data);
|
||||
}
|
||||
free(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,70 @@
|
||||
INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
|
||||
AM_CPPFLAGS = -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@
|
||||
METASOURCES = AUTO
|
||||
noinst_LIBRARIES = libflash.a
|
||||
libflash_a_SOURCES = flash.c lpc2000.c cfi.c non_cfi.c at91sam7.c at91sam7_old.c str7x.c str9x.c aduc702x.c nand.c lpc3180_nand_controller.c \
|
||||
stellaris.c str9xpec.c stm32x.c tms470.c ecos.c \
|
||||
s3c24xx_nand.c s3c2410_nand.c s3c2412_nand.c s3c2440_nand.c s3c2443_nand.c lpc288x.c ocl.c mflash.c pic32mx.c
|
||||
noinst_HEADERS = flash.h lpc2000.h cfi.h non_cfi.h at91sam7.h at91sam7_old.h str7x.h str9x.h nand.h lpc3180_nand_controller.h \
|
||||
stellaris.h str9xpec.h stm32x.h tms470.h s3c24xx_nand.h s3c24xx_regs_nand.h lpc288x.h mflash.h \
|
||||
ocl.h pic32mx.h
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag \
|
||||
-I$(top_srcdir)/src/target
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
METASOURCES = AUTO
|
||||
noinst_LTLIBRARIES = libflash.la
|
||||
libflash_la_SOURCES = \
|
||||
arm_nandio.c \
|
||||
flash.c \
|
||||
lpc2000.c \
|
||||
lpc288x.c \
|
||||
lpc2900.c \
|
||||
cfi.c \
|
||||
non_cfi.c \
|
||||
at91sam7.c \
|
||||
at91sam3.c \
|
||||
davinci_nand.c \
|
||||
str7x.c \
|
||||
str9x.c \
|
||||
aduc702x.c \
|
||||
nand.c \
|
||||
nand_ecc.c \
|
||||
nand_ecc_kw.c \
|
||||
lpc3180_nand_controller.c \
|
||||
stellaris.c \
|
||||
str9xpec.c \
|
||||
stm32x.c \
|
||||
tms470.c \
|
||||
ecos.c \
|
||||
orion_nand.c \
|
||||
s3c24xx_nand.c \
|
||||
s3c2410_nand.c \
|
||||
s3c2412_nand.c \
|
||||
s3c2440_nand.c \
|
||||
s3c2443_nand.c \
|
||||
ocl.c \
|
||||
mflash.c \
|
||||
pic32mx.c \
|
||||
avrf.c \
|
||||
faux.c \
|
||||
mx3_nand.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
arm_nandio.h \
|
||||
flash.h \
|
||||
lpc2000.h \
|
||||
lpc288x.h \
|
||||
lpc2900.h \
|
||||
cfi.h \
|
||||
non_cfi.h \
|
||||
at91sam7.h \
|
||||
at91sam3.h \
|
||||
str7x.h \
|
||||
str9x.h \
|
||||
nand.h \
|
||||
lpc3180_nand_controller.h \
|
||||
stellaris.h \
|
||||
str9xpec.h \
|
||||
stm32x.h \
|
||||
tms470.h \
|
||||
s3c24xx_nand.h \
|
||||
s3c24xx_regs_nand.h \
|
||||
mflash.h \
|
||||
ocl.h \
|
||||
pic32mx.h \
|
||||
avrf.h \
|
||||
mx3_nand.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
@@ -23,32 +23,25 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "time_support.h"
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "armv4_5.h"
|
||||
#include "algorithm.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "time_support.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int aduc702x_register_commands(struct command_context_s *cmd_ctx);
|
||||
int aduc702x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int aduc702x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int aduc702x_write_single(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int aduc702x_probe(struct flash_bank_s *bank);
|
||||
int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
int aduc702x_protect_check(struct flash_bank_s *bank);
|
||||
int aduc702x_build_sector_list(struct flash_bank_s *bank);
|
||||
int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms);
|
||||
int aduc702x_set_write_enable(target_t *target, int enable);
|
||||
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int aduc702x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int aduc702x_probe(struct flash_bank_s *bank);
|
||||
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int aduc702x_protect_check(struct flash_bank_s *bank);
|
||||
static int aduc702x_build_sector_list(struct flash_bank_s *bank);
|
||||
static int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms);
|
||||
static int aduc702x_set_write_enable(target_t *target, int enable);
|
||||
|
||||
#define ADUC702x_FLASH 0xfffff800
|
||||
#define ADUC702x_FLASH_FEESTA (0*4)
|
||||
@@ -61,14 +54,14 @@ int aduc702x_set_write_enable(target_t *target, int enable);
|
||||
#define ADUC702x_FLASH_FEEHIDE (7*4)
|
||||
|
||||
typedef struct {
|
||||
u32 feesta;
|
||||
u32 feemod;
|
||||
u32 feecon;
|
||||
u32 feedat;
|
||||
u32 feeadr;
|
||||
u32 feesign;
|
||||
u32 feepro;
|
||||
u32 feehide;
|
||||
uint32_t feesta;
|
||||
uint32_t feemod;
|
||||
uint32_t feecon;
|
||||
uint32_t feedat;
|
||||
uint32_t feeadr;
|
||||
uint32_t feesign;
|
||||
uint32_t feepro;
|
||||
uint32_t feehide;
|
||||
} ADUC702x_FLASH_MMIO;
|
||||
|
||||
typedef struct
|
||||
@@ -91,14 +84,14 @@ flash_driver_t aduc702x_flash =
|
||||
.info = aduc702x_info
|
||||
};
|
||||
|
||||
int aduc702x_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int aduc702x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash bank aduc702x 0 0 0 0 <target#>
|
||||
* The ADC7019-28 devices all have the same flash layout */
|
||||
int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
aduc702x_flash_bank_t *nbank;
|
||||
|
||||
@@ -113,12 +106,12 @@ int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_build_sector_list(struct flash_bank_s *bank)
|
||||
static int aduc702x_build_sector_list(struct flash_bank_s *bank)
|
||||
{
|
||||
//aduc7026_flash_bank_t *aduc7026_info = bank->driver_priv;
|
||||
|
||||
int i = 0;
|
||||
u32 offset = 0;
|
||||
uint32_t offset = 0;
|
||||
|
||||
// sector size is 512
|
||||
bank->num_sectors = bank->size / 512;
|
||||
@@ -135,18 +128,18 @@ int aduc702x_build_sector_list(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_protect_check(struct flash_bank_s *bank)
|
||||
static int aduc702x_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
printf("aduc702x_protect_check not implemented yet.\n");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
//int res;
|
||||
int x;
|
||||
int count;
|
||||
//u32 v;
|
||||
//uint32_t v;
|
||||
target_t *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
@@ -194,23 +187,34 @@ int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
printf("aduc702x_protect not implemented yet.\n");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
|
||||
* back to another mechanism that does not require onboard RAM
|
||||
*
|
||||
* Caller should not check for other return values specifically
|
||||
*/
|
||||
static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
aduc702x_flash_bank_t *aduc702x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 buffer_size = 7000;
|
||||
uint32_t buffer_size = 7000;
|
||||
working_area_t *source;
|
||||
u32 address = bank->base + offset;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[6];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (((count%2)!=0)||((offset%2)!=0))
|
||||
{
|
||||
LOG_ERROR("write block must be multiple of two bytes in offset & length");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* parameters:
|
||||
|
||||
r0 - address of source data (absolute)
|
||||
@@ -225,7 +229,7 @@ int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
r6 - set to 2, used to write flash command
|
||||
|
||||
*/
|
||||
u32 aduc702x_flash_write_code[] = {
|
||||
uint32_t aduc702x_flash_write_code[] = {
|
||||
//<_start>:
|
||||
0xe3a05008, // mov r5, #8 ; 0x8
|
||||
0xe5845004, // str r5, [r4, #4]
|
||||
@@ -256,8 +260,12 @@ int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
|
||||
target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
||||
sizeof(aduc702x_flash_write_code), (u8*)aduc702x_flash_write_code);
|
||||
retval=target_write_buffer(target, aduc702x_info->write_algorithm->address,
|
||||
sizeof(aduc702x_flash_write_code), (uint8_t*)aduc702x_flash_write_code);
|
||||
if (retval!=ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* memory buffer */
|
||||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
|
||||
@@ -286,32 +294,38 @@ int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
|
||||
uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;
|
||||
|
||||
target_write_buffer(target, source->address, thisrun_count * 2, buffer);
|
||||
retval=target_write_buffer(target, source->address, thisrun_count, buffer);
|
||||
if (retval!=ERROR_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, source->address);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, thisrun_count);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);
|
||||
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 5,
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 5,
|
||||
reg_params, aduc702x_info->write_algorithm->address,
|
||||
aduc702x_info->write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4,
|
||||
10000, &armv4_5_info)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error executing aduc702x flash write algorithm");
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) {
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1)
|
||||
{
|
||||
/* FIX!!!! what does this mean??? replace w/sensible error message */
|
||||
LOG_ERROR("aduc702x detected error writing flash");
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += thisrun_count * 2;
|
||||
address += thisrun_count * 2;
|
||||
buffer += thisrun_count;
|
||||
address += thisrun_count;
|
||||
count -= thisrun_count;
|
||||
}
|
||||
|
||||
@@ -329,10 +343,10 @@ int aduc702x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
|
||||
/* All-JTAG, single-access method. Very slow. Used only if there is no
|
||||
* working area available. */
|
||||
int aduc702x_write_single(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int x;
|
||||
u8 b;
|
||||
uint32_t x;
|
||||
uint8_t b;
|
||||
target_t *target = bank->target;
|
||||
|
||||
aduc702x_set_write_enable(target, 1);
|
||||
@@ -370,7 +384,7 @@ int aduc702x_write_single(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -389,30 +403,25 @@ int aduc702x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
else if (retval == ERROR_FLASH_OPERATION_FAILED)
|
||||
{
|
||||
LOG_ERROR("flash block writing failed");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int aduc702x_probe(struct flash_bank_s *bank)
|
||||
static int aduc702x_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "aduc702x flash driver info" );
|
||||
snprintf(buf, buf_size, "aduc702x flash driver info");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* sets FEEMOD bit 3
|
||||
* enable = 1 enables writes & erases, 0 disables them */
|
||||
int aduc702x_set_write_enable(target_t *target, int enable)
|
||||
static int aduc702x_set_write_enable(target_t *target, int enable)
|
||||
{
|
||||
// don't bother to preserve int enable bit here
|
||||
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
|
||||
@@ -425,9 +434,9 @@ int aduc702x_set_write_enable(target_t *target, int enable)
|
||||
*
|
||||
* this function sleeps 1ms between checks (after the first one),
|
||||
* so in some cases may slow things down without a usleep after the first read */
|
||||
int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms)
|
||||
static int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms)
|
||||
{
|
||||
u8 v = 4;
|
||||
uint8_t v = 4;
|
||||
|
||||
long long endtime = timeval_ms() + timeout_ms;
|
||||
while (1) {
|
||||
|
||||
134
src/flash/arm_nandio.c
Normal file
134
src/flash/arm_nandio.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2009 by Marvell Semiconductors, Inc.
|
||||
* Written by Nicolas Pitre <nico at marvell.com>
|
||||
*
|
||||
* Copyright (C) 2009 by David Brownell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arm_nandio.h"
|
||||
#include "armv4_5.h"
|
||||
|
||||
|
||||
/*
|
||||
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
|
||||
* For now this only supports ARMv4 and ARMv5 cores.
|
||||
*
|
||||
* Enhancements to target_run_algorithm() could enable:
|
||||
* - ARMv6 and ARMv7 cores in ARM mode
|
||||
*
|
||||
* Different code fragments could handle:
|
||||
* - Thumb2 cores like Cortex-M (needs different byteswapping)
|
||||
* - 16-bit wide data (needs different setup too)
|
||||
*/
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
|
||||
{
|
||||
target_t *target = nand->target;
|
||||
armv4_5_algorithm_t algo;
|
||||
armv4_5_common_t *armv4_5 = target->arch_info;
|
||||
reg_param_t reg_params[3];
|
||||
uint32_t target_buf;
|
||||
uint32_t exit = 0;
|
||||
int retval;
|
||||
|
||||
/* Inputs:
|
||||
* r0 NAND data address (byte wide)
|
||||
* r1 buffer address
|
||||
* r2 buffer length
|
||||
*/
|
||||
static const uint32_t code[] = {
|
||||
0xe4d13001, /* s: ldrb r3, [r1], #1 */
|
||||
0xe5c03000, /* strb r3, [r0] */
|
||||
0xe2522001, /* subs r2, r2, #1 */
|
||||
0x1afffffb, /* bne s */
|
||||
|
||||
/* exit: ARMv4 needs hardware breakpoint */
|
||||
0xe1200070, /* e: bkpt #0 */
|
||||
};
|
||||
|
||||
if (!nand->copy_area) {
|
||||
uint8_t code_buf[sizeof(code)];
|
||||
unsigned i;
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target,
|
||||
sizeof(code) + nand->chunk_size,
|
||||
&nand->copy_area) != ERROR_OK) {
|
||||
LOG_DEBUG("%s: no %d byte buffer",
|
||||
__FUNCTION__,
|
||||
(int) sizeof(code) + nand->chunk_size);
|
||||
return ERROR_NAND_NO_BUFFER;
|
||||
}
|
||||
|
||||
/* buffer code in target endianness */
|
||||
for (i = 0; i < sizeof(code) / 4; i++)
|
||||
target_buffer_set_u32(target, code_buf + i * 4, code[i]);
|
||||
|
||||
/* copy code to work area */
|
||||
retval = target_write_memory(target,
|
||||
nand->copy_area->address,
|
||||
4, sizeof(code) / 4, code_buf);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* copy data to work area */
|
||||
target_buf = nand->copy_area->address + sizeof(code);
|
||||
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
|
||||
if (retval == ERROR_OK && (size & 3) != 0)
|
||||
retval = target_write_memory(target,
|
||||
target_buf + (size & ~3),
|
||||
1, size & 3, data + (size & ~3));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* set up algorithm and parameters */
|
||||
algo.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
algo.core_mode = ARMV4_5_MODE_SVC;
|
||||
algo.core_state = ARMV4_5_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_IN);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_IN);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, nand->data);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, size);
|
||||
|
||||
/* armv4 must exit using a hardware breakpoint */
|
||||
if (armv4_5->is_armv4)
|
||||
exit = nand->copy_area->address + sizeof(code) - 4;
|
||||
|
||||
/* use alg to write data from work area to NAND chip */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
nand->copy_area->address, exit, 1000, &algo);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("error executing hosted NAND write");
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* REVISIT do the same for bulk *read* too ... */
|
||||
|
||||
25
src/flash/arm_nandio.h
Normal file
25
src/flash/arm_nandio.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef __ARM_NANDIO_H
|
||||
#define __ARM_NANDIO_H
|
||||
|
||||
#include "nand.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
struct arm_nand_data {
|
||||
/* target is proxy for some ARM core */
|
||||
struct target_s *target;
|
||||
|
||||
/* copy_area holds write-to-NAND loop and data to write */
|
||||
struct working_area_s *copy_area;
|
||||
|
||||
/* chunk_size == page or ECC unit */
|
||||
unsigned chunk_size;
|
||||
|
||||
/* data == where to write the data */
|
||||
uint32_t data;
|
||||
|
||||
/* currently implicit: data width == 8 bits (not 16) */
|
||||
};
|
||||
|
||||
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size);
|
||||
|
||||
#endif /* __ARM_NANDIO_H */
|
||||
2531
src/flash/at91sam3.c
Normal file
2531
src/flash/at91sam3.c
Normal file
File diff suppressed because it is too large
Load Diff
23
src/flash/at91sam3.h
Normal file
23
src/flash/at91sam3.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Duane Ellis *
|
||||
* openocd@duaneellis.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. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
// nothing to do here other then export this.
|
||||
extern flash_driver_t at91sam3_flash;
|
||||
@@ -20,59 +20,59 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
****************************************************************************/
|
||||
|
||||
/***************************************************************************************************************************************************************************************
|
||||
/***************************************************************************
|
||||
*
|
||||
* New flash setup command:
|
||||
*
|
||||
* flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>]
|
||||
* flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_id>
|
||||
* [<chip_type> <banks>
|
||||
* <sectors_per_bank> <pages_per_sector>
|
||||
* <page_size> <num_nvmbits>
|
||||
* <ext_freq_khz>]
|
||||
*
|
||||
* <ext_freq_khz> - MUST be used if clock is from external source,
|
||||
* CAN be used if main oscillator frequency is known (recomended)
|
||||
* CAN be used if main oscillator frequency is known (recommended)
|
||||
* Examples:
|
||||
* flash bank at91sam7 0x00100000 0 0 4 0 0 AT91SAM7XC256 1 16 64 256 3 25000 ==== RECOMENDED ============
|
||||
* flash bank at91sam7 0 0 0 0 0 0 0 0 0 0 0 0 25000 (auto-detection, except for clock) ==== RECOMENDED ============
|
||||
* flash bank at91sam7 0x00100000 0 0 4 0 0 AT91SAM7XC256 1 16 64 256 3 0 ==== NOT RECOMENDED !!! ====
|
||||
* flash bank at91sam7 0 0 0 0 0 (old style, full auto-detection) ==== NOT RECOMENDED !!! ====
|
||||
****************************************************************************************************************************************************************************************/
|
||||
* ==== RECOMMENDED (covers clock speed) ============
|
||||
* flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000
|
||||
* (if auto-detect fails; provides clock spec)
|
||||
* flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000
|
||||
* (auto-detect everything except the clock)
|
||||
* ==== NOT RECOMMENDED !!! (clock speed is not configured) ====
|
||||
* flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0
|
||||
* (if auto-detect fails)
|
||||
* flash bank at91sam7 0 0 0 0 $_TARGETNAME
|
||||
* (old style, auto-detect everything)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "at91sam7.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int at91sam7_register_commands(struct command_context_s *cmd_ctx);
|
||||
int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int at91sam7_probe(struct flash_bank_s *bank);
|
||||
int at91sam7_auto_probe(struct flash_bank_s *bank);
|
||||
int at91sam7_erase_check(struct flash_bank_s *bank);
|
||||
int at91sam7_protect_check(struct flash_bank_s *bank);
|
||||
int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int at91sam7_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int at91sam7_probe(struct flash_bank_s *bank);
|
||||
//static int at91sam7_auto_probe(struct flash_bank_s *bank);
|
||||
static int at91sam7_erase_check(struct flash_bank_s *bank);
|
||||
static int at91sam7_protect_check(struct flash_bank_s *bank);
|
||||
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
u32 at91sam7_get_flash_status(target_t *target, int bank_number);
|
||||
void at91sam7_set_flash_mode(flash_bank_t *bank, int mode);
|
||||
u32 at91sam7_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);
|
||||
int at91sam7_flash_command(struct flash_bank_s *bank, u8 cmd, u16 pagen);
|
||||
int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number);
|
||||
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode);
|
||||
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
|
||||
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen);
|
||||
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t at91sam7_flash =
|
||||
{
|
||||
.name = "at91sam7_new",
|
||||
.name = "at91sam7",
|
||||
.register_commands = at91sam7_register_commands,
|
||||
.flash_bank_command = at91sam7_flash_bank_command,
|
||||
.erase = at91sam7_erase,
|
||||
@@ -85,13 +85,14 @@ flash_driver_t at91sam7_flash =
|
||||
.info = at91sam7_info
|
||||
};
|
||||
|
||||
u32 MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
|
||||
u32 MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
||||
u32 MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
||||
static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
|
||||
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
||||
static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
||||
|
||||
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"};
|
||||
|
||||
long SRAMSIZ[16] = {
|
||||
#if 0
|
||||
static long SRAMSIZ[16] = {
|
||||
-1,
|
||||
0x0400, /* 1K */
|
||||
0x0800, /* 2K */
|
||||
@@ -109,30 +110,31 @@ long SRAMSIZ[16] = {
|
||||
0x18000, /* 96K */
|
||||
0x80000, /* 512K */
|
||||
};
|
||||
#endif
|
||||
|
||||
int at91sam7_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int at91sam7_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7_new", NULL, COMMAND_ANY, NULL);
|
||||
command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,
|
||||
"at91sam7 gpnvm <bit> set|clear, set or clear one gpnvm bit");
|
||||
"at91sam7 gpnvm <bit> set | clear, set or clear one gpnvm bit");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 at91sam7_get_flash_status(target_t *target, int bank_number)
|
||||
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number)
|
||||
{
|
||||
u32 fsr;
|
||||
uint32_t fsr;
|
||||
target_read_u32(target, MC_FSR[bank_number], &fsr);
|
||||
|
||||
return fsr;
|
||||
}
|
||||
|
||||
/* Read clock configuration and set at91sam7_info->mck_freq */
|
||||
void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
static void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
{
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 mckr, mcfr, pllr, mor;
|
||||
uint32_t mckr, mcfr, pllr, mor;
|
||||
unsigned long tmp = 0, mainfreq;
|
||||
|
||||
/* Read Clock Generator Main Oscillator Register */
|
||||
@@ -195,7 +197,7 @@ void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
}
|
||||
|
||||
/* Prescaler adjust */
|
||||
if ( (((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0) )
|
||||
if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0))
|
||||
{
|
||||
at91sam7_info->mck_valid = 0;
|
||||
at91sam7_info->mck_freq = 0;
|
||||
@@ -207,9 +209,9 @@ void at91sam7_read_clock_info(flash_bank_t *bank)
|
||||
}
|
||||
|
||||
/* Setup the timimg registers for nvbits or normal flash */
|
||||
void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
{
|
||||
u32 fmr, fmcn = 0, fws = 0;
|
||||
uint32_t fmr, fmcn = 0, fws = 0;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
@@ -221,33 +223,33 @@ void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
if (at91sam7_info->cidr_arch == 0x60)
|
||||
{
|
||||
/* AT91SAM7A3 uses master clocks in 100 ns */
|
||||
fmcn = (at91sam7_info->mck_freq/10000000ul)+1;
|
||||
fmcn = (at91sam7_info->mck_freq/10000000ul) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* master clocks in 1uS for ARCH 0x7 types */
|
||||
fmcn = (at91sam7_info->mck_freq/1000000ul)+1;
|
||||
fmcn = (at91sam7_info->mck_freq/1000000ul) + 1;
|
||||
}
|
||||
}
|
||||
else if (mode == FMR_TIMING_FLASH)
|
||||
{
|
||||
/* main clocks in 1.5uS */
|
||||
fmcn = (at91sam7_info->mck_freq/1000000ul)+
|
||||
(at91sam7_info->mck_freq/2000000ul)+1;
|
||||
(at91sam7_info->mck_freq/2000000ul) + 1;
|
||||
}
|
||||
|
||||
/* hard overclocking */
|
||||
if (fmcn > 0xFF)
|
||||
fmcn = 0xFF;
|
||||
|
||||
/* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
|
||||
/* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */
|
||||
if (at91sam7_info->mck_freq <= 33333ul)
|
||||
fmcn = 0;
|
||||
/* Only allow fws=0 if clock frequency is < 30 MHz. */
|
||||
/* Only allow fws = 0 if clock frequency is < 30 MHz. */
|
||||
if (at91sam7_info->mck_freq > 30000000ul)
|
||||
fws = 1;
|
||||
|
||||
LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, fmcn);
|
||||
LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn));
|
||||
fmr = fmcn << 16 | fws << 8;
|
||||
target_write_u32(target, MC_FMR[bank->bank_number], fmr);
|
||||
}
|
||||
@@ -255,21 +257,21 @@ void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
|
||||
at91sam7_info->flashmode = mode;
|
||||
}
|
||||
|
||||
u32 at91sam7_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
|
||||
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0))
|
||||
{
|
||||
LOG_DEBUG("status[%i]: 0x%x", bank->bank_number, status);
|
||||
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status);
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
LOG_DEBUG("status[%i]: 0x%x", bank->bank_number, status);
|
||||
LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status);
|
||||
|
||||
if (status & 0x0C)
|
||||
{
|
||||
LOG_ERROR("status register: 0x%x", status);
|
||||
LOG_ERROR("status register: 0x%" PRIx32 "", status);
|
||||
if (status & 0x4)
|
||||
LOG_ERROR("Lock Error Bit Detected, Operation Abort");
|
||||
if (status & 0x8)
|
||||
@@ -282,17 +284,17 @@ u32 at91sam7_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
|
||||
}
|
||||
|
||||
/* Send one command to the AT91SAM flash controller */
|
||||
int at91sam7_flash_command(struct flash_bank_s *bank, u8 cmd, u16 pagen)
|
||||
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen)
|
||||
{
|
||||
u32 fcr;
|
||||
uint32_t fcr;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
fcr = (0x5A<<24) | ((pagen&0x3FF)<<8) | cmd;
|
||||
fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
|
||||
target_write_u32(target, MC_FCR[bank->bank_number], fcr);
|
||||
LOG_DEBUG("Flash command: 0x%x, flash bank: %i, page number: %u", fcr, bank->bank_number+1, pagen);
|
||||
LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen);
|
||||
|
||||
if ((at91sam7_info->cidr_arch == 0x60)&&((cmd==SLB)|(cmd==CLB)))
|
||||
if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB)))
|
||||
{
|
||||
/* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
|
||||
if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C)
|
||||
@@ -311,23 +313,23 @@ int at91sam7_flash_command(struct flash_bank_s *bank, u8 cmd, u16 pagen)
|
||||
}
|
||||
|
||||
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||
int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
static int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
{
|
||||
flash_bank_t *t_bank = bank;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
target_t *target = t_bank->target;
|
||||
|
||||
u16 bnk, sec;
|
||||
u16 arch;
|
||||
u32 cidr;
|
||||
u8 banks_num;
|
||||
u16 num_nvmbits;
|
||||
u16 sectors_num;
|
||||
u16 pages_per_sector;
|
||||
u16 page_size;
|
||||
u32 ext_freq;
|
||||
u32 bank_size;
|
||||
u32 base_address = 0;
|
||||
uint16_t bnk, sec;
|
||||
uint16_t arch;
|
||||
uint32_t cidr;
|
||||
uint8_t banks_num = 0;
|
||||
uint16_t num_nvmbits = 0;
|
||||
uint16_t sectors_num = 0;
|
||||
uint16_t pages_per_sector = 0;
|
||||
uint16_t page_size = 0;
|
||||
uint32_t ext_freq;
|
||||
uint32_t bank_size;
|
||||
uint32_t base_address = 0;
|
||||
char *target_name = "Unknown";
|
||||
|
||||
at91sam7_info = t_bank->driver_priv;
|
||||
@@ -374,13 +376,13 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
at91sam7_info = t_bank->driver_priv;
|
||||
|
||||
at91sam7_info->cidr = cidr;
|
||||
at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
|
||||
at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
|
||||
at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
|
||||
at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
|
||||
at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
|
||||
at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
|
||||
at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
|
||||
at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
|
||||
at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
|
||||
at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
|
||||
at91sam7_info->cidr_version = cidr&0x001F;
|
||||
|
||||
/* calculate master clock frequency */
|
||||
@@ -399,10 +401,10 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
arch = (cidr>>20)&0x00FF;
|
||||
arch = (cidr >> 20)&0x00FF;
|
||||
|
||||
/* check flash size */
|
||||
switch ((cidr>>8)&0x000F)
|
||||
switch ((cidr >> 8)&0x000F)
|
||||
{
|
||||
case FLASH_SIZE_8KB:
|
||||
break;
|
||||
@@ -558,7 +560,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
/* calculate bank size */
|
||||
bank_size = sectors_num * pages_per_sector * page_size;
|
||||
|
||||
for (bnk=0; bnk<banks_num; bnk++)
|
||||
for (bnk = 0; bnk < banks_num; bnk++)
|
||||
{
|
||||
if (bnk > 0)
|
||||
{
|
||||
@@ -583,7 +585,7 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
|
||||
/* allocate sectors */
|
||||
t_bank->sectors = malloc(sectors_num * sizeof(flash_sector_t));
|
||||
for (sec=0; sec<sectors_num; sec++)
|
||||
for (sec = 0; sec < sectors_num; sec++)
|
||||
{
|
||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
||||
@@ -594,13 +596,13 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
at91sam7_info = t_bank->driver_priv;
|
||||
|
||||
at91sam7_info->cidr = cidr;
|
||||
at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
|
||||
at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
|
||||
at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
|
||||
at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
|
||||
at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
|
||||
at91sam7_info->cidr_ext = (cidr >> 31)&0x0001;
|
||||
at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007;
|
||||
at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF;
|
||||
at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F;
|
||||
at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F;
|
||||
at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
|
||||
at91sam7_info->cidr_version = cidr&0x001F;
|
||||
|
||||
at91sam7_info->target_name = target_name;
|
||||
@@ -621,20 +623,20 @@ int at91sam7_read_part_info(struct flash_bank_s *bank)
|
||||
at91sam7_protect_check(t_bank);
|
||||
}
|
||||
|
||||
LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );
|
||||
LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
static int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u16 retval;
|
||||
u32 blank;
|
||||
u16 fast_check;
|
||||
u8 *buffer;
|
||||
u16 nSector;
|
||||
u16 nByte;
|
||||
uint16_t retval;
|
||||
uint32_t blank;
|
||||
uint16_t fast_check;
|
||||
uint8_t *buffer;
|
||||
uint16_t nSector;
|
||||
uint16_t nByte;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -647,9 +649,9 @@ int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||
|
||||
fast_check = 1;
|
||||
for (nSector=0; nSector<bank->num_sectors; nSector++)
|
||||
for (nSector = 0; nSector < bank->num_sectors; nSector++)
|
||||
{
|
||||
retval = target_blank_check_memory(target, bank->base+bank->sectors[nSector].offset,
|
||||
retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset,
|
||||
bank->sectors[nSector].size, &blank);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
@@ -670,15 +672,15 @@ int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
LOG_USER("Running slow fallback erase check - add working memory");
|
||||
|
||||
buffer = malloc(bank->sectors[0].size);
|
||||
for (nSector=0; nSector<bank->num_sectors; nSector++)
|
||||
for (nSector = 0; nSector < bank->num_sectors; nSector++)
|
||||
{
|
||||
bank->sectors[nSector].is_erased = 1;
|
||||
retval = target->type->read_memory(target, bank->base+bank->sectors[nSector].offset, 4,
|
||||
retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
|
||||
bank->sectors[nSector].size/4, buffer);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
for (nByte=0; nByte<bank->sectors[nSector].size; nByte++)
|
||||
for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++)
|
||||
{
|
||||
if (buffer[nByte] != 0xFF)
|
||||
{
|
||||
@@ -692,10 +694,10 @@ int at91sam7_erase_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
static int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
u8 lock_pos, gpnvm_pos;
|
||||
u32 status;
|
||||
uint8_t lock_pos, gpnvm_pos;
|
||||
uint32_t status;
|
||||
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
|
||||
@@ -710,12 +712,12 @@ int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
}
|
||||
|
||||
status = at91sam7_get_flash_status(bank->target, bank->bank_number);
|
||||
at91sam7_info->lockbits = (status>>16);
|
||||
at91sam7_info->lockbits = (status >> 16);
|
||||
|
||||
at91sam7_info->num_lockbits_on = 0;
|
||||
for (lock_pos=0; lock_pos<bank->num_sectors; lock_pos++)
|
||||
for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++)
|
||||
{
|
||||
if ( ((status>>(16+lock_pos))&(0x0001)) == 1)
|
||||
if (((status >> (16 + lock_pos))&(0x0001)) == 1)
|
||||
{
|
||||
at91sam7_info->num_lockbits_on++;
|
||||
bank->sectors[lock_pos].is_protected = 1;
|
||||
@@ -727,13 +729,13 @@ int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
||||
status = at91sam7_get_flash_status(bank->target, 0);
|
||||
|
||||
at91sam7_info->securitybit = (status>>4)&0x01;
|
||||
at91sam7_info->nvmbits = (status>>8)&0xFF;
|
||||
at91sam7_info->securitybit = (status >> 4)&0x01;
|
||||
at91sam7_info->nvmbits = (status >> 8)&0xFF;
|
||||
|
||||
at91sam7_info->num_nvmbits_on = 0;
|
||||
for (gpnvm_pos=0; gpnvm_pos<at91sam7_info->num_nvmbits; gpnvm_pos++)
|
||||
for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++)
|
||||
{
|
||||
if ( ((status>>(8+gpnvm_pos))&(0x01)) == 1)
|
||||
if (((status >> (8 + gpnvm_pos))&(0x01)) == 1)
|
||||
{
|
||||
at91sam7_info->num_nvmbits_on++;
|
||||
}
|
||||
@@ -742,34 +744,24 @@ int at91sam7_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************************************************************************
|
||||
# flash bank <driver> <base_addr> <size> <chip_width> <bus_width> <target_number> [<target_name> <banks> <sectors_per_bank> <pages_per_sector> <page_size> <num_nvmbits> <ext_freq_khz>]
|
||||
# <ext_freq_khz> - MUST be used if clock is from external source
|
||||
# CAN be used if main oscillator frequency is known
|
||||
# Examples:
|
||||
# flash bank at91sam7 0x00100000 0 0 4 0 0 AT91SAM7XC256 1 16 64 256 3 25000 ==== RECOMENDED ============
|
||||
# flash bank at91sam7 0 0 0 0 0 0 0 0 0 0 0 0 25000 (auto-detection, except for clock) ==== RECOMENDED ============
|
||||
# flash bank at91sam7 0x00100000 0 0 4 0 0 AT91SAM7XC256 1 16 64 256 3 0 ==== NOT RECOMENDED !!! ====
|
||||
# flash bank at91sam7 0 0 0 0 0 (old style, full auto-detection) ==== NOT RECOMENDED !!! ====
|
||||
****************************************************************************************************************************************************************************************/
|
||||
int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
flash_bank_t *t_bank = bank;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
target_t *target = t_bank->target;
|
||||
|
||||
u32 base_address;
|
||||
u32 bank_size;
|
||||
u32 ext_freq;
|
||||
uint32_t base_address;
|
||||
uint32_t bank_size;
|
||||
uint32_t ext_freq;
|
||||
|
||||
int chip_width;
|
||||
int bus_width;
|
||||
int banks_num;
|
||||
int num_sectors;
|
||||
|
||||
u16 pages_per_sector;
|
||||
u16 page_size;
|
||||
u16 num_nvmbits;
|
||||
uint16_t pages_per_sector;
|
||||
uint16_t page_size;
|
||||
uint16_t num_nvmbits;
|
||||
|
||||
char *target_name;
|
||||
|
||||
@@ -811,13 +803,13 @@ int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
page_size = atoi(args[11]);
|
||||
num_nvmbits = atoi(args[12]);
|
||||
|
||||
target_name = calloc(strlen(args[7])+1, sizeof(char));
|
||||
target_name = calloc(strlen(args[7]) + 1, sizeof(char));
|
||||
strcpy(target_name, args[7]);
|
||||
|
||||
/* calculate bank size */
|
||||
bank_size = num_sectors * pages_per_sector * page_size;
|
||||
|
||||
for (bnk=0; bnk<banks_num; bnk++)
|
||||
for (bnk = 0; bnk < banks_num; bnk++)
|
||||
{
|
||||
if (bnk > 0)
|
||||
{
|
||||
@@ -842,7 +834,7 @@ int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
|
||||
/* allocate sectors */
|
||||
t_bank->sectors = malloc(num_sectors * sizeof(flash_sector_t));
|
||||
for (sec=0; sec<num_sectors; sec++)
|
||||
for (sec = 0; sec < num_sectors; sec++)
|
||||
{
|
||||
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
|
||||
t_bank->sectors[sec].size = pages_per_sector * page_size;
|
||||
@@ -864,13 +856,13 @@ int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
int sec;
|
||||
u32 nbytes, pos;
|
||||
u8 *buffer;
|
||||
u8 erase_all;
|
||||
uint32_t nbytes, pos;
|
||||
uint8_t *buffer;
|
||||
uint8_t erase_all;
|
||||
|
||||
if (at91sam7_info->cidr == 0)
|
||||
{
|
||||
@@ -898,7 +890,7 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
at91sam7_read_clock_info(bank);
|
||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||
|
||||
if(erase_all)
|
||||
if (erase_all)
|
||||
{
|
||||
if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK)
|
||||
{
|
||||
@@ -909,13 +901,13 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
/* allocate and clean buffer */
|
||||
nbytes = (last - first + 1) * bank->sectors[first].size;
|
||||
buffer = malloc(nbytes * sizeof(u8));
|
||||
for (pos=0; pos<nbytes; pos++)
|
||||
buffer = malloc(nbytes * sizeof(uint8_t));
|
||||
for (pos = 0; pos < nbytes; pos++)
|
||||
{
|
||||
buffer[pos] = 0xFF;
|
||||
}
|
||||
|
||||
if ( at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
|
||||
if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
@@ -924,7 +916,7 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
}
|
||||
|
||||
/* mark erased sectors */
|
||||
for (sec=first; sec<=last; sec++)
|
||||
for (sec = first; sec <= last; sec++)
|
||||
{
|
||||
bank->sectors[sec].is_erased = 1;
|
||||
}
|
||||
@@ -932,10 +924,11 @@ int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
u32 cmd;
|
||||
u32 sector, pagen;
|
||||
uint32_t cmd;
|
||||
int sector;
|
||||
uint32_t pagen;
|
||||
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
|
||||
@@ -959,7 +952,7 @@ int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
at91sam7_read_clock_info(bank);
|
||||
at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS);
|
||||
|
||||
for (sector=first; sector<=last; sector++)
|
||||
for (sector = first; sector <= last; sector++)
|
||||
{
|
||||
if (set)
|
||||
cmd = SLB;
|
||||
@@ -981,13 +974,13 @@ int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 dst_min_alignment, wcount, bytes_remaining = count;
|
||||
u32 first_page, last_page, pagen, buffer_pos;
|
||||
uint32_t dst_min_alignment, wcount, bytes_remaining = count;
|
||||
uint32_t first_page, last_page, pagen, buffer_pos;
|
||||
|
||||
if (at91sam7_info->cidr == 0)
|
||||
{
|
||||
@@ -1007,7 +1000,7 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (offset % dst_min_alignment)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
@@ -1017,15 +1010,15 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
first_page = offset/dst_min_alignment;
|
||||
last_page = CEIL(offset + count, dst_min_alignment);
|
||||
|
||||
LOG_DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
|
||||
LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
|
||||
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_read_clock_info(bank);
|
||||
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
|
||||
|
||||
for (pagen=first_page; pagen<last_page; pagen++)
|
||||
for (pagen = first_page; pagen < last_page; pagen++)
|
||||
{
|
||||
if (bytes_remaining<dst_min_alignment)
|
||||
if (bytes_remaining < dst_min_alignment)
|
||||
count = bytes_remaining;
|
||||
else
|
||||
count = dst_min_alignment;
|
||||
@@ -1034,7 +1027,7 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
/* Write one block to the PageWriteBuffer */
|
||||
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
||||
wcount = CEIL(count,4);
|
||||
if((retval = target->type->write_memory(target, bank->base+pagen*dst_min_alignment, 4, wcount, buffer+buffer_pos)) != ERROR_OK)
|
||||
if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
@@ -1044,13 +1037,13 @@ int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
LOG_DEBUG("Write flash bank:%i page number:%i", bank->bank_number, pagen);
|
||||
LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_probe(struct flash_bank_s *bank)
|
||||
static int at91sam7_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we can't probe on an at91sam7
|
||||
* if this is an at91sam7, it has the configured flash */
|
||||
@@ -1069,7 +1062,7 @@ int at91sam7_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
|
||||
@@ -1086,17 +1079,21 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size,
|
||||
" Cidr: 0x%8.8x | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | Flashsize: 0x%8.8x\n",
|
||||
at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc],
|
||||
at91sam7_info->cidr_version, bank->size);
|
||||
printed = snprintf(buf,
|
||||
buf_size,
|
||||
" Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | Flashsize: 0x%8.8" PRIx32 "\n",
|
||||
at91sam7_info->cidr,
|
||||
at91sam7_info->cidr_arch,
|
||||
EPROC[at91sam7_info->cidr_eproc],
|
||||
at91sam7_info->cidr_version,
|
||||
bank->size);
|
||||
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size,
|
||||
" Master clock (estimated): %u KHz | External clock: %u KHz\n",
|
||||
at91sam7_info->mck_freq / 1000, at91sam7_info->ext_freq / 1000);
|
||||
(unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000));
|
||||
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
@@ -1130,18 +1127,18 @@ int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
* The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes
|
||||
* Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
|
||||
*/
|
||||
int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int bit;
|
||||
u8 flashcmd;
|
||||
u32 status;
|
||||
uint8_t flashcmd;
|
||||
uint32_t status;
|
||||
at91sam7_flash_bank_t *at91sam7_info;
|
||||
int retval;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
command_print(cmd_ctx, "at91sam7 gpnvm <bit> <set|clear>");
|
||||
command_print(cmd_ctx, "at91sam7 gpnvm <bit> <set | clear>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1202,7 +1199,7 @@ int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
|
||||
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
|
||||
status = at91sam7_get_flash_status(bank->target, 0);
|
||||
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value 0x%x, status 0x%x \n", flashcmd, bit, status);
|
||||
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32 " \n", flashcmd, bit, status);
|
||||
|
||||
/* check protect state */
|
||||
at91sam7_protect_check(bank);
|
||||
|
||||
@@ -24,49 +24,48 @@
|
||||
#define AT91SAM7_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct at91sam7_flash_bank_s
|
||||
{
|
||||
/* chip id register */
|
||||
u32 cidr;
|
||||
u16 cidr_ext;
|
||||
u16 cidr_nvptyp;
|
||||
u16 cidr_arch;
|
||||
u16 cidr_sramsiz;
|
||||
u16 cidr_nvpsiz;
|
||||
u16 cidr_nvpsiz2;
|
||||
u16 cidr_eproc;
|
||||
u16 cidr_version;
|
||||
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 */
|
||||
u8 flash_autodetection;
|
||||
uint8_t flash_autodetection;
|
||||
|
||||
/* flash geometry */
|
||||
u16 pages_per_sector;
|
||||
u16 pagesize;
|
||||
u16 pages_in_lockregion;
|
||||
uint16_t pages_per_sector;
|
||||
uint16_t pagesize;
|
||||
uint16_t pages_in_lockregion;
|
||||
|
||||
/* nv memory bits */
|
||||
u16 num_lockbits_on;
|
||||
u16 lockbits;
|
||||
u16 num_nvmbits;
|
||||
u16 num_nvmbits_on;
|
||||
u16 nvmbits;
|
||||
u8 securitybit;
|
||||
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) */
|
||||
u8 flashmode;
|
||||
uint8_t flashmode;
|
||||
|
||||
/* main clock status */
|
||||
u8 mck_valid;
|
||||
u32 mck_freq;
|
||||
uint8_t mck_valid;
|
||||
uint32_t mck_freq;
|
||||
|
||||
/* external clock frequency */
|
||||
u32 ext_freq;
|
||||
uint32_t ext_freq;
|
||||
|
||||
} at91sam7_flash_bank_t;
|
||||
|
||||
|
||||
@@ -1,954 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Magnus Lundin *
|
||||
* lundin@mlu.mine.nu *
|
||||
* *
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
There are some things to notice
|
||||
|
||||
* AT91SAM7S64 is tested
|
||||
* All AT91SAM7Sxx and AT91SAM7Xxx should work but is not tested
|
||||
* All parameters are identified from onchip configuartion registers
|
||||
*
|
||||
* The flash controller handles erases automatically on a page (128/265 byte) basis
|
||||
* Only an EraseAll command is supported by the controller
|
||||
* Partial erases can be implemented in software by writing one 0xFFFFFFFF word to
|
||||
* some location in every page in the region to be erased
|
||||
*
|
||||
* Lock regions (sectors) are 32 or 64 pages
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "at91sam7_old.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int at91sam7_old_register_commands(struct command_context_s *cmd_ctx);
|
||||
int at91sam7_old_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int at91sam7_old_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int at91sam7_old_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int at91sam7_old_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int at91sam7_old_probe(struct flash_bank_s *bank);
|
||||
int at91sam7_old_auto_probe(struct flash_bank_s *bank);
|
||||
int at91sam7_old_erase_check(struct flash_bank_s *bank);
|
||||
int at91sam7_old_protect_check(struct flash_bank_s *bank);
|
||||
int at91sam7_old_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
u32 at91sam7_old_get_flash_status(flash_bank_t *bank, u8 flashplane);
|
||||
void at91sam7_old_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode);
|
||||
u32 at91sam7_old_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout);
|
||||
int at91sam7_old_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen);
|
||||
int at91sam7_old_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t at91sam7_old_flash =
|
||||
{
|
||||
.name = "at91sam7",
|
||||
.register_commands = at91sam7_old_register_commands,
|
||||
.flash_bank_command = at91sam7_old_flash_bank_command,
|
||||
.erase = at91sam7_old_erase,
|
||||
.protect = at91sam7_old_protect,
|
||||
.write = at91sam7_old_write,
|
||||
.probe = at91sam7_old_probe,
|
||||
.auto_probe = at91sam7_old_probe,
|
||||
.erase_check = at91sam7_old_erase_check,
|
||||
.protect_check = at91sam7_old_protect_check,
|
||||
.info = at91sam7_old_info
|
||||
};
|
||||
|
||||
u32 MC_FMR_old[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
|
||||
u32 MC_FCR_old[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
|
||||
u32 MC_FSR_old[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
|
||||
|
||||
char * EPROC_old[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
|
||||
long NVPSIZ_old[16] = {
|
||||
0,
|
||||
0x2000, /* 8K */
|
||||
0x4000, /* 16K */
|
||||
0x8000, /* 32K */
|
||||
-1,
|
||||
0x10000, /* 64K */
|
||||
-1,
|
||||
0x20000, /* 128K */
|
||||
-1,
|
||||
0x40000, /* 256K */
|
||||
0x80000, /* 512K */
|
||||
-1,
|
||||
0x100000, /* 1024K */
|
||||
-1,
|
||||
0x200000, /* 2048K */
|
||||
-1
|
||||
};
|
||||
|
||||
long SRAMSIZ_old[16] = {
|
||||
-1,
|
||||
0x0400, /* 1K */
|
||||
0x0800, /* 2K */
|
||||
-1,
|
||||
0x1c000, /* 112K */
|
||||
0x1000, /* 4K */
|
||||
0x14000, /* 80K */
|
||||
0x28000, /* 160K */
|
||||
0x2000, /* 8K */
|
||||
0x4000, /* 16K */
|
||||
0x8000, /* 32K */
|
||||
0x10000, /* 64K */
|
||||
0x20000, /* 128K */
|
||||
0x40000, /* 256K */
|
||||
0x18000, /* 96K */
|
||||
0x80000, /* 512K */
|
||||
};
|
||||
|
||||
int at91sam7_old_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *at91sam7_old_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
|
||||
register_command(cmd_ctx, at91sam7_old_cmd, "gpnvm", at91sam7_old_handle_gpnvm_command, COMMAND_EXEC,
|
||||
"at91sam7 gpnvm <num> <bit> set|clear, set or clear at91sam7 gpnvm bit");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 at91sam7_old_get_flash_status(flash_bank_t *bank, u8 flashplane)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 fsr;
|
||||
|
||||
target_read_u32(target, MC_FSR_old[flashplane], &fsr);
|
||||
|
||||
return fsr;
|
||||
}
|
||||
|
||||
/* Read clock configuration and set at91sam7_old_info->usec_clocks*/
|
||||
void at91sam7_old_read_clock_info(flash_bank_t *bank)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 mckr, mcfr, pllr;
|
||||
unsigned long tmp = 0, mainfreq;
|
||||
int flashplane;
|
||||
|
||||
/* Read main clock freqency register */
|
||||
target_read_u32(target, CKGR_MCFR_old, &mcfr);
|
||||
/* Read master clock register */
|
||||
target_read_u32(target, PMC_MCKR_old, &mckr);
|
||||
/* Read Clock Generator PLL Register */
|
||||
target_read_u32(target, CKGR_PLLR_old, &pllr);
|
||||
|
||||
at91sam7_old_info->mck_valid = 0;
|
||||
switch (mckr & PMC_MCKR_CSS_old)
|
||||
{
|
||||
case 0: /* Slow Clock */
|
||||
at91sam7_old_info->mck_valid = 1;
|
||||
mainfreq = RC_FREQ_old / 16ul * (mcfr & 0xffff);
|
||||
tmp = mainfreq;
|
||||
break;
|
||||
case 1: /* Main Clock */
|
||||
if (mcfr & CKGR_MCFR_MAINRDY_old)
|
||||
{
|
||||
at91sam7_old_info->mck_valid = 1;
|
||||
mainfreq = RC_FREQ_old / 16ul * (mcfr & 0xffff);
|
||||
tmp = mainfreq;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* Reserved */
|
||||
break;
|
||||
case 3: /* PLL Clock */
|
||||
if (mcfr & CKGR_MCFR_MAINRDY_old)
|
||||
{
|
||||
target_read_u32(target, CKGR_PLLR_old, &pllr);
|
||||
if (!(pllr & CKGR_PLLR_DIV_old))
|
||||
break; /* 0 Hz */
|
||||
at91sam7_old_info->mck_valid = 1;
|
||||
mainfreq = RC_FREQ_old / 16ul * (mcfr & 0xffff);
|
||||
/* Integer arithmetic should have sufficient precision
|
||||
as long as PLL is properly configured. */
|
||||
tmp = mainfreq / (pllr & CKGR_PLLR_DIV_old) *
|
||||
(((pllr & CKGR_PLLR_MUL_old) >> 16) + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Prescaler adjust */
|
||||
if (((mckr & PMC_MCKR_PRES_old) >> 2) == 7)
|
||||
at91sam7_old_info->mck_valid = 0;
|
||||
else
|
||||
at91sam7_old_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES_old) >> 2);
|
||||
|
||||
/* Forget old flash timing */
|
||||
for (flashplane = 0; flashplane<at91sam7_old_info->num_planes; flashplane++)
|
||||
{
|
||||
at91sam7_old_set_flash_mode(bank, flashplane, FMR_TIMING_NONE_old);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup the timimg registers for nvbits or normal flash */
|
||||
void at91sam7_old_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode)
|
||||
{
|
||||
u32 fmr, fmcn = 0, fws = 0;
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
if (mode && (mode != at91sam7_old_info->flashmode[flashplane]))
|
||||
{
|
||||
/* Always round up (ceil) */
|
||||
if (mode==FMR_TIMING_NVBITS_old)
|
||||
{
|
||||
if (at91sam7_old_info->cidr_arch == 0x60)
|
||||
{
|
||||
/* AT91SAM7A3 uses master clocks in 100 ns */
|
||||
fmcn = (at91sam7_old_info->mck_freq/10000000ul)+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* master clocks in 1uS for ARCH 0x7 types */
|
||||
fmcn = (at91sam7_old_info->mck_freq/1000000ul)+1;
|
||||
}
|
||||
}
|
||||
else if (mode==FMR_TIMING_FLASH_old)
|
||||
/* main clocks in 1.5uS */
|
||||
fmcn = (at91sam7_old_info->mck_freq/666666ul)+1;
|
||||
|
||||
/* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
|
||||
if (at91sam7_old_info->mck_freq <= 33333ul)
|
||||
fmcn = 0;
|
||||
/* Only allow fws=0 if clock frequency is < 30 MHz. */
|
||||
if (at91sam7_old_info->mck_freq > 30000000ul)
|
||||
fws = 1;
|
||||
|
||||
LOG_DEBUG("fmcn[%i]: %i", flashplane, fmcn);
|
||||
fmr = fmcn << 16 | fws << 8;
|
||||
target_write_u32(target, MC_FMR_old[flashplane], fmr);
|
||||
}
|
||||
|
||||
at91sam7_old_info->flashmode[flashplane] = mode;
|
||||
}
|
||||
|
||||
u32 at91sam7_old_wait_status_busy(flash_bank_t *bank, u8 flashplane, u32 waitbits, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
while ((!((status = at91sam7_old_get_flash_status(bank,flashplane)) & waitbits)) && (timeout-- > 0))
|
||||
{
|
||||
LOG_DEBUG("status[%i]: 0x%x", flashplane, status);
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
LOG_DEBUG("status[%i]: 0x%x", flashplane, status);
|
||||
|
||||
if (status & 0x0C)
|
||||
{
|
||||
LOG_ERROR("status register: 0x%x", status);
|
||||
if (status & 0x4)
|
||||
LOG_ERROR("Lock Error Bit Detected, Operation Abort");
|
||||
if (status & 0x8)
|
||||
LOG_ERROR("Invalid command and/or bad keyword, Operation Abort");
|
||||
if (status & 0x10)
|
||||
LOG_ERROR("Security Bit Set, Operation Abort");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Send one command to the AT91SAM flash controller */
|
||||
int at91sam7_old_flash_command(struct flash_bank_s *bank, u8 flashplane, u8 cmd, u16 pagen)
|
||||
{
|
||||
u32 fcr;
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
fcr = (0x5A<<24) | ((pagen&0x3FF)<<8) | cmd;
|
||||
target_write_u32(target, MC_FCR_old[flashplane], fcr);
|
||||
LOG_DEBUG("Flash command: 0x%x, flashplane: %i, pagenumber:%u", fcr, flashplane, pagen);
|
||||
|
||||
if ((at91sam7_old_info->cidr_arch == 0x60)&&((cmd==SLB_old)|(cmd==CLB_old)))
|
||||
{
|
||||
/* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */
|
||||
if (at91sam7_old_wait_status_busy(bank, flashplane, MC_FSR_EOL_old, 10)&0x0C)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (at91sam7_old_wait_status_busy(bank, flashplane, MC_FSR_FRDY_old, 10)&0x0C)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||
int at91sam7_old_read_part_info(struct flash_bank_s *bank)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 cidr, status;
|
||||
int sectornum;
|
||||
|
||||
if (at91sam7_old_info->cidr != 0)
|
||||
return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
|
||||
|
||||
/* Read and parse chip identification register */
|
||||
target_read_u32(target, DBGU_CIDR_old, &cidr);
|
||||
|
||||
if (cidr == 0)
|
||||
{
|
||||
LOG_WARNING("Cannot identify target as an AT91SAM");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
at91sam7_old_info->cidr = cidr;
|
||||
at91sam7_old_info->cidr_ext = (cidr>>31)&0x0001;
|
||||
at91sam7_old_info->cidr_nvptyp = (cidr>>28)&0x0007;
|
||||
at91sam7_old_info->cidr_arch = (cidr>>20)&0x00FF;
|
||||
at91sam7_old_info->cidr_sramsiz = (cidr>>16)&0x000F;
|
||||
at91sam7_old_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
|
||||
at91sam7_old_info->cidr_nvpsiz = (cidr>>8)&0x000F;
|
||||
at91sam7_old_info->cidr_eproc = (cidr>>5)&0x0007;
|
||||
at91sam7_old_info->cidr_version = cidr&0x001F;
|
||||
bank->size = NVPSIZ_old[at91sam7_old_info->cidr_nvpsiz];
|
||||
at91sam7_old_info->target_name = "Unknown";
|
||||
|
||||
/* Support just for bulk erase of a single flash plane, whole device if flash size <= 256k */
|
||||
if (NVPSIZ_old[at91sam7_old_info->cidr_nvpsiz]<0x80000) /* Flash size less than 512K, one flash plane */
|
||||
{
|
||||
bank->num_sectors = 1;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t));
|
||||
bank->sectors[0].offset = 0;
|
||||
bank->sectors[0].size = bank->size;
|
||||
bank->sectors[0].is_erased = -1;
|
||||
bank->sectors[0].is_protected = -1;
|
||||
}
|
||||
else /* Flash size 512K or larger, several flash planes */
|
||||
{
|
||||
bank->num_sectors = NVPSIZ_old[at91sam7_old_info->cidr_nvpsiz]/0x40000;
|
||||
bank->sectors = malloc(bank->num_sectors*sizeof(flash_sector_t));
|
||||
for (sectornum=0; sectornum<bank->num_sectors; sectornum++)
|
||||
{
|
||||
bank->sectors[sectornum].offset = sectornum*0x40000;
|
||||
bank->sectors[sectornum].size = 0x40000;
|
||||
bank->sectors[sectornum].is_erased = -1;
|
||||
bank->sectors[sectornum].is_protected = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_old_info->cidr_nvptyp, at91sam7_old_info->cidr_arch );
|
||||
|
||||
/* Read main and master clock freqency register */
|
||||
at91sam7_old_read_clock_info(bank);
|
||||
|
||||
at91sam7_old_info->num_planes = 1;
|
||||
status = at91sam7_old_get_flash_status(bank, 0);
|
||||
at91sam7_old_info->securitybit = (status>>4)&0x01;
|
||||
at91sam7_old_protect_check(bank); /* TODO Check the protect check */
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0x70 )
|
||||
{
|
||||
at91sam7_old_info->num_nvmbits = 2;
|
||||
at91sam7_old_info->nvmbits = (status>>8)&0x03;
|
||||
bank->base = 0x100000;
|
||||
bank->bus_width = 4;
|
||||
if (bank->size==0x80000) /* AT91SAM7S512 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7S512";
|
||||
at91sam7_old_info->num_planes = 2;
|
||||
if (at91sam7_old_info->num_planes != bank->num_sectors)
|
||||
LOG_WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
|
||||
at91sam7_old_info->num_lockbits = 2*16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 2*16*64;
|
||||
}
|
||||
if (bank->size==0x40000) /* AT91SAM7S256 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7S256";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 16*64;
|
||||
}
|
||||
if (bank->size==0x20000) /* AT91SAM7S128 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7S128";
|
||||
at91sam7_old_info->num_lockbits = 8;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 8*64;
|
||||
}
|
||||
if (bank->size==0x10000) /* AT91SAM7S64 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7S64";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 128;
|
||||
at91sam7_old_info->pages_in_lockregion = 32;
|
||||
at91sam7_old_info->num_pages = 16*32;
|
||||
}
|
||||
if (bank->size==0x08000) /* AT91SAM7S321/32 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7S321/32";
|
||||
at91sam7_old_info->num_lockbits = 8;
|
||||
at91sam7_old_info->pagesize = 128;
|
||||
at91sam7_old_info->pages_in_lockregion = 32;
|
||||
at91sam7_old_info->num_pages = 8*32;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0x71 )
|
||||
{
|
||||
at91sam7_old_info->num_nvmbits = 3;
|
||||
at91sam7_old_info->nvmbits = (status>>8)&0x07;
|
||||
bank->base = 0x100000;
|
||||
bank->bus_width = 4;
|
||||
if (bank->size==0x80000) /* AT91SAM7XC512 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7XC512";
|
||||
at91sam7_old_info->num_planes = 2;
|
||||
if (at91sam7_old_info->num_planes != bank->num_sectors)
|
||||
LOG_WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
|
||||
at91sam7_old_info->num_lockbits = 2*16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 2*16*64;
|
||||
}
|
||||
if (bank->size==0x40000) /* AT91SAM7XC256 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7XC256";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 16*64;
|
||||
}
|
||||
if (bank->size==0x20000) /* AT91SAM7XC128 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7XC128";
|
||||
at91sam7_old_info->num_lockbits = 8;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 8*64;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0x72 )
|
||||
{
|
||||
at91sam7_old_info->num_nvmbits = 3;
|
||||
at91sam7_old_info->nvmbits = (status>>8)&0x07;
|
||||
bank->base = 0x100000;
|
||||
bank->bus_width = 4;
|
||||
if (bank->size==0x80000) /* AT91SAM7SE512 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7SE512";
|
||||
at91sam7_old_info->num_planes = 2;
|
||||
if (at91sam7_old_info->num_planes != bank->num_sectors)
|
||||
LOG_WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
|
||||
at91sam7_old_info->num_lockbits = 32;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 32*64;
|
||||
}
|
||||
if (bank->size==0x40000)
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7SE256";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 16*64;
|
||||
}
|
||||
if (bank->size==0x08000)
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7SE32";
|
||||
at91sam7_old_info->num_lockbits = 8;
|
||||
at91sam7_old_info->pagesize = 128;
|
||||
at91sam7_old_info->pages_in_lockregion = 32;
|
||||
at91sam7_old_info->num_pages = 8*32;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0x75 )
|
||||
{
|
||||
at91sam7_old_info->num_nvmbits = 3;
|
||||
at91sam7_old_info->nvmbits = (status>>8)&0x07;
|
||||
bank->base = 0x100000;
|
||||
bank->bus_width = 4;
|
||||
if (bank->size==0x80000) /* AT91SAM7X512 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7X512";
|
||||
at91sam7_old_info->num_planes = 2;
|
||||
if (at91sam7_old_info->num_planes != bank->num_sectors)
|
||||
LOG_WARNING("Internal error: Number of flash planes and erase sectors does not match, please report");;
|
||||
at91sam7_old_info->num_lockbits = 32;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 2*16*64;
|
||||
LOG_DEBUG("Support for AT91SAM7X512 is experimental in this version!");
|
||||
}
|
||||
if (bank->size==0x40000) /* AT91SAM7X256 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7X256";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 16*64;
|
||||
}
|
||||
if (bank->size==0x20000) /* AT91SAM7X128 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7X128";
|
||||
at91sam7_old_info->num_lockbits = 8;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 64;
|
||||
at91sam7_old_info->num_pages = 8*64;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0x60 )
|
||||
{
|
||||
at91sam7_old_info->num_nvmbits = 3;
|
||||
at91sam7_old_info->nvmbits = (status>>8)&0x07;
|
||||
bank->base = 0x100000;
|
||||
bank->bus_width = 4;
|
||||
|
||||
if (bank->size == 0x40000) /* AT91SAM7A3 */
|
||||
{
|
||||
at91sam7_old_info->target_name = "AT91SAM7A3";
|
||||
at91sam7_old_info->num_lockbits = 16;
|
||||
at91sam7_old_info->pagesize = 256;
|
||||
at91sam7_old_info->pages_in_lockregion = 16;
|
||||
at91sam7_old_info->num_pages = 16*64;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
LOG_WARNING("at91sam7_old flash only tested for AT91SAM7Sxx series");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_old_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
|
||||
if (!at91sam7_old_info->working_area_size)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_old_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
u32 status;
|
||||
int flashplane;
|
||||
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
for (flashplane=0;flashplane<at91sam7_old_info->num_planes;flashplane++)
|
||||
{
|
||||
status = at91sam7_old_get_flash_status(bank, flashplane);
|
||||
at91sam7_old_info->lockbits[flashplane] = (status >> 16);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank at91sam7_old 0 0 0 0 <target#>
|
||||
*/
|
||||
int at91sam7_old_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info;
|
||||
int i;
|
||||
|
||||
if (argc < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank at91sam7_old configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
at91sam7_old_info = malloc(sizeof(at91sam7_old_flash_bank_t));
|
||||
bank->driver_priv = at91sam7_old_info;
|
||||
|
||||
/* part wasn't probed for info yet */
|
||||
at91sam7_old_info->cidr = 0;
|
||||
for (i=0;i<4;i++)
|
||||
at91sam7_old_info->flashmode[i]=0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int at91sam7_old_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
u8 flashplane;
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
||||
{
|
||||
if ((first == 0) && (last == (at91sam7_old_info->num_lockbits-1)))
|
||||
{
|
||||
LOG_WARNING("Sector numbers based on lockbit count, probably a deprecated script");
|
||||
last = bank->num_sectors-1;
|
||||
}
|
||||
else return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_old_read_clock_info(bank);
|
||||
for (flashplane = first; flashplane<=last; flashplane++)
|
||||
{
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_old_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH_old);
|
||||
if (at91sam7_old_flash_command(bank, flashplane, EA_old, 0) != ERROR_OK)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
|
||||
}
|
||||
|
||||
int at91sam7_old_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
u32 cmd, pagen;
|
||||
u8 flashplane;
|
||||
int lockregion;
|
||||
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((first < 0) || (last < first) || (last >= at91sam7_old_info->num_lockbits))
|
||||
{
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
at91sam7_old_read_clock_info(bank);
|
||||
|
||||
for (lockregion=first;lockregion<=last;lockregion++)
|
||||
{
|
||||
pagen = lockregion*at91sam7_old_info->pages_in_lockregion;
|
||||
flashplane = (pagen>>10)&0x03;
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_old_set_flash_mode(bank, flashplane, FMR_TIMING_NVBITS_old);
|
||||
|
||||
if (set)
|
||||
cmd = SLB_old;
|
||||
else
|
||||
cmd = CLB_old;
|
||||
|
||||
if (at91sam7_old_flash_command(bank, flashplane, cmd, pagen) != ERROR_OK)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
at91sam7_old_protect_check(bank);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
int at91sam7_old_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
{
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 dst_min_alignment, wcount, bytes_remaining = count;
|
||||
u32 first_page, last_page, pagen, buffer_pos;
|
||||
u8 flashplane;
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
|
||||
dst_min_alignment = at91sam7_old_info->pagesize;
|
||||
|
||||
if (offset % dst_min_alignment)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr_arch == 0)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
first_page = offset/dst_min_alignment;
|
||||
last_page = CEIL(offset + count, dst_min_alignment);
|
||||
|
||||
LOG_DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
|
||||
|
||||
at91sam7_old_read_clock_info(bank);
|
||||
|
||||
for (pagen=first_page; pagen<last_page; pagen++)
|
||||
{
|
||||
if (bytes_remaining<dst_min_alignment)
|
||||
count = bytes_remaining;
|
||||
else
|
||||
count = dst_min_alignment;
|
||||
bytes_remaining -= count;
|
||||
|
||||
/* Write one block to the PageWriteBuffer */
|
||||
buffer_pos = (pagen-first_page)*dst_min_alignment;
|
||||
wcount = CEIL(count,4);
|
||||
target->type->write_memory(target, bank->base+pagen*dst_min_alignment, 4, wcount, buffer+buffer_pos);
|
||||
flashplane = (pagen>>10)&0x3;
|
||||
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_old_set_flash_mode(bank, flashplane, FMR_TIMING_FLASH_old);
|
||||
/* Send Write Page command to Flash Controller */
|
||||
if (at91sam7_old_flash_command(bank, flashplane, WP_old, pagen) != ERROR_OK)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
LOG_DEBUG("Write flash plane:%i page number:%i", flashplane, pagen);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
int at91sam7_old_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we can't probe on an at91sam7_old
|
||||
* if this is an at91sam7_old, it has the configured flash
|
||||
*/
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
int retval;
|
||||
|
||||
if (at91sam7_old_info->cidr != 0)
|
||||
{
|
||||
return ERROR_OK; /* already probed */
|
||||
}
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
retval = at91sam7_old_read_part_info(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
int at91sam7_old_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed, flashplane;
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info = bank->driver_priv;
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
printed = snprintf(buf, buf_size, "\nat91sam7_old information: Chip is %s\n",at91sam7_old_info->target_name);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x, flashsize: 0x%8.8x\n",
|
||||
at91sam7_old_info->cidr, at91sam7_old_info->cidr_arch, EPROC_old[at91sam7_old_info->cidr_eproc], at91sam7_old_info->cidr_version, bank->size);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz \n", at91sam7_old_info->mck_freq / 1000);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
if (at91sam7_old_info->num_planes>1) {
|
||||
printed = snprintf(buf, buf_size, "flashplanes: %i, pagesize: %i, lock regions: %i, pages in lock region: %i \n",
|
||||
at91sam7_old_info->num_planes, at91sam7_old_info->pagesize, at91sam7_old_info->num_lockbits, at91sam7_old_info->num_pages/at91sam7_old_info->num_lockbits);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
for (flashplane=0; flashplane<at91sam7_old_info->num_planes; flashplane++)
|
||||
{
|
||||
printed = snprintf(buf, buf_size, "lockbits[%i]: 0x%4.4x, ", flashplane, at91sam7_old_info->lockbits[flashplane]);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (at91sam7_old_info->num_lockbits>0) {
|
||||
printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n",
|
||||
at91sam7_old_info->pagesize, at91sam7_old_info->num_lockbits, at91sam7_old_info->lockbits[0], at91sam7_old_info->num_pages/at91sam7_old_info->num_lockbits);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
}
|
||||
|
||||
printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits(%i): 0x%1.1x\n", at91sam7_old_info->securitybit, at91sam7_old_info->num_nvmbits, at91sam7_old_info->nvmbits);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* On AT91SAM7S: When the gpnvm bits are set with
|
||||
* > at91sam7_old gpnvm 0 bitnr set
|
||||
* the changes are not visible in the flash controller status register MC_FSR_old
|
||||
* until the processor has been reset.
|
||||
* On the Olimex board this requires a power cycle.
|
||||
* Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3):
|
||||
* The maximum number of write/erase cycles for Non Volatile Memory bits is 100. This includes
|
||||
* Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
|
||||
*/
|
||||
int at91sam7_old_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int bit;
|
||||
u8 flashcmd;
|
||||
u32 status;
|
||||
char *value;
|
||||
at91sam7_old_flash_bank_t *at91sam7_old_info;
|
||||
int retval;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
command_print(cmd_ctx, "at91sam7_old gpnvm <num> <bit> <set|clear>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num_noprobe(strtoul(args[0], NULL, 0));
|
||||
bit = atoi(args[1]);
|
||||
value = args[2];
|
||||
|
||||
if (bank == NULL)
|
||||
{
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if (bank->driver != &at91sam7_old_flash)
|
||||
{
|
||||
command_print(cmd_ctx, "not an at91sam7_old flash bank '%s'", args[0]);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
if (strcmp(value, "set") == 0)
|
||||
{
|
||||
flashcmd = SGPB_old;
|
||||
}
|
||||
else if (strcmp(value, "clear") == 0)
|
||||
{
|
||||
flashcmd = CGPB_old;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
at91sam7_old_info = bank->driver_priv;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("target has to be halted to perform flash operation");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (at91sam7_old_info->cidr == 0)
|
||||
{
|
||||
retval = at91sam7_old_read_part_info(bank);
|
||||
if (retval != ERROR_OK) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if ((bit<0) || (at91sam7_old_info->num_nvmbits <= bit))
|
||||
{
|
||||
command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[1],at91sam7_old_info->target_name);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Configure the flash controller timing */
|
||||
at91sam7_old_read_clock_info(bank);
|
||||
at91sam7_old_set_flash_mode(bank, 0, FMR_TIMING_NVBITS_old);
|
||||
|
||||
if (at91sam7_old_flash_command(bank, 0, flashcmd, (u16)(bit)) != ERROR_OK)
|
||||
{
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
status = at91sam7_old_get_flash_status(bank, 0);
|
||||
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value 0x%x, status 0x%x \n",flashcmd,bit,status);
|
||||
at91sam7_old_info->nvmbits = (status>>8)&((1<<at91sam7_old_info->num_nvmbits)-1);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Magnus Lundin *
|
||||
* lundin@mlu.mine.nu *
|
||||
* *
|
||||
* 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_OLD_H
|
||||
#define AT91SAM7_OLD_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct at91sam7_old_flash_bank_s
|
||||
{
|
||||
u32 working_area;
|
||||
u32 working_area_size;
|
||||
|
||||
/* chip id register */
|
||||
u32 cidr;
|
||||
u16 cidr_ext;
|
||||
u16 cidr_nvptyp;
|
||||
u16 cidr_arch;
|
||||
u16 cidr_sramsiz;
|
||||
u16 cidr_nvpsiz;
|
||||
u16 cidr_nvpsiz2;
|
||||
u16 cidr_eproc;
|
||||
u16 cidr_version;
|
||||
char * target_name;
|
||||
|
||||
/* flash geometry */
|
||||
u16 num_pages;
|
||||
u16 pagesize;
|
||||
u16 pages_in_lockregion;
|
||||
u8 num_erase_regions;
|
||||
u8 num_planes;
|
||||
u32 *erase_region_info;
|
||||
|
||||
/* nv memory bits */
|
||||
u16 num_lockbits;
|
||||
u16 lockbits[4];
|
||||
u16 num_nvmbits;
|
||||
u16 nvmbits;
|
||||
u8 securitybit;
|
||||
u8 flashmode[4]; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */
|
||||
|
||||
/* main clock status */
|
||||
u8 mck_valid;
|
||||
u32 mck_freq;
|
||||
|
||||
} at91sam7_old_flash_bank_t;
|
||||
|
||||
/* AT91SAM7 control registers */
|
||||
#define DBGU_CIDR_old 0xFFFFF240
|
||||
#define CKGR_MCFR_old 0xFFFFFC24
|
||||
#define CKGR_MCFR_MAINRDY_old 0x10000
|
||||
#define CKGR_PLLR_old 0xFFFFFC2c
|
||||
#define CKGR_PLLR_DIV_old 0xff
|
||||
#define CKGR_PLLR_MUL_old 0x07ff0000
|
||||
#define PMC_MCKR_old 0xFFFFFC30
|
||||
#define PMC_MCKR_CSS_old 0x03
|
||||
#define PMC_MCKR_PRES_old 0x1c
|
||||
|
||||
/* Flash Controller Commands */
|
||||
#define WP_old 0x01
|
||||
#define SLB_old 0x02
|
||||
#define WPL_old 0x03
|
||||
#define CLB_old 0x04
|
||||
#define EA_old 0x08
|
||||
#define SGPB_old 0x0B
|
||||
#define CGPB_old 0x0D
|
||||
#define SSB_old 0x0F
|
||||
|
||||
/* MC_FSR bit definitions */
|
||||
#define MC_FSR_FRDY_old 1
|
||||
#define MC_FSR_EOL_old 2
|
||||
|
||||
/* AT91SAM7 constants */
|
||||
#define RC_FREQ_old 32000
|
||||
|
||||
/* FLASH_TIMING_MODES */
|
||||
#define FMR_TIMING_NONE_old 0
|
||||
#define FMR_TIMING_NVBITS_old 1
|
||||
#define FMR_TIMING_FLASH_old 2
|
||||
|
||||
#endif /* AT91SAM7_OLD_H */
|
||||
492
src/flash/avrf.c
Normal file
492
src/flash/avrf.c
Normal file
@@ -0,0 +1,492 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Simon Qian *
|
||||
* SimonQian@SimonQian.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 "avrf.h"
|
||||
#include "avrt.h"
|
||||
#include "flash.h"
|
||||
|
||||
|
||||
/* AVR_JTAG_Instructions */
|
||||
#define AVR_JTAG_INS_LEN 4
|
||||
// Public Instructions:
|
||||
#define AVR_JTAG_INS_EXTEST 0x00
|
||||
#define AVR_JTAG_INS_IDCODE 0x01
|
||||
#define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02
|
||||
#define AVR_JTAG_INS_BYPASS 0x0F
|
||||
// AVR Specified Public Instructions:
|
||||
#define AVR_JTAG_INS_AVR_RESET 0x0C
|
||||
#define AVR_JTAG_INS_PROG_ENABLE 0x04
|
||||
#define AVR_JTAG_INS_PROG_COMMANDS 0x05
|
||||
#define AVR_JTAG_INS_PROG_PAGELOAD 0x06
|
||||
#define AVR_JTAG_INS_PROG_PAGEREAD 0x07
|
||||
|
||||
// Data Registers:
|
||||
#define AVR_JTAG_REG_Bypass_Len 1
|
||||
#define AVR_JTAG_REG_DeviceID_Len 32
|
||||
|
||||
#define AVR_JTAG_REG_Reset_Len 1
|
||||
#define AVR_JTAG_REG_JTAGID_Len 32
|
||||
#define AVR_JTAG_REG_ProgrammingEnable_Len 16
|
||||
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
|
||||
#define AVR_JTAG_REG_FlashDataByte_Len 16
|
||||
|
||||
avrf_type_t avft_chips_info[] =
|
||||
{
|
||||
// name, chip_id, flash_page_size, flash_page_num, eeprom_page_size, eeprom_page_num
|
||||
{"atmega128", 0x9702, 256, 512, 8, 512},
|
||||
};
|
||||
|
||||
static int avrf_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int avrf_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int avrf_probe(struct flash_bank_s *bank);
|
||||
static int avrf_auto_probe(struct flash_bank_s *bank);
|
||||
//static int avrf_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int avrf_protect_check(struct flash_bank_s *bank);
|
||||
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
extern int avr_jtag_sendinstr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out);
|
||||
extern int avr_jtag_senddat(jtag_tap_t *tap, uint32_t *dr_in, uint32_t dr_out, int len);
|
||||
|
||||
extern int mcu_write_ir(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_write_ir_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
|
||||
extern int mcu_write_dr_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
|
||||
extern int mcu_execute_queue(void);
|
||||
|
||||
flash_driver_t avr_flash =
|
||||
{
|
||||
.name = "avr",
|
||||
.register_commands = avrf_register_commands,
|
||||
.flash_bank_command = avrf_flash_bank_command,
|
||||
.erase = avrf_erase,
|
||||
.protect = avrf_protect,
|
||||
.write = avrf_write,
|
||||
.probe = avrf_probe,
|
||||
.auto_probe = avrf_auto_probe,
|
||||
.erase_check = default_flash_mem_blank_check,
|
||||
.protect_check = avrf_protect_check,
|
||||
.info = avrf_info
|
||||
};
|
||||
|
||||
/* avr program functions */
|
||||
static int avr_jtag_reset(avr_common_t *avr, uint32_t reset)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, reset ,AVR_JTAG_REG_Reset_Len);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtag_read_jtagid(avr_common_t *avr, uint32_t *id)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_enterprogmode(avr_common_t *avr)
|
||||
{
|
||||
avr_jtag_reset(avr, 1);
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_ProgrammingEnable_Len);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_leaveprogmode(avr_common_t *avr)
|
||||
{
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_ProgrammingEnable_Len);
|
||||
|
||||
avr_jtag_reset(avr, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_chiperase(avr_common_t *avr)
|
||||
{
|
||||
uint32_t poll_value;
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
do {
|
||||
poll_value = 0;
|
||||
avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||
} while (!(poll_value & 0x0200));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avr_jtagprg_writeflashpage(avr_common_t *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
|
||||
{
|
||||
uint32_t i, poll_value;
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
// load addr high byte
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
// load addr low byte
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
|
||||
|
||||
for (i = 0; i < page_size; i++)
|
||||
{
|
||||
if (i < buf_size)
|
||||
{
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8);
|
||||
}
|
||||
}
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
do {
|
||||
poll_value = 0;
|
||||
avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value);
|
||||
} while (!(poll_value & 0x0200));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* interface command */
|
||||
static int avrf_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *avr_cmd = register_command(cmd_ctx, NULL, "avr", NULL, COMMAND_ANY, "avr flash specific commands");
|
||||
|
||||
register_command(cmd_ctx, avr_cmd, "mass_erase", avrf_handle_mass_erase_command, COMMAND_EXEC,
|
||||
"mass erase device");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
avrf_flash_bank_t *avrf_info;
|
||||
|
||||
if (argc < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank avr configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
avrf_info = malloc(sizeof(avrf_flash_bank_t));
|
||||
bank->driver_priv = avrf_info;
|
||||
|
||||
avrf_info->probed = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
uint32_t cur_size, cur_buffer_size, page_size;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
page_size = bank->sectors[0].size;
|
||||
if ((offset % page_size) != 0)
|
||||
{
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
LOG_DEBUG("offset is 0x%08" PRIx32 "", offset);
|
||||
LOG_DEBUG("count is %" PRId32 "", count);
|
||||
|
||||
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
cur_size = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
if (count > page_size)
|
||||
{
|
||||
cur_buffer_size = page_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_buffer_size = count;
|
||||
}
|
||||
avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size);
|
||||
count -= cur_buffer_size;
|
||||
cur_size += cur_buffer_size;
|
||||
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
return avr_jtagprg_leaveprogmode(avr);
|
||||
}
|
||||
|
||||
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
|
||||
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
|
||||
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
|
||||
static int avrf_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avrf_flash_bank_t *avrf_info = bank->driver_priv;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
avrf_type_t *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
avrf_info->probed = 0;
|
||||
|
||||
avr_jtag_read_jtagid(avr, &device_id);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||
{
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
avr_info = &avft_chips_info[i];
|
||||
LOG_INFO("target device is %s", avr_info->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (avr_info != NULL)
|
||||
{
|
||||
// chip found
|
||||
bank->base = 0x00000000;
|
||||
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
|
||||
bank->num_sectors = avr_info->flash_page_num;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * avr_info->flash_page_num);
|
||||
|
||||
for (i = 0; i < avr_info->flash_page_num; i++)
|
||||
{
|
||||
bank->sectors[i].offset = i * avr_info->flash_page_size;
|
||||
bank->sectors[i].size = avr_info->flash_page_size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
|
||||
avrf_info->probed = 1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// chip not supported
|
||||
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
|
||||
|
||||
avrf_info->probed = 1;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static int avrf_auto_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
avrf_flash_bank_t *avrf_info = bank->driver_priv;
|
||||
if (avrf_info->probed)
|
||||
return ERROR_OK;
|
||||
return avrf_probe(bank);
|
||||
}
|
||||
|
||||
static int avrf_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
LOG_INFO("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
avrf_type_t *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
avr_jtag_read_jtagid(avr, &device_id);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||
if (EXTRACT_MFG(device_id) != 0x1F)
|
||||
{
|
||||
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
|
||||
{
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
|
||||
{
|
||||
avr_info = &avft_chips_info[i];
|
||||
LOG_INFO("target device is %s", avr_info->name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (avr_info != NULL)
|
||||
{
|
||||
// chip found
|
||||
snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id));
|
||||
return ERROR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// chip not supported
|
||||
snprintf(buf, buf_size, "Cannot identify target as a avr\n");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static int avrf_mass_erase(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
avr_common_t *avr = target->arch_info;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||
|| (ERROR_OK != avr_jtagprg_chiperase(avr))
|
||||
|| (ERROR_OK != avr_jtagprg_leaveprogmode(avr)))
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "avr mass_erase <bank>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (avrf_mass_erase(bank) == ERROR_OK)
|
||||
{
|
||||
/* set all sectors as erased */
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "avr mass erase complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "avr mass erase failed");
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s", __FUNCTION__);
|
||||
return ERROR_OK;
|
||||
}
|
||||
41
src/flash/avrf.h
Normal file
41
src/flash/avrf.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Simon Qian *
|
||||
* SimonQian@SimonQian.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. *
|
||||
***************************************************************************/
|
||||
#ifndef AVRF_H
|
||||
#define AVRF_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct avrf_type_s
|
||||
{
|
||||
char name[15];
|
||||
uint16_t chip_id;
|
||||
int flash_page_size;
|
||||
int flash_page_num;
|
||||
int eeprom_page_size;
|
||||
int eeprom_page_num;
|
||||
} avrf_type_t;
|
||||
|
||||
typedef struct avrf_flash_bank_s
|
||||
{
|
||||
int ppage_size;
|
||||
int probed;
|
||||
} avrf_flash_bank_t;
|
||||
|
||||
#endif /* AVRF_H */
|
||||
778
src/flash/cfi.c
778
src/flash/cfi.c
File diff suppressed because it is too large
Load Diff
131
src/flash/cfi.h
131
src/flash/cfi.h
@@ -21,49 +21,52 @@
|
||||
#define CFI_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
|
||||
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
|
||||
|
||||
typedef struct cfi_flash_bank_s
|
||||
{
|
||||
working_area_t *write_algorithm;
|
||||
|
||||
|
||||
int x16_as_x8;
|
||||
int jedec_probe;
|
||||
int not_cfi;
|
||||
int probed;
|
||||
|
||||
u16 manufacturer;
|
||||
u16 device_id;
|
||||
uint16_t manufacturer;
|
||||
uint16_t device_id;
|
||||
|
||||
char qry[3];
|
||||
|
||||
/* identification string */
|
||||
u16 pri_id;
|
||||
u16 pri_addr;
|
||||
u16 alt_id;
|
||||
u16 alt_addr;
|
||||
uint16_t pri_id;
|
||||
uint16_t pri_addr;
|
||||
uint16_t alt_id;
|
||||
uint16_t alt_addr;
|
||||
|
||||
/* device-system interface */
|
||||
u8 vcc_min;
|
||||
u8 vcc_max;
|
||||
u8 vpp_min;
|
||||
u8 vpp_max;
|
||||
u8 word_write_timeout_typ;
|
||||
u8 buf_write_timeout_typ;
|
||||
u8 block_erase_timeout_typ;
|
||||
u8 chip_erase_timeout_typ;
|
||||
u8 word_write_timeout_max;
|
||||
u8 buf_write_timeout_max;
|
||||
u8 block_erase_timeout_max;
|
||||
u8 chip_erase_timeout_max;
|
||||
uint8_t vcc_min;
|
||||
uint8_t vcc_max;
|
||||
uint8_t vpp_min;
|
||||
uint8_t vpp_max;
|
||||
uint8_t word_write_timeout_typ;
|
||||
uint8_t buf_write_timeout_typ;
|
||||
uint8_t block_erase_timeout_typ;
|
||||
uint8_t chip_erase_timeout_typ;
|
||||
uint8_t word_write_timeout_max;
|
||||
uint8_t buf_write_timeout_max;
|
||||
uint8_t block_erase_timeout_max;
|
||||
uint8_t chip_erase_timeout_max;
|
||||
|
||||
uint8_t status_poll_mask;
|
||||
|
||||
/* flash geometry */
|
||||
u8 dev_size;
|
||||
u16 interface_desc;
|
||||
u16 max_buf_write_size;
|
||||
u8 num_erase_regions;
|
||||
u32 *erase_region_info;
|
||||
uint32_t dev_size;
|
||||
uint16_t interface_desc;
|
||||
uint16_t max_buf_write_size;
|
||||
uint8_t num_erase_regions;
|
||||
uint32_t *erase_region_info;
|
||||
|
||||
void *pri_ext;
|
||||
void *alt_ext;
|
||||
@@ -76,18 +79,18 @@ typedef struct cfi_flash_bank_s
|
||||
typedef struct cfi_intel_pri_ext_s
|
||||
{
|
||||
char pri[3];
|
||||
u8 major_version;
|
||||
u8 minor_version;
|
||||
u32 feature_support;
|
||||
u8 suspend_cmd_support;
|
||||
u16 blk_status_reg_mask;
|
||||
u8 vcc_optimal;
|
||||
u8 vpp_optimal;
|
||||
u8 num_protection_fields;
|
||||
u16 prot_reg_addr;
|
||||
u8 fact_prot_reg_size;
|
||||
u8 user_prot_reg_size;
|
||||
u8 extra[0];
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint32_t feature_support;
|
||||
uint8_t suspend_cmd_support;
|
||||
uint16_t blk_status_reg_mask;
|
||||
uint8_t vcc_optimal;
|
||||
uint8_t vpp_optimal;
|
||||
uint8_t num_protection_fields;
|
||||
uint16_t prot_reg_addr;
|
||||
uint8_t fact_prot_reg_size;
|
||||
uint8_t user_prot_reg_size;
|
||||
uint8_t extra[0];
|
||||
} cfi_intel_pri_ext_t;
|
||||
|
||||
/* Spansion primary extended query table as defined for and used by
|
||||
@@ -95,23 +98,23 @@ typedef struct cfi_intel_pri_ext_s
|
||||
*/
|
||||
typedef struct cfi_spansion_pri_ext_s
|
||||
{
|
||||
u8 pri[3];
|
||||
u8 major_version;
|
||||
u8 minor_version;
|
||||
u8 SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
|
||||
u8 EraseSuspend;
|
||||
u8 BlkProt;
|
||||
u8 TmpBlkUnprotect;
|
||||
u8 BlkProtUnprot;
|
||||
u8 SimultaneousOps;
|
||||
u8 BurstMode;
|
||||
u8 PageMode;
|
||||
u8 VppMin;
|
||||
u8 VppMax;
|
||||
u8 TopBottom;
|
||||
uint8_t pri[3];
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
|
||||
uint8_t EraseSuspend;
|
||||
uint8_t BlkProt;
|
||||
uint8_t TmpBlkUnprotect;
|
||||
uint8_t BlkProtUnprot;
|
||||
uint8_t SimultaneousOps;
|
||||
uint8_t BurstMode;
|
||||
uint8_t PageMode;
|
||||
uint8_t VppMin;
|
||||
uint8_t VppMax;
|
||||
uint8_t TopBottom;
|
||||
int _reversed_geometry;
|
||||
u32 _unlock1;
|
||||
u32 _unlock2;
|
||||
uint32_t _unlock1;
|
||||
uint32_t _unlock2;
|
||||
} cfi_spansion_pri_ext_t;
|
||||
|
||||
/* Atmel primary extended query table as defined for and used by
|
||||
@@ -119,13 +122,13 @@ typedef struct cfi_spansion_pri_ext_s
|
||||
*/
|
||||
typedef struct cfi_atmel_pri_ext_s
|
||||
{
|
||||
u8 pri[3];
|
||||
u8 major_version;
|
||||
u8 minor_version;
|
||||
u8 features;
|
||||
u8 bottom_boot;
|
||||
u8 burst_mode;
|
||||
u8 page_mode;
|
||||
uint8_t pri[3];
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint8_t features;
|
||||
uint8_t bottom_boot;
|
||||
uint8_t burst_mode;
|
||||
uint8_t page_mode;
|
||||
} cfi_atmel_pri_ext_t;
|
||||
|
||||
enum {
|
||||
@@ -135,14 +138,14 @@ enum {
|
||||
|
||||
typedef struct cfi_unlock_addresses_s
|
||||
{
|
||||
u32 unlock1;
|
||||
u32 unlock2;
|
||||
uint32_t unlock1;
|
||||
uint32_t unlock2;
|
||||
} cfi_unlock_addresses_t;
|
||||
|
||||
typedef struct cfi_fixup_s
|
||||
{
|
||||
u16 mfr;
|
||||
u16 id;
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
void (*fixup)(flash_bank_t *flash, void *param);
|
||||
void *param;
|
||||
} cfi_fixup_t;
|
||||
|
||||
765
src/flash/davinci_nand.c
Normal file
765
src/flash/davinci_nand.c
Normal file
@@ -0,0 +1,765 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by David Brownell *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* DaVinci family NAND controller support for OpenOCD.
|
||||
*
|
||||
* This driver uses hardware ECC (1-bit or 4-bit) unless
|
||||
* the chip is accessed in "raw" mode.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arm_nandio.h"
|
||||
|
||||
|
||||
enum ecc {
|
||||
HWECC1, /* all controllers support 1-bit ECC */
|
||||
HWECC4, /* newer chips also have 4-bit ECC hardware */
|
||||
HWECC4_INFIX, /* avoid this layout, except maybe for boot code */
|
||||
};
|
||||
|
||||
struct davinci_nand {
|
||||
target_t *target;
|
||||
|
||||
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
|
||||
uint8_t eccmode;
|
||||
|
||||
/* Async EMIF controller base */
|
||||
uint32_t aemif;
|
||||
|
||||
/* NAND chip addresses */
|
||||
uint32_t data; /* without CLE or ALE */
|
||||
uint32_t cmd; /* with CLE */
|
||||
uint32_t addr; /* with ALE */
|
||||
|
||||
/* write acceleration */
|
||||
struct arm_nand_data io;
|
||||
|
||||
/* page i/o for the relevant flavor of hardware ECC */
|
||||
int (*read_page)(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int (*write_page)(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
};
|
||||
|
||||
#define NANDFCR 0x60 /* flash control register */
|
||||
#define NANDFSR 0x64 /* flash status register */
|
||||
#define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */
|
||||
#define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */
|
||||
#define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */
|
||||
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */
|
||||
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */
|
||||
|
||||
static int halted(target_t *target, const char *label)
|
||||
{
|
||||
if (target->state == TARGET_HALTED)
|
||||
return true;
|
||||
|
||||
LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int davinci_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_init(struct nand_device_s *nand)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
uint32_t nandfcr;
|
||||
|
||||
if (!halted(target, "init"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
/* We require something else to have configured AEMIF to talk
|
||||
* to NAND chip in this range (including timings and width).
|
||||
*/
|
||||
target_read_u32(target, info->aemif + NANDFCR, &nandfcr);
|
||||
if (!(nandfcr & (1 << info->chipsel))) {
|
||||
LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* REVISIT verify: AxCR must be in 8-bit mode, since that's all we
|
||||
* tested. 16 bit support should work too; but not with 4-bit ECC.
|
||||
*/
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_reset(struct nand_device_s *nand)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
uint32_t nandfsr;
|
||||
|
||||
/* NOTE: return code is zero/error, else success; not ERROR_* */
|
||||
|
||||
if (!halted(target, "ready"))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
target_read_u32(target, info->aemif + NANDFSR, &nandfsr);
|
||||
|
||||
if (nandfsr & 0x01)
|
||||
return 1;
|
||||
|
||||
alive_sleep(1);
|
||||
} while (timeout-- > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_command(struct nand_device_s *nand, uint8_t command)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
|
||||
if (!halted(target, "command"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
target_write_u8(target, info->cmd, command);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_address(struct nand_device_s *nand, uint8_t address)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
|
||||
if (!halted(target, "address"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
target_write_u8(target, info->addr, address);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
|
||||
if (!halted(target, "write_data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
target_write_u8(target, info->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_read_data(struct nand_device_s *nand, void *data)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
|
||||
if (!halted(target, "read_data"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
target_read_u8(target, info->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* REVISIT a bit of native code should let block reads be MUCH faster */
|
||||
|
||||
static int davinci_read_block_data(struct nand_device_s *nand,
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
uint32_t nfdata = info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
if (!halted(target, "read_block"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
while (data_size >= 4) {
|
||||
target_read_u32(target, nfdata, &tmp);
|
||||
|
||||
data[0] = tmp;
|
||||
data[1] = tmp >> 8;
|
||||
data[2] = tmp >> 16;
|
||||
data[3] = tmp >> 24;
|
||||
|
||||
data_size -= 4;
|
||||
data += 4;
|
||||
}
|
||||
|
||||
while (data_size > 0) {
|
||||
target_read_u8(target, nfdata, data);
|
||||
|
||||
data_size -= 1;
|
||||
data += 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_block_data(struct nand_device_s *nand,
|
||||
uint8_t *data, int data_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
uint32_t nfdata = info->data;
|
||||
uint32_t tmp;
|
||||
int status;
|
||||
|
||||
if (!halted(target, "write_block"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
/* try the fast way first */
|
||||
status = arm_nandwrite(&info->io, data, data_size);
|
||||
if (status != ERROR_NAND_NO_BUFFER)
|
||||
return status;
|
||||
|
||||
/* else do it slowly */
|
||||
while (data_size >= 4) {
|
||||
tmp = le_to_h_u32(data);
|
||||
target_write_u32(target, nfdata, tmp);
|
||||
|
||||
data_size -= 4;
|
||||
data += 4;
|
||||
}
|
||||
|
||||
while (data_size > 0) {
|
||||
target_write_u8(target, nfdata, *data);
|
||||
|
||||
data_size -= 1;
|
||||
data += 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
uint8_t *ooballoc = NULL;
|
||||
int status;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
if (!halted(info->target, "write_page"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
/* Always write both data and OOB ... we are not "raw" I/O! */
|
||||
if (!data) {
|
||||
LOG_ERROR("Missing NAND data; try 'nand raw_access enable'\n");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* If we're not given OOB, write 0xff where we don't write ECC codes. */
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
oob_size = 16;
|
||||
break;
|
||||
case 2048:
|
||||
oob_size = 64;
|
||||
break;
|
||||
case 4096:
|
||||
oob_size = 128;
|
||||
break;
|
||||
default:
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
if (!oob) {
|
||||
ooballoc = malloc(oob_size);
|
||||
if (!ooballoc)
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
oob = ooballoc;
|
||||
memset(oob, 0x0ff, oob_size);
|
||||
}
|
||||
|
||||
/* REVISIT avoid wasting SRAM: unless nand->use_raw is set,
|
||||
* use 512 byte chunks. Read side support will often want
|
||||
* to include oob_size ...
|
||||
*/
|
||||
info->io.chunk_size = nand->page_size;
|
||||
|
||||
status = info->write_page(nand, page, data, data_size, oob, oob_size);
|
||||
free(ooballoc);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int davinci_read_page(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
|
||||
if (!nand->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
if (!halted(info->target, "read_page"))
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
|
||||
return info->read_page(nand, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
int page3 = nand->address_cycles - (nand->page_size == 512);
|
||||
|
||||
/* write command ({page,otp}x{read,program} */
|
||||
target_write_u8(target, info->cmd, cmd);
|
||||
|
||||
/* column address (beginning-of-page) */
|
||||
target_write_u8(target, info->addr, 0);
|
||||
if (nand->page_size > 512)
|
||||
target_write_u8(target, info->addr, 0);
|
||||
|
||||
/* page address */
|
||||
target_write_u8(target, info->addr, page);
|
||||
target_write_u8(target, info->addr, page >> 8);
|
||||
if (page3)
|
||||
target_write_u8(target, info->addr, page >> 16);
|
||||
if (page3 == 2)
|
||||
target_write_u8(target, info->addr, page >> 24);
|
||||
}
|
||||
|
||||
static int davinci_writepage_tail(struct nand_device_s *nand,
|
||||
uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
uint8_t status;
|
||||
|
||||
if (oob_size)
|
||||
davinci_write_block_data(nand, oob, oob_size);
|
||||
|
||||
/* non-cachemode page program */
|
||||
target_write_u8(target, info->cmd, NAND_CMD_PAGEPROG);
|
||||
|
||||
if (!davinci_nand_ready(nand, 100))
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
|
||||
if (nand_read_status(nand, &status) != ERROR_OK) {
|
||||
LOG_ERROR("couldn't read status");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (status & NAND_STATUS_FAIL) {
|
||||
LOG_ERROR("write operation failed, status: 0x%02x", status);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
|
||||
*/
|
||||
static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
unsigned oob_offset;
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
|
||||
uint32_t fcr, ecc1;
|
||||
|
||||
/* Write contiguous ECC bytes starting at specified offset.
|
||||
* NOTE: Linux reserves twice as many bytes as we need; and
|
||||
* for 16-bit OOB, those extra bytes are discontiguous.
|
||||
*/
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
oob_offset = 0;
|
||||
break;
|
||||
case 2048:
|
||||
oob_offset = 40;
|
||||
break;
|
||||
default:
|
||||
oob_offset = 80;
|
||||
break;
|
||||
}
|
||||
|
||||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
|
||||
|
||||
/* scrub any old ECC state */
|
||||
target_read_u32(target, ecc1_addr, &ecc1);
|
||||
|
||||
target_read_u32(target, fcr_addr, &fcr);
|
||||
fcr |= 1 << (8 + info->chipsel);
|
||||
|
||||
do {
|
||||
/* set "start csX 1bit ecc" bit */
|
||||
target_write_u32(target, fcr_addr, fcr);
|
||||
|
||||
/* write 512 bytes */
|
||||
davinci_write_block_data(nand, data, 512);
|
||||
data += 512;
|
||||
data_size -= 512;
|
||||
|
||||
/* read the ecc, pack to 3 bytes, and invert so the ecc
|
||||
* in an erased block is correct
|
||||
*/
|
||||
target_read_u32(target, ecc1_addr, &ecc1);
|
||||
ecc1 = (ecc1 & 0x0fff) | ((ecc1 & 0x0fff0000) >> 4);
|
||||
ecc1 = ~ecc1;
|
||||
|
||||
/* save correct ECC code into oob data */
|
||||
oob[oob_offset++] = (uint8_t)(ecc1);
|
||||
oob[oob_offset++] = (uint8_t)(ecc1 >> 8);
|
||||
oob[oob_offset++] = (uint8_t)(ecc1 >> 16);
|
||||
|
||||
} while (data_size);
|
||||
|
||||
/* write OOB into spare area */
|
||||
return davinci_writepage_tail(nand, oob, oob_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Preferred "new style" ECC layout for use with 4-bit ECC. This somewhat
|
||||
* slows down large page reads done with error correction (since the OOB
|
||||
* is read first, so its ECC data can be used incrementally), but the
|
||||
* manufacturer bad block markers are safe. Contrast: old "infix" style.
|
||||
*/
|
||||
static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
static const uint8_t ecc512[] = {
|
||||
0, 1, 2, 3, 4, /* 5== mfr badblock */
|
||||
6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15,
|
||||
};
|
||||
static const uint8_t ecc2048[] = {
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
};
|
||||
static const uint8_t ecc4096[] = {
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
|
||||
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
|
||||
78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
|
||||
108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
|
||||
118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
};
|
||||
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
const uint8_t *l;
|
||||
target_t *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||
uint32_t fcr, ecc4;
|
||||
|
||||
/* Use the same ECC layout Linux uses. For small page chips
|
||||
* it's a bit cramped.
|
||||
*
|
||||
* NOTE: at this writing, 4KB pages have issues in Linux
|
||||
* because they need more than 64 bytes of ECC data, which
|
||||
* the standard ECC logic can't handle.
|
||||
*/
|
||||
switch (nand->page_size) {
|
||||
case 512:
|
||||
l = ecc512;
|
||||
break;
|
||||
case 2048:
|
||||
l = ecc2048;
|
||||
break;
|
||||
default:
|
||||
l = ecc4096;
|
||||
break;
|
||||
}
|
||||
|
||||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
|
||||
|
||||
/* scrub any old ECC state */
|
||||
target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
|
||||
|
||||
target_read_u32(target, fcr_addr, &fcr);
|
||||
fcr &= ~(0x03 << 4);
|
||||
fcr |= (1 << 12) | (info->chipsel << 4);
|
||||
|
||||
do {
|
||||
uint32_t raw_ecc[4], *p;
|
||||
int i;
|
||||
|
||||
/* start 4bit ecc on csX */
|
||||
target_write_u32(target, fcr_addr, fcr);
|
||||
|
||||
/* write 512 bytes */
|
||||
davinci_write_block_data(nand, data, 512);
|
||||
data += 512;
|
||||
data_size -= 512;
|
||||
|
||||
/* read the ecc, then save it into 10 bytes in the oob */
|
||||
for (i = 0; i < 4; i++) {
|
||||
target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
|
||||
raw_ecc[i] &= 0x03ff03ff;
|
||||
}
|
||||
for (i = 0, p = raw_ecc; i < 2; i++, p += 2) {
|
||||
oob[*l++] = p[0] & 0xff;
|
||||
oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
|
||||
oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
|
||||
oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
|
||||
oob[*l++] = (p[1] >> 18) & 0xff;
|
||||
}
|
||||
|
||||
} while (data_size);
|
||||
|
||||
/* write OOB into spare area */
|
||||
return davinci_writepage_tail(nand, oob, oob_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* "Infix" OOB ... like Linux ECC_HW_SYNDROME. Avoided because it trashes
|
||||
* manufacturer bad block markers, except on small page chips. Once you
|
||||
* write to a page using this scheme, you need specialized code to update
|
||||
* it (code which ignores now-invalid bad block markers).
|
||||
*
|
||||
* This is needed *only* to support older firmware. Older ROM Boot Loaders
|
||||
* need it to read their second stage loader (UBL) into SRAM, but from then
|
||||
* on the whole system can use the cleaner non-infix layouts. Systems with
|
||||
* older second stage loaders (ABL/U-Boot, etc) or other system software
|
||||
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
|
||||
*/
|
||||
static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
struct davinci_nand *info = nand->controller_priv;
|
||||
target_t *target = info->target;
|
||||
const uint32_t fcr_addr = info->aemif + NANDFCR;
|
||||
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
|
||||
uint32_t fcr, ecc4;
|
||||
|
||||
davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page);
|
||||
|
||||
/* scrub any old ECC state */
|
||||
target_read_u32(target, info->aemif + NANDERRVAL, &ecc4);
|
||||
|
||||
target_read_u32(target, fcr_addr, &fcr);
|
||||
fcr &= ~(0x03 << 4);
|
||||
fcr |= (1 << 12) | (info->chipsel << 4);
|
||||
|
||||
do {
|
||||
uint32_t raw_ecc[4], *p;
|
||||
uint8_t *l;
|
||||
int i;
|
||||
|
||||
/* start 4bit ecc on csX */
|
||||
target_write_u32(target, fcr_addr, fcr);
|
||||
|
||||
/* write 512 bytes */
|
||||
davinci_write_block_data(nand, data, 512);
|
||||
data += 512;
|
||||
data_size -= 512;
|
||||
|
||||
/* read the ecc */
|
||||
for (i = 0; i < 4; i++) {
|
||||
target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]);
|
||||
raw_ecc[i] &= 0x03ff03ff;
|
||||
}
|
||||
|
||||
/* skip 6 bytes of prepad, then pack 10 packed ecc bytes */
|
||||
for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) {
|
||||
*l++ = p[0] & 0xff;
|
||||
*l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc);
|
||||
*l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0);
|
||||
*l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0);
|
||||
*l++ = (p[1] >> 18) & 0xff;
|
||||
}
|
||||
|
||||
/* write this "out-of-band" data -- infix */
|
||||
davinci_write_block_data(nand, oob, 16);
|
||||
oob += 16;
|
||||
oob_size -= 16;
|
||||
|
||||
} while (data_size);
|
||||
|
||||
/* the last data and OOB writes included the spare area */
|
||||
return davinci_writepage_tail(nand, NULL, 0);
|
||||
}
|
||||
|
||||
static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
|
||||
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
|
||||
|
||||
/* large page devices need a start command */
|
||||
if (nand->page_size > 512)
|
||||
davinci_command(nand, NAND_CMD_READSTART);
|
||||
|
||||
if (!davinci_nand_ready(nand, 100))
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
|
||||
/* NOTE: not bothering to compute and use ECC data for now */
|
||||
|
||||
do {
|
||||
/* write 512 bytes */
|
||||
davinci_read_block_data(nand, data, 512);
|
||||
data += 512;
|
||||
data_size -= 512;
|
||||
|
||||
/* read this "out-of-band" data -- infix */
|
||||
davinci_read_block_data(nand, oob, 16);
|
||||
oob += 16;
|
||||
oob_size -= 16;
|
||||
} while (data_size);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **argv, int argc,
|
||||
struct nand_device_s *nand)
|
||||
{
|
||||
struct davinci_nand *info;
|
||||
target_t *target;
|
||||
unsigned long chip, aemif;
|
||||
enum ecc eccmode;
|
||||
int chipsel;
|
||||
char *ep;
|
||||
|
||||
/* arguments:
|
||||
* - "davinci"
|
||||
* - target
|
||||
* - nand chip address
|
||||
* - ecc mode
|
||||
* - aemif address
|
||||
* Plus someday, optionally, ALE and CLE masks.
|
||||
*/
|
||||
if (argc < 5) {
|
||||
LOG_ERROR("parameters: %s target "
|
||||
"chip_addr hwecc_mode aemif_addr",
|
||||
argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
target = get_target(argv[1]);
|
||||
if (!target) {
|
||||
LOG_ERROR("invalid target %s", argv[1]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chip = strtoul(argv[2], &ep, 0);
|
||||
if (*ep || chip == 0 || chip == ULONG_MAX) {
|
||||
LOG_ERROR("Invalid NAND chip address %s", argv[2]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (strcmp(argv[3], "hwecc1") == 0)
|
||||
eccmode = HWECC1;
|
||||
else if (strcmp(argv[3], "hwecc4") == 0)
|
||||
eccmode = HWECC4;
|
||||
else if (strcmp(argv[3], "hwecc4_infix") == 0)
|
||||
eccmode = HWECC4_INFIX;
|
||||
else {
|
||||
LOG_ERROR("Invalid ecc mode %s", argv[3]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
aemif = strtoul(argv[4], &ep, 0);
|
||||
if (*ep || aemif == 0 || aemif == ULONG_MAX) {
|
||||
LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* REVISIT what we'd *like* to do is look up valid ranges using
|
||||
* target-specific declarations, and not even need to pass the
|
||||
* AEMIF controller address.
|
||||
*/
|
||||
if (aemif == 0x01e00000 /* dm6446, dm357 */
|
||||
|| aemif == 0x01e10000 /* dm335, dm355 */
|
||||
|| aemif == 0x01d10000 /* dm365 */
|
||||
) {
|
||||
if (chip < 0x02000000 || chip >= 0x0a000000) {
|
||||
LOG_ERROR("NAND address %08lx out of range?", chip);
|
||||
goto fail;
|
||||
}
|
||||
chipsel = (chip - 0x02000000) >> 25;
|
||||
} else {
|
||||
LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
info = calloc(1, sizeof *info);
|
||||
if (info == NULL)
|
||||
goto fail;
|
||||
|
||||
info->target = target;
|
||||
info->eccmode = eccmode;
|
||||
info->chipsel = chipsel;
|
||||
info->aemif = aemif;
|
||||
info->data = chip;
|
||||
info->cmd = chip | 0x10;
|
||||
info->addr = chip | 0x08;
|
||||
|
||||
nand->controller_priv = info;
|
||||
|
||||
info->io.target = target;
|
||||
info->io.data = info->data;
|
||||
|
||||
/* NOTE: for now we don't do any error correction on read.
|
||||
* Nothing else in OpenOCD currently corrects read errors,
|
||||
* and in any case it's *writing* that we care most about.
|
||||
*/
|
||||
info->read_page = nand_read_page_raw;
|
||||
|
||||
switch (eccmode) {
|
||||
case HWECC1:
|
||||
/* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc1;
|
||||
break;
|
||||
case HWECC4:
|
||||
/* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */
|
||||
info->write_page = davinci_write_page_ecc4;
|
||||
break;
|
||||
case HWECC4_INFIX:
|
||||
/* Same 4-bit ECC HW, with problematic page/ecc layout */
|
||||
info->read_page = davinci_read_page_ecc4infix;
|
||||
info->write_page = davinci_write_page_ecc4infix;
|
||||
break;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
fail:
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
nand_flash_controller_t davinci_nand_controller = {
|
||||
.name = "davinci",
|
||||
.nand_device_command = davinci_nand_device_command,
|
||||
.register_commands = davinci_register_commands,
|
||||
.init = davinci_init,
|
||||
.reset = davinci_reset,
|
||||
.command = davinci_command,
|
||||
.address = davinci_address,
|
||||
.write_data = davinci_write_data,
|
||||
.read_data = davinci_read_data,
|
||||
.write_page = davinci_write_page,
|
||||
.read_page = davinci_read_page,
|
||||
.write_block_data = davinci_write_block_data,
|
||||
.read_block_data = davinci_read_block_data,
|
||||
.nand_ready = davinci_nand_ready,
|
||||
};
|
||||
208
src/flash/ecos.c
208
src/flash/ecos.c
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
@@ -21,34 +21,26 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "embeddedice.h"
|
||||
#include "image.h"
|
||||
|
||||
#include "target.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "../target/embeddedice.h"
|
||||
#include "types.h"
|
||||
static int ecosflash_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int ecosflash_probe(struct flash_bank_s *bank);
|
||||
static int ecosflash_protect_check(struct flash_bank_s *bank);
|
||||
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
int ecosflash_register_commands(struct command_context_s *cmd_ctx);
|
||||
int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int ecosflash_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int ecosflash_probe(struct flash_bank_s *bank);
|
||||
int ecosflash_protect_check(struct flash_bank_s *bank);
|
||||
int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
u32 ecosflash_get_flash_status(flash_bank_t *bank);
|
||||
void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);
|
||||
u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);
|
||||
int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
#if 0
|
||||
static uint32_t ecosflash_get_flash_status(flash_bank_t *bank);
|
||||
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);
|
||||
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
|
||||
static int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
#endif
|
||||
|
||||
flash_driver_t ecosflash_flash =
|
||||
{
|
||||
@@ -71,10 +63,10 @@ typedef struct ecosflash_flash_bank_s
|
||||
working_area_t *write_algorithm;
|
||||
working_area_t *erase_check_algorithm;
|
||||
char *driverPath;
|
||||
u32 start_address;
|
||||
uint32_t start_address;
|
||||
} ecosflash_flash_bank_t;
|
||||
|
||||
static const int sectorSize=0x10000;
|
||||
static const int sectorSize = 0x10000;
|
||||
|
||||
char *
|
||||
flash_errmsg(int err);
|
||||
@@ -136,7 +128,7 @@ flash_errmsg(int err)
|
||||
|
||||
/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
|
||||
*/
|
||||
int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
ecosflash_flash_bank_t *info;
|
||||
|
||||
@@ -147,21 +139,21 @@ int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, c
|
||||
}
|
||||
|
||||
info = malloc(sizeof(ecosflash_flash_bank_t));
|
||||
if(info == NULL)
|
||||
if (info == NULL)
|
||||
{
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
exit(-1);
|
||||
}
|
||||
bank->driver_priv = info;
|
||||
info->driverPath=strdup(args[6]);
|
||||
info->driverPath = strdup(args[6]);
|
||||
|
||||
/* eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as
|
||||
* a way to improve impeadance matach between OpenOCD and eCos flash
|
||||
* a way to improve impedance match between OpenOCD and eCos flash
|
||||
* driver.
|
||||
*/
|
||||
int i = 0;
|
||||
u32 offset = 0;
|
||||
bank->num_sectors=bank->size/sectorSize;
|
||||
uint32_t offset = 0;
|
||||
bank->num_sectors = bank->size/sectorSize;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
@@ -172,32 +164,32 @@ int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, c
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
info->target = get_target_by_num(strtoul(args[5], NULL, 0));
|
||||
info->target = get_target(args[5]);
|
||||
if (info->target == NULL)
|
||||
{
|
||||
LOG_ERROR("no target '%i' configured", (int)strtoul(args[5], NULL, 0));
|
||||
LOG_ERROR("target '%s' not defined", args[5]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int loadDriver(ecosflash_flash_bank_t *info)
|
||||
static int loadDriver(ecosflash_flash_bank_t *info)
|
||||
{
|
||||
u32 buf_cnt;
|
||||
u32 image_size;
|
||||
uint32_t buf_cnt;
|
||||
uint32_t image_size;
|
||||
image_t image;
|
||||
|
||||
image.base_address_set = 0;
|
||||
image.start_address_set = 0;
|
||||
target_t *target=info->target;
|
||||
target_t *target = info->target;
|
||||
int retval;
|
||||
|
||||
if ((retval=image_open(&image, info->driverPath, NULL)) != ERROR_OK)
|
||||
if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
info->start_address=image.start_address;
|
||||
info->start_address = image.start_address;
|
||||
|
||||
image_size = 0x0;
|
||||
int i;
|
||||
@@ -213,7 +205,7 @@ int loadDriver(ecosflash_flash_bank_t *info)
|
||||
}
|
||||
target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
|
||||
image_size += buf_cnt;
|
||||
LOG_DEBUG("%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address);
|
||||
LOG_DEBUG("%" PRIu32 " byte written at address 0x%8.8" PRIx32 "", buf_cnt, image.sections[i].base_address);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
@@ -223,20 +215,20 @@ int loadDriver(ecosflash_flash_bank_t *info)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int const OFFSET_ERASE=0x0;
|
||||
static int const OFFSET_ERASE_SIZE=0x8;
|
||||
static int const OFFSET_FLASH=0xc;
|
||||
static int const OFFSET_FLASH_SIZE=0x8;
|
||||
static int const OFFSET_GET_WORKAREA=0x18;
|
||||
static int const OFFSET_GET_WORKAREA_SIZE=0x4;
|
||||
static int const OFFSET_ERASE = 0x0;
|
||||
static int const OFFSET_ERASE_SIZE = 0x8;
|
||||
static int const OFFSET_FLASH = 0xc;
|
||||
static int const OFFSET_FLASH_SIZE = 0x8;
|
||||
static int const OFFSET_GET_WORKAREA = 0x18;
|
||||
static int const OFFSET_GET_WORKAREA_SIZE = 0x4;
|
||||
|
||||
int runCode(ecosflash_flash_bank_t *info,
|
||||
u32 codeStart, u32 codeStop, u32 r0, u32 r1, u32 r2,
|
||||
u32 *result,
|
||||
static int runCode(ecosflash_flash_bank_t *info,
|
||||
uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2,
|
||||
uint32_t *result,
|
||||
/* timeout in ms */
|
||||
int timeout)
|
||||
{
|
||||
target_t *target=info->target;
|
||||
target_t *target = info->target;
|
||||
|
||||
reg_param_t reg_params[3];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
@@ -253,7 +245,7 @@ int runCode(ecosflash_flash_bank_t *info,
|
||||
buf_set_u32(reg_params[2].value, 0, 32, r2);
|
||||
|
||||
int retval;
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
codeStart,
|
||||
codeStop, timeout,
|
||||
&armv4_5_info)) != ERROR_OK)
|
||||
@@ -262,7 +254,7 @@ int runCode(ecosflash_flash_bank_t *info,
|
||||
return retval;
|
||||
}
|
||||
|
||||
*result=buf_get_u32(reg_params[0].value, 0, 32);
|
||||
*result = buf_get_u32(reg_params[0].value, 0, 32);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
@@ -271,81 +263,81 @@ int runCode(ecosflash_flash_bank_t *info,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int eCosBoard_erase(ecosflash_flash_bank_t *info, u32 address, u32 len)
|
||||
static int eCosBoard_erase(ecosflash_flash_bank_t *info, uint32_t address, uint32_t len)
|
||||
{
|
||||
int retval;
|
||||
int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/
|
||||
|
||||
retval=loadDriver(info);
|
||||
if (retval!=ERROR_OK)
|
||||
retval = loadDriver(info);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
u32 flashErr;
|
||||
retval=runCode(info,
|
||||
info->start_address+OFFSET_ERASE,
|
||||
info->start_address+OFFSET_ERASE+OFFSET_ERASE_SIZE,
|
||||
uint32_t flashErr;
|
||||
retval = runCode(info,
|
||||
info->start_address + OFFSET_ERASE,
|
||||
info->start_address + OFFSET_ERASE + OFFSET_ERASE_SIZE,
|
||||
address,
|
||||
len,
|
||||
0,
|
||||
&flashErr,
|
||||
timeout
|
||||
);
|
||||
if (retval!=ERROR_OK)
|
||||
);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (flashErr != 0x0)
|
||||
{
|
||||
LOG_ERROR("Flash erase failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));
|
||||
LOG_ERROR("Flash erase failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 len)
|
||||
static int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, uint32_t address, uint32_t len)
|
||||
{
|
||||
target_t *target=info->target;
|
||||
const int chunk=8192;
|
||||
int retval=ERROR_OK;
|
||||
target_t *target = info->target;
|
||||
const int chunk = 8192;
|
||||
int retval = ERROR_OK;
|
||||
int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/
|
||||
|
||||
retval=loadDriver(info);
|
||||
if (retval!=ERROR_OK)
|
||||
retval = loadDriver(info);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
u32 buffer;
|
||||
retval=runCode(info,
|
||||
info->start_address+OFFSET_GET_WORKAREA,
|
||||
info->start_address+OFFSET_GET_WORKAREA+OFFSET_GET_WORKAREA_SIZE,
|
||||
uint32_t buffer;
|
||||
retval = runCode(info,
|
||||
info->start_address + OFFSET_GET_WORKAREA,
|
||||
info->start_address + OFFSET_GET_WORKAREA + OFFSET_GET_WORKAREA_SIZE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
&buffer,
|
||||
1000);
|
||||
if (retval!=ERROR_OK)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
||||
int i;
|
||||
for (i=0; i<len; i+=chunk)
|
||||
uint32_t i;
|
||||
for (i = 0; i < len; i += chunk)
|
||||
{
|
||||
int t=len-i;
|
||||
if (t>chunk)
|
||||
int t = len-i;
|
||||
if (t > chunk)
|
||||
{
|
||||
t=chunk;
|
||||
t = chunk;
|
||||
}
|
||||
|
||||
int retval;
|
||||
retval=target_write_buffer(target, buffer, t, ((u8 *)data)+i);
|
||||
retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
u32 flashErr;
|
||||
retval=runCode(info,
|
||||
info->start_address+OFFSET_FLASH,
|
||||
info->start_address+OFFSET_FLASH+OFFSET_FLASH_SIZE,
|
||||
uint32_t flashErr;
|
||||
retval = runCode(info,
|
||||
info->start_address + OFFSET_FLASH,
|
||||
info->start_address + OFFSET_FLASH + OFFSET_FLASH_SIZE,
|
||||
buffer,
|
||||
address+i,
|
||||
address + i,
|
||||
t,
|
||||
&flashErr,
|
||||
timeout);
|
||||
@@ -354,19 +346,19 @@ int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 l
|
||||
|
||||
if (flashErr != 0x0)
|
||||
{
|
||||
LOG_ERROR("Flash prog failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));
|
||||
LOG_ERROR("Flash prog failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ecosflash_probe(struct flash_bank_s *bank)
|
||||
static int ecosflash_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ecosflash_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int ecosflash_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
@@ -374,7 +366,7 @@ int ecosflash_register_commands(struct command_context_s *cmd_ctx)
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
|
||||
static void command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
int i;
|
||||
@@ -396,10 +388,11 @@ static void command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 ecosflash_address(struct flash_bank_s *bank, u32 address)
|
||||
#if 0
|
||||
static uint32_t ecosflash_address(struct flash_bank_s *bank, uint32_t address)
|
||||
{
|
||||
u32 retval = 0;
|
||||
switch(bank->bus_width)
|
||||
uint32_t retval = 0;
|
||||
switch (bank->bus_width)
|
||||
{
|
||||
case 4:
|
||||
retval = address & 0xfffffffc;
|
||||
@@ -411,54 +404,57 @@ u32 ecosflash_address(struct flash_bank_s *bank, u32 address)
|
||||
|
||||
return retval + bank->base;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ecosflash_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
struct flash_bank_s *c=bank;
|
||||
struct flash_bank_s *c = bank;
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
return eCosBoard_erase(info, c->base+first*sectorSize, sectorSize*(last-first+1));
|
||||
return eCosBoard_erase(info, c->base + first*sectorSize, sectorSize*(last-first + 1));
|
||||
}
|
||||
|
||||
int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
struct flash_bank_s *c=bank;
|
||||
return eCosBoard_flash(info, buffer, c->base+offset, count);
|
||||
struct flash_bank_s *c = bank;
|
||||
return eCosBoard_flash(info, buffer, c->base + offset, count);
|
||||
}
|
||||
|
||||
int ecosflash_protect_check(struct flash_bank_s *bank)
|
||||
static int ecosflash_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
ecosflash_flash_bank_t *info = bank->driver_priv;
|
||||
snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 ecosflash_get_flash_status(flash_bank_t *bank)
|
||||
#if 0
|
||||
static uint32_t ecosflash_get_flash_status(flash_bank_t *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)
|
||||
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
|
||||
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
153
src/flash/faux.c
Normal file
153
src/flash/faux.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "flash.h"
|
||||
#include "image.h"
|
||||
|
||||
|
||||
static int faux_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int faux_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int faux_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int faux_probe(struct flash_bank_s *bank);
|
||||
static int faux_protect_check(struct flash_bank_s *bank);
|
||||
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
flash_driver_t faux_flash =
|
||||
{
|
||||
.name = "faux",
|
||||
.register_commands = faux_register_commands,
|
||||
.flash_bank_command = faux_flash_bank_command,
|
||||
.erase = faux_erase,
|
||||
.protect = faux_protect,
|
||||
.write = faux_write,
|
||||
.probe = faux_probe,
|
||||
.auto_probe = faux_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = faux_protect_check,
|
||||
.info = faux_info
|
||||
};
|
||||
|
||||
typedef struct faux_flash_bank_s
|
||||
{
|
||||
struct target_s *target;
|
||||
uint8_t *memory;
|
||||
uint32_t start_address;
|
||||
} faux_flash_bank_t;
|
||||
|
||||
static const int sectorSize = 0x10000;
|
||||
|
||||
|
||||
/* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath>
|
||||
*/
|
||||
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
faux_flash_bank_t *info;
|
||||
|
||||
if (argc < 6)
|
||||
{
|
||||
LOG_WARNING("incomplete flash_bank faux configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
info = malloc(sizeof(faux_flash_bank_t));
|
||||
if (info == NULL)
|
||||
{
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
info->memory = malloc(bank->size);
|
||||
if (info == NULL)
|
||||
{
|
||||
free(info);
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
bank->driver_priv = info;
|
||||
|
||||
/* Use 0x10000 as a fixed sector size. */
|
||||
int i = 0;
|
||||
uint32_t offset = 0;
|
||||
bank->num_sectors = bank->size/sectorSize;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
bank->sectors[i].size = sectorSize;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
info->target = get_target(args[5]);
|
||||
if (info->target == NULL)
|
||||
{
|
||||
LOG_ERROR("target '%s' not defined", args[5]);
|
||||
free(info->memory);
|
||||
free(info);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
faux_flash_bank_t *info = bank->driver_priv;
|
||||
memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1));
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
LOG_USER("set protection sector %d to %d to %s", first, last, set?"on":"off");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
faux_flash_bank_t *info = bank->driver_priv;
|
||||
memcpy(info->memory + offset, buffer, count);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "faux flash driver");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int faux_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2008 by Spencer Oliver *
|
||||
@@ -28,46 +28,31 @@
|
||||
#endif
|
||||
|
||||
#include "flash.h"
|
||||
#include "command.h"
|
||||
#include "target.h"
|
||||
#include "time_support.h"
|
||||
#include "fileio.h"
|
||||
#include "image.h"
|
||||
#include "log.h"
|
||||
#include "armv4_5.h"
|
||||
#include "algorithm.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "armv7m.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include "time_support.h"
|
||||
|
||||
/* command handlers */
|
||||
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
|
||||
static int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int flash_write_unlock(target_t *target, image_t *image, uint32_t *written, int erase, bool unlock);
|
||||
|
||||
/* flash drivers
|
||||
*/
|
||||
extern flash_driver_t lpc2000_flash;
|
||||
extern flash_driver_t lpc288x_flash;
|
||||
extern flash_driver_t lpc2900_flash;
|
||||
extern flash_driver_t cfi_flash;
|
||||
extern flash_driver_t at91sam3_flash;
|
||||
extern flash_driver_t at91sam7_flash;
|
||||
extern flash_driver_t at91sam7_old_flash;
|
||||
extern flash_driver_t str7x_flash;
|
||||
extern flash_driver_t str9x_flash;
|
||||
extern flash_driver_t aduc702x_flash;
|
||||
@@ -76,15 +61,18 @@ extern flash_driver_t str9xpec_flash;
|
||||
extern flash_driver_t stm32x_flash;
|
||||
extern flash_driver_t tms470_flash;
|
||||
extern flash_driver_t ecosflash_flash;
|
||||
extern flash_driver_t lpc288x_flash;
|
||||
extern flash_driver_t ocl_flash;
|
||||
extern flash_driver_t pic32mx_flash;
|
||||
extern flash_driver_t avr_flash;
|
||||
extern flash_driver_t faux_flash;
|
||||
|
||||
flash_driver_t *flash_drivers[] = {
|
||||
&lpc2000_flash,
|
||||
&lpc288x_flash,
|
||||
&lpc2900_flash,
|
||||
&cfi_flash,
|
||||
&at91sam7_flash,
|
||||
&at91sam7_old_flash,
|
||||
&at91sam3_flash,
|
||||
&str7x_flash,
|
||||
&str9x_flash,
|
||||
&aduc702x_flash,
|
||||
@@ -93,9 +81,10 @@ flash_driver_t *flash_drivers[] = {
|
||||
&stm32x_flash,
|
||||
&tms470_flash,
|
||||
&ecosflash_flash,
|
||||
&lpc288x_flash,
|
||||
&ocl_flash,
|
||||
&pic32mx_flash,
|
||||
&avr_flash,
|
||||
&faux_flash,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -103,14 +92,15 @@ flash_bank_t *flash_banks;
|
||||
static command_t *flash_cmd;
|
||||
|
||||
/* wafer thin wrapper for invoking the flash driver */
|
||||
static int flash_driver_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int flash_driver_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval=bank->driver->write(bank, buffer, offset, count);
|
||||
if (retval!=ERROR_OK)
|
||||
retval = bank->driver->write(bank, buffer, offset, count);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error writing to flash at address 0x%08x at offset 0x%8.8x (%d)", bank->base, offset, retval);
|
||||
LOG_ERROR("error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " (%d)",
|
||||
bank->base, offset, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -120,8 +110,8 @@ static int flash_driver_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval=bank->driver->erase(bank, first, last);
|
||||
if (retval!=ERROR_OK)
|
||||
retval = bank->driver->erase(bank, first, last);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed erasing sectors %d to %d (%d)", first, last, retval);
|
||||
}
|
||||
@@ -133,8 +123,8 @@ int flash_driver_protect(struct flash_bank_s *bank, int set, int first, int last
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval=bank->driver->protect(bank, set, first, last);
|
||||
if (retval!=ERROR_OK)
|
||||
retval = bank->driver->protect(bank, set, first, last);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("failed setting protection for areas %d to %d (%d)", first, last, retval);
|
||||
}
|
||||
@@ -159,10 +149,10 @@ static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
Jim_Obj *list=Jim_NewListObj(interp, NULL, 0);
|
||||
Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
|
||||
for (p = flash_banks; p; p = p->next)
|
||||
{
|
||||
Jim_Obj *elem=Jim_NewListObj(interp, NULL, 0);
|
||||
Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0);
|
||||
|
||||
Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
|
||||
Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
|
||||
@@ -212,9 +202,9 @@ int flash_init_drivers(struct command_context_s *cmd_ctx)
|
||||
register_command(cmd_ctx, flash_cmd, "write_bank", handle_flash_write_bank_command, COMMAND_EXEC,
|
||||
"write binary data to <bank> <file> <offset>");
|
||||
register_command(cmd_ctx, flash_cmd, "write_image", handle_flash_write_image_command, COMMAND_EXEC,
|
||||
"write_image [erase] <file> [offset] [type]");
|
||||
"write_image [erase] [unlock] <file> [offset] [type]");
|
||||
register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
|
||||
"set protection of sectors at <bank> <first> <last> <on|off>");
|
||||
"set protection of sectors at <bank> <first> <last> <on | off>");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -265,7 +255,7 @@ flash_bank_t *get_flash_bank_by_num(int num)
|
||||
return p;
|
||||
}
|
||||
|
||||
int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
int retval;
|
||||
int i;
|
||||
@@ -277,9 +267,9 @@ int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if ((target = get_target_by_num(strtoul(args[5], NULL, 0))) == NULL)
|
||||
if ((target = get_target(args[5])) == NULL)
|
||||
{
|
||||
LOG_ERROR("target %lu not defined", strtoul(args[5], NULL, 0));
|
||||
LOG_ERROR("target '%s' not defined", args[5]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -308,9 +298,9 @@ int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
c->sectors = NULL;
|
||||
c->next = NULL;
|
||||
|
||||
if ((retval=flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
|
||||
if ((retval = flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
|
||||
LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 , args[0], c->base);
|
||||
free(c);
|
||||
return retval;
|
||||
}
|
||||
@@ -345,10 +335,10 @@ int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *p;
|
||||
int i = 0;
|
||||
uint32_t i = 0;
|
||||
int j = 0;
|
||||
int retval;
|
||||
|
||||
@@ -367,8 +357,14 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
if ((retval = p->driver->auto_probe(p)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
|
||||
i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
|
||||
command_print(cmd_ctx,
|
||||
"#%" PRIi32 " : %s at 0x%8.8" PRIx32 ", size 0x%8.8" PRIx32 ", buswidth %i, chipwidth %i",
|
||||
i,
|
||||
p->driver->name,
|
||||
p->base,
|
||||
p->size,
|
||||
p->bus_width,
|
||||
p->chip_width);
|
||||
for (j = 0; j < p->num_sectors; j++)
|
||||
{
|
||||
char *protect_state;
|
||||
@@ -380,9 +376,13 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
else
|
||||
protect_state = "protection state unknown";
|
||||
|
||||
command_print(cmd_ctx, "\t#%3i: 0x%8.8x (0x%x %ikB) %s",
|
||||
j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
|
||||
protect_state);
|
||||
command_print(cmd_ctx,
|
||||
"\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
|
||||
j,
|
||||
p->sectors[j].offset,
|
||||
p->sectors[j].size,
|
||||
p->sectors[j].size >> 10,
|
||||
protect_state);
|
||||
}
|
||||
|
||||
*buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver function fails */
|
||||
@@ -396,7 +396,7 @@ int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *p;
|
||||
int retval;
|
||||
@@ -411,16 +411,16 @@ int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
{
|
||||
if ((retval = p->driver->probe(p)) == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
|
||||
command_print(cmd_ctx, "flash '%s' found at 0x%8.8" PRIx32, p->driver->name, p->base);
|
||||
}
|
||||
else if (retval == ERROR_FLASH_BANK_INVALID)
|
||||
{
|
||||
command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
|
||||
command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8" PRIx32,
|
||||
args[0], p->base);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
|
||||
command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8" PRIx32,
|
||||
args[0], p->base);
|
||||
}
|
||||
}
|
||||
@@ -432,7 +432,7 @@ int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *p;
|
||||
int retval;
|
||||
@@ -448,11 +448,11 @@ int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cm
|
||||
int j;
|
||||
if ((retval = p->driver->erase_check(p)) == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
|
||||
command_print(cmd_ctx, "successfully checked erase state");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
|
||||
command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32,
|
||||
args[0], p->base);
|
||||
}
|
||||
|
||||
@@ -467,16 +467,20 @@ int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cm
|
||||
else
|
||||
erase_state = "erase state unknown";
|
||||
|
||||
command_print(cmd_ctx, "\t#%3i: 0x%8.8x (0x%x %ikB) %s",
|
||||
j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size>>10,
|
||||
erase_state);
|
||||
command_print(cmd_ctx,
|
||||
"\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s",
|
||||
j,
|
||||
p->sectors[j].offset,
|
||||
p->sectors[j].size,
|
||||
p->sectors[j].size >> 10,
|
||||
erase_state);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *p;
|
||||
int retval;
|
||||
@@ -524,7 +528,7 @@ int handle_flash_erase_address_command(struct command_context_s *cmd_ctx, char *
|
||||
return retval;
|
||||
}
|
||||
|
||||
int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *p;
|
||||
int retval;
|
||||
@@ -543,11 +547,11 @@ int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *
|
||||
}
|
||||
else if (retval == ERROR_FLASH_OPERATION_FAILED)
|
||||
{
|
||||
command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
|
||||
command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8" PRIx32, args[0], p->base);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
|
||||
command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8" PRIx32, args[0], p->base);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -558,88 +562,131 @@ int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int flash_check_sector_parameters(struct command_context_s *cmd_ctx,
|
||||
uint32_t first, uint32_t last, uint32_t num_sectors)
|
||||
{
|
||||
if (!(first <= last)) {
|
||||
command_print(cmd_ctx, "ERROR: "
|
||||
"first sector must be <= last sector");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!(last <= (num_sectors - 1))) {
|
||||
command_print(cmd_ctx, "ERROR: last sector must be <= %d",
|
||||
(int) num_sectors - 1);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int handle_flash_erase_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc)
|
||||
{
|
||||
if (argc > 2)
|
||||
{
|
||||
int first = strtoul(args[1], NULL, 0);
|
||||
int last = strtoul(args[2], NULL, 0);
|
||||
uint32_t bank_nr;
|
||||
uint32_t first;
|
||||
uint32_t last;
|
||||
int retval;
|
||||
flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
|
||||
if ((retval = parse_u32(args[0], &bank_nr)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
flash_bank_t *p = get_flash_bank_by_num(bank_nr);
|
||||
if (!p)
|
||||
return ERROR_OK;
|
||||
|
||||
if ((retval = parse_u32(args[1], &first)) != ERROR_OK)
|
||||
return retval;
|
||||
if (strcmp(args[2], "last") == 0)
|
||||
last = p->num_sectors - 1;
|
||||
else
|
||||
if ((retval = parse_u32(args[2], &last)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((retval = flash_check_sector_parameters(cmd_ctx,
|
||||
first, last, p->num_sectors)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
duration_t duration;
|
||||
char *duration_text;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
|
||||
if (!p)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK)
|
||||
{
|
||||
if ((retval = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
|
||||
{
|
||||
if ((retval = flash_driver_erase(p, first, last)) == ERROR_OK) {
|
||||
if ((retval = duration_stop_measure(&duration,
|
||||
&duration_text)) != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
command_print(cmd_ctx, "erased sectors %i through %i on flash bank %i in %s", first, last, strtoul(args[0], 0, 0), duration_text);
|
||||
command_print(cmd_ctx, "erased sectors %i through %i "
|
||||
"on flash bank %i in %s",
|
||||
(int) first, (int) last, (int) bank_nr,
|
||||
duration_text);
|
||||
free(duration_text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_protect_command(struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc)
|
||||
{
|
||||
if (argc > 3)
|
||||
{
|
||||
int first = strtoul(args[1], NULL, 0);
|
||||
int last = strtoul(args[2], NULL, 0);
|
||||
int set;
|
||||
uint32_t bank_nr;
|
||||
uint32_t first;
|
||||
uint32_t last;
|
||||
int retval;
|
||||
flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
int set;
|
||||
|
||||
if ((retval = parse_u32(args[0], &bank_nr)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
flash_bank_t *p = get_flash_bank_by_num(bank_nr);
|
||||
if (!p)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if ((retval = parse_u32(args[1], &first)) != ERROR_OK)
|
||||
return retval;
|
||||
if (strcmp(args[2], "last") == 0)
|
||||
last = p->num_sectors - 1;
|
||||
else
|
||||
if ((retval = parse_u32(args[2], &last)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (strcmp(args[3], "on") == 0)
|
||||
set = 1;
|
||||
else if (strcmp(args[3], "off") == 0)
|
||||
set = 0;
|
||||
else
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if ((retval = flash_check_sector_parameters(cmd_ctx,
|
||||
first, last, p->num_sectors)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = flash_driver_protect(p, set, first, last);
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "%s protection for sectors %i through %i on flash bank %i", (set) ? "set" : "cleared", first, last, strtoul(args[0], 0, 0));
|
||||
if (retval == ERROR_OK) {
|
||||
command_print(cmd_ctx, "%s protection for sectors %i "
|
||||
"through %i on flash bank %i",
|
||||
(set) ? "set" : "cleared", (int) first,
|
||||
(int) last, (int) bank_nr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
target_t *target = get_current_target(cmd_ctx);
|
||||
|
||||
image_t image;
|
||||
u32 written;
|
||||
uint32_t written;
|
||||
|
||||
duration_t duration;
|
||||
char *duration_text;
|
||||
@@ -653,13 +700,26 @@ int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cm
|
||||
|
||||
/* flash auto-erase is disabled by default*/
|
||||
int auto_erase = 0;
|
||||
bool auto_unlock = false;
|
||||
|
||||
if (strcmp(args[0], "erase")==0)
|
||||
for (;;)
|
||||
{
|
||||
auto_erase = 1;
|
||||
args++;
|
||||
argc--;
|
||||
command_print(cmd_ctx, "auto erase enabled");
|
||||
if (strcmp(args[0], "erase") == 0)
|
||||
{
|
||||
auto_erase = 1;
|
||||
args++;
|
||||
argc--;
|
||||
command_print(cmd_ctx, "auto erase enabled");
|
||||
} else if (strcmp(args[0], "unlock") == 0)
|
||||
{
|
||||
auto_unlock = true;
|
||||
args++;
|
||||
argc--;
|
||||
command_print(cmd_ctx, "auto unlock enabled");
|
||||
} else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
@@ -694,7 +754,7 @@ int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cm
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = flash_write(target, &image, &written, auto_erase);
|
||||
retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
image_close(&image);
|
||||
@@ -706,12 +766,16 @@ int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cm
|
||||
image_close(&image);
|
||||
return retvaltemp;
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "wrote %u byte from file %s in %s (%f kb/s)",
|
||||
written, args[0], duration_text,
|
||||
(float)written / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
|
||||
}
|
||||
|
||||
float speed;
|
||||
|
||||
speed = written / 1024.0;
|
||||
speed /= ((float)duration.duration.tv_sec
|
||||
+ ((float)duration.duration.tv_usec / 1000000.0));
|
||||
command_print(cmd_ctx,
|
||||
"wrote %" PRIu32 " byte from file %s in %s (%f kb/s)",
|
||||
written, args[0], duration_text, speed);
|
||||
|
||||
free(duration_text);
|
||||
|
||||
image_close(&image);
|
||||
@@ -719,20 +783,22 @@ int handle_flash_write_image_command(struct command_context_s *cmd_ctx, char *cm
|
||||
return retval;
|
||||
}
|
||||
|
||||
int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
int err = ERROR_OK, retval;
|
||||
u32 address;
|
||||
u32 pattern;
|
||||
u32 count;
|
||||
u8 chunk[1024];
|
||||
u32 wrote = 0;
|
||||
int chunk_count;
|
||||
uint32_t address;
|
||||
uint32_t pattern;
|
||||
uint32_t count;
|
||||
uint8_t chunk[1024];
|
||||
uint8_t readback[1024];
|
||||
uint32_t wrote = 0;
|
||||
uint32_t cur_size = 0;
|
||||
uint32_t chunk_count;
|
||||
char *duration_text;
|
||||
duration_t duration;
|
||||
target_t *target = get_current_target(cmd_ctx);
|
||||
u32 i;
|
||||
int wordsize;
|
||||
uint32_t i;
|
||||
uint32_t wordsize;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
@@ -743,35 +809,35 @@ int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
pattern = strtoul(args[1], NULL, 0);
|
||||
count = strtoul(args[2], NULL, 0);
|
||||
|
||||
if(count == 0)
|
||||
if (count == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
switch(cmd[4])
|
||||
switch (cmd[4])
|
||||
{
|
||||
case 'w':
|
||||
wordsize=4;
|
||||
wordsize = 4;
|
||||
break;
|
||||
case 'h':
|
||||
wordsize=2;
|
||||
wordsize = 2;
|
||||
break;
|
||||
case 'b':
|
||||
wordsize=1;
|
||||
wordsize = 1;
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
chunk_count = MIN(count, (1024 / wordsize));
|
||||
switch(wordsize)
|
||||
switch (wordsize)
|
||||
{
|
||||
case 4:
|
||||
for(i = 0; i < chunk_count; i++)
|
||||
for (i = 0; i < chunk_count; i++)
|
||||
{
|
||||
target_buffer_set_u32(target, chunk + i * wordsize, pattern);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for(i = 0; i < chunk_count; i++)
|
||||
for (i = 0; i < chunk_count; i++)
|
||||
{
|
||||
target_buffer_set_u16(target, chunk + i * wordsize, pattern);
|
||||
}
|
||||
@@ -786,19 +852,34 @@ int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
|
||||
duration_start_measure(&duration);
|
||||
|
||||
for (wrote=0; wrote<(count*wordsize); wrote+=sizeof(chunk))
|
||||
for (wrote = 0; wrote < (count*wordsize); wrote += cur_size)
|
||||
{
|
||||
int cur_size = MIN( (count*wordsize - wrote) , 1024 );
|
||||
cur_size = MIN((count*wordsize - wrote), sizeof(chunk));
|
||||
flash_bank_t *bank;
|
||||
bank = get_flash_bank_by_addr(target, address);
|
||||
if(bank == NULL)
|
||||
if (bank == NULL)
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size);
|
||||
if (err!=ERROR_OK)
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
wrote += cur_size;
|
||||
|
||||
err = target_read_buffer(target, address + wrote, cur_size, readback);
|
||||
if (err != ERROR_OK)
|
||||
return err;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < cur_size; i++)
|
||||
{
|
||||
if (readback[i]!=chunk[i])
|
||||
{
|
||||
LOG_ERROR("Verfication error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x",
|
||||
address + wrote + i, readback[i], chunk[i]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((retval = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
|
||||
@@ -806,24 +887,24 @@ int handle_flash_fill_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return retval;
|
||||
}
|
||||
|
||||
if(err == ERROR_OK)
|
||||
{
|
||||
float speed;
|
||||
speed=wrote / 1024.0;
|
||||
speed/=((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0));
|
||||
command_print(cmd_ctx, "wrote %d bytes to 0x%8.8x in %s (%f kb/s)",
|
||||
count*wordsize, address, duration_text,
|
||||
speed);
|
||||
}
|
||||
float speed;
|
||||
|
||||
speed = wrote / 1024.0;
|
||||
speed /= ((float)duration.duration.tv_sec
|
||||
+ ((float)duration.duration.tv_usec / 1000000.0));
|
||||
command_print(cmd_ctx,
|
||||
"wrote %" PRIu32 " bytes to 0x%8.8" PRIx32 " in %s (%f kb/s)",
|
||||
wrote, address, duration_text, speed);
|
||||
|
||||
free(duration_text);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
u32 offset;
|
||||
u8 *buffer;
|
||||
u32 buf_cnt;
|
||||
uint32_t offset;
|
||||
uint8_t *buffer;
|
||||
uint32_t buf_cnt;
|
||||
|
||||
fileio_t fileio;
|
||||
|
||||
@@ -871,11 +952,16 @@ int handle_flash_write_bank_command(struct command_context_s *cmd_ctx, char *cmd
|
||||
fileio_close(&fileio);
|
||||
return retvaltemp;
|
||||
}
|
||||
if (retval==ERROR_OK)
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "wrote %"PRIi64" byte from file %s to flash bank %i at offset 0x%8.8x in %s (%f kb/s)",
|
||||
fileio.size, args[1], strtoul(args[0], NULL, 0), offset, duration_text,
|
||||
(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
|
||||
command_print(cmd_ctx,
|
||||
"wrote %lld byte from file %s to flash bank %li at offset 0x%8.8" PRIx32 " in %s (%f kb/s)",
|
||||
fileio.size,
|
||||
args[1],
|
||||
strtoul(args[0], NULL, 0),
|
||||
offset,
|
||||
duration_text,
|
||||
(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
|
||||
}
|
||||
free(duration_text);
|
||||
|
||||
@@ -900,7 +986,7 @@ void flash_set_dirty(void)
|
||||
}
|
||||
|
||||
/* lookup flash bank by address */
|
||||
flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)
|
||||
flash_bank_t *get_flash_bank_by_addr(target_t *target, uint32_t addr)
|
||||
{
|
||||
flash_bank_t *c;
|
||||
|
||||
@@ -919,12 +1005,13 @@ flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr)
|
||||
if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
|
||||
return c;
|
||||
}
|
||||
LOG_ERROR("No flash at address 0x%08x\n", addr);
|
||||
LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* erase given flash region, selects proper bank according to target and address */
|
||||
int flash_erase_address_range(target_t *target, u32 addr, u32 length)
|
||||
static int flash_iterate_address_range(target_t *target, uint32_t addr, uint32_t length,
|
||||
int (*callback)(struct flash_bank_s *bank, int first, int last))
|
||||
{
|
||||
flash_bank_t *c;
|
||||
int first = -1;
|
||||
@@ -946,11 +1033,11 @@ int flash_erase_address_range(target_t *target, u32 addr, u32 length)
|
||||
if (addr != c->base)
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
|
||||
return flash_driver_erase(c, 0, c->num_sectors - 1);
|
||||
return callback(c, 0, c->num_sectors - 1);
|
||||
}
|
||||
|
||||
/* check whether it fits */
|
||||
if (addr + length > c->base + c->size)
|
||||
if (addr + length - 1 > c->base + c->size - 1)
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
|
||||
addr -= c->base;
|
||||
@@ -966,19 +1053,37 @@ int flash_erase_address_range(target_t *target, u32 addr, u32 length)
|
||||
}
|
||||
}
|
||||
|
||||
if( first == -1 || last == -1 )
|
||||
if (first == -1 || last == -1)
|
||||
return ERROR_OK;
|
||||
|
||||
return flash_driver_erase(c, first, last);
|
||||
return callback(c, first, last);
|
||||
}
|
||||
|
||||
/* write (optional verify) an image to flash memory of the given target */
|
||||
int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
|
||||
|
||||
int flash_erase_address_range(target_t *target, uint32_t addr, uint32_t length)
|
||||
{
|
||||
int retval=ERROR_OK;
|
||||
return flash_iterate_address_range(target, addr, length, &flash_driver_erase);
|
||||
}
|
||||
|
||||
static int flash_driver_unprotect(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
return flash_driver_protect(bank, 0, first, last);
|
||||
}
|
||||
|
||||
static int flash_unlock_address_range(target_t *target, uint32_t addr, uint32_t length)
|
||||
{
|
||||
return flash_iterate_address_range(target, addr, length, &flash_driver_unprotect);
|
||||
}
|
||||
|
||||
|
||||
/* write (optional verify) an image to flash memory of the given target */
|
||||
static int flash_write_unlock(target_t *target, image_t *image, uint32_t *written, int erase, bool unlock)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
int section;
|
||||
u32 section_offset;
|
||||
uint32_t section_offset;
|
||||
flash_bank_t *c;
|
||||
int *padding;
|
||||
|
||||
@@ -1002,12 +1107,12 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
/* loop until we reach end of the image */
|
||||
while (section < image->num_sections)
|
||||
{
|
||||
u32 buffer_size;
|
||||
u8 *buffer;
|
||||
uint32_t buffer_size;
|
||||
uint8_t *buffer;
|
||||
int section_first;
|
||||
int section_last;
|
||||
u32 run_address = image->sections[section].base_address + section_offset;
|
||||
u32 run_size = image->sections[section].size - section_offset;
|
||||
uint32_t run_address = image->sections[section].base_address + section_offset;
|
||||
uint32_t run_size = image->sections[section].size - section_offset;
|
||||
int pad_bytes = 0;
|
||||
|
||||
if (image->sections[section].size == 0)
|
||||
@@ -1030,7 +1135,7 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
section_first = section;
|
||||
section_last = section;
|
||||
padding[section] = 0;
|
||||
while ((run_address + run_size < c->base + c->size)
|
||||
while ((run_address + run_size - 1 < c->base + c->size - 1)
|
||||
&& (section_last + 1 < image->num_sections))
|
||||
{
|
||||
if (image->sections[section_last + 1].base_address < (run_address + run_size))
|
||||
@@ -1048,12 +1153,16 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
run_size += pad_bytes;
|
||||
padding[section_last] = 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 > c->base + c->size)
|
||||
if (run_address + run_size - 1 > c->base + c->size - 1)
|
||||
{
|
||||
LOG_WARNING("writing %d bytes only - as image section is %d bytes and bank is only %d bytes", \
|
||||
(int)(c->base + c->size - run_address), (int)(run_size), (int)(c->size));
|
||||
run_size = c->base + c->size - run_address;
|
||||
}
|
||||
|
||||
/* allocate buffer */
|
||||
buffer = malloc(run_size);
|
||||
@@ -1062,7 +1171,7 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
/* read sections to the buffer */
|
||||
while (buffer_size < run_size)
|
||||
{
|
||||
u32 size_read;
|
||||
uint32_t size_read;
|
||||
|
||||
size_read = run_size - buffer_size;
|
||||
if (size_read > image->sections[section].size - section_offset)
|
||||
@@ -1078,7 +1187,7 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
|
||||
/* see if we need to pad the section */
|
||||
while (padding[section]--)
|
||||
(buffer+buffer_size)[size_read++] = 0xff;
|
||||
(buffer + buffer_size)[size_read++] = 0xff;
|
||||
|
||||
buffer_size += size_read;
|
||||
section_offset += size_read;
|
||||
@@ -1092,10 +1201,17 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
|
||||
retval = ERROR_OK;
|
||||
|
||||
if (erase)
|
||||
if (unlock)
|
||||
{
|
||||
/* calculate and erase sectors */
|
||||
retval = flash_erase_address_range( target, run_address, run_size );
|
||||
retval = flash_unlock_address_range(target, run_address, run_size);
|
||||
}
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if (erase)
|
||||
{
|
||||
/* calculate and erase sectors */
|
||||
retval = flash_erase_address_range(target, run_address, run_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == ERROR_OK)
|
||||
@@ -1121,13 +1237,18 @@ int flash_write(target_t *target, image_t *image, u32 *written, int erase)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int flash_write(target_t *target, image_t *image, uint32_t *written, int erase)
|
||||
{
|
||||
return flash_write_unlock(target, image, written, erase, false);
|
||||
}
|
||||
|
||||
int default_flash_mem_blank_check(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u8 buffer[1024];
|
||||
uint8_t buffer[1024];
|
||||
int buffer_size = sizeof(buffer);
|
||||
int i;
|
||||
int nBytes;
|
||||
uint32_t nBytes;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -1137,12 +1258,12 @@ int default_flash_mem_blank_check(struct flash_bank_s *bank)
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
int j;
|
||||
uint32_t j;
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
for (j = 0; j < bank->sectors[i].size; j += buffer_size)
|
||||
{
|
||||
int chunk;
|
||||
uint32_t chunk;
|
||||
int retval;
|
||||
chunk = buffer_size;
|
||||
if (chunk > (j - bank->sectors[i].size))
|
||||
@@ -1150,7 +1271,7 @@ int default_flash_mem_blank_check(struct flash_bank_s *bank)
|
||||
chunk = (j - bank->sectors[i].size);
|
||||
}
|
||||
|
||||
retval = target->type->read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
|
||||
retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
@@ -1174,7 +1295,7 @@ int default_flash_blank_check(struct flash_bank_s *bank)
|
||||
int i;
|
||||
int retval;
|
||||
int fast_check = 0;
|
||||
u32 blank;
|
||||
uint32_t blank;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -1184,8 +1305,8 @@ int default_flash_blank_check(struct flash_bank_s *bank)
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
u32 address = bank->base + bank->sectors[i].offset;
|
||||
u32 size = bank->sectors[i].size;
|
||||
uint32_t address = bank->base + bank->sectors[i].offset;
|
||||
uint32_t size = bank->sectors[i].size;
|
||||
|
||||
if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2008 by Spencer Oliver *
|
||||
@@ -27,70 +27,305 @@
|
||||
#define FLASH_H
|
||||
|
||||
#include "target.h"
|
||||
#include "image.h"
|
||||
#include "log.h"
|
||||
|
||||
struct image_s;
|
||||
|
||||
#define FLASH_MAX_ERROR_STR (128)
|
||||
|
||||
/**
|
||||
* Describes the geometry and status of a single flash sector
|
||||
* within a flash bank. A single bank typically consists of multiple
|
||||
* sectors, each of which can be erased and protected independently.
|
||||
*/
|
||||
typedef struct flash_sector_s
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
/// Bus offset from start of the flash chip (in bytes).
|
||||
uint32_t offset;
|
||||
/// Number of bytes in this flash sector.
|
||||
uint32_t size;
|
||||
/**
|
||||
* Indication of erasure status: 0 = not erased, 1 = erased,
|
||||
* other = unknown. Set by @c flash_driver_s::erase_check.
|
||||
*/
|
||||
int is_erased;
|
||||
/**
|
||||
* Indication of protection status: 0 = unprotected/unlocked,
|
||||
* 1 = protected/locked, other = unknown. Set by
|
||||
* @c flash_driver_s::protect_check.
|
||||
*/
|
||||
int is_protected;
|
||||
} flash_sector_t;
|
||||
|
||||
struct flash_bank_s;
|
||||
|
||||
/**
|
||||
* @brief Provides the implementation-independent structure that defines
|
||||
* all of the callbacks required by OpenOCD flash drivers.
|
||||
*
|
||||
* Driver authors must implement the routines defined here, providing an
|
||||
* instance with the fields filled out. After that, the instance must
|
||||
* be registered in flash.c, so it can be used by the driver lookup system.
|
||||
*
|
||||
* Specifically, the user can issue the command: @par
|
||||
* @code
|
||||
* flash bank DRIVERNAME ...parameters...
|
||||
* @endcode
|
||||
*
|
||||
* OpenOCD will search for the driver with a @c flash_driver_s::name
|
||||
* that matches @c DRIVERNAME.
|
||||
*
|
||||
* The flash subsystem calls some of the other drivers routines a using
|
||||
* corresponding static <code>flash_driver_<i>callback</i>()</code>
|
||||
* routine in flash.c.
|
||||
*/
|
||||
typedef struct flash_driver_s
|
||||
{
|
||||
/**
|
||||
* Gives a human-readable name of this flash driver,
|
||||
* This field is used to select and initialize the driver.
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Registers driver-specific commands. When called (during the
|
||||
* "flash bank" command), the driver may register addition
|
||||
* commands to support new flash chip functions.
|
||||
*
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||
|
||||
/**
|
||||
* Finish the "flash bank" command for @a bank. The
|
||||
* @a bank parameter will have been filled in by the core flash
|
||||
* layer when this routine is called, and the driver can store
|
||||
* additional information in its flash_bank_t::driver_priv field.
|
||||
*
|
||||
* @param cmd_ctx - the command context
|
||||
* @param cmd - the command, in this case 'flash'
|
||||
* @param args - parameters, see below
|
||||
* @param argc - number of parameters on command line
|
||||
* @param bank - new filled in flash bank.
|
||||
*
|
||||
* The args are: @par
|
||||
* @code
|
||||
* args[0] = bank
|
||||
* args[1] = drivername {name above}
|
||||
* args[2] = baseaddress
|
||||
* args[3] = lengthbytes
|
||||
* args[4] = chip_width_in bytes
|
||||
* args[5] = bus_width_bytes
|
||||
* args[6] = driver-specific parameters
|
||||
* @endcode
|
||||
*
|
||||
* For example, args[4] = 16 bit flash, args[5] = 32bit bus.
|
||||
*
|
||||
* If extra arguments are provided (@a argc > 6), they will
|
||||
* start in @a args[6]. These can be used to implement
|
||||
* driver-specific extensions.
|
||||
*
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
|
||||
/* use flash_driver_erase() wrapper to invoke */
|
||||
/**
|
||||
* Bank/sector erase routine (target-specific). When
|
||||
* called, the flash driver should erase the specified sectors
|
||||
* using whatever means are at its disposal.
|
||||
*
|
||||
* @param bank The bank of flash to be erased.
|
||||
* @param first The number of the first sector to erase, typically 0.
|
||||
* @param last The number of the last sector to erase, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase)(struct flash_bank_s *bank, int first, int last);
|
||||
|
||||
/* use flash_driver_protect() wrapper to invoke */
|
||||
/**
|
||||
* Bank/sector protection routine (target-specific).
|
||||
* When called, the driver should disable 'flash write' bits (or
|
||||
* enable 'erase protection' bits) for the given @a bank and @a
|
||||
* sectors.
|
||||
*
|
||||
* @param bank The bank to protect or unprotect.
|
||||
* @param set If non-zero, enable protection; if 0, disable it.
|
||||
* @param first The first sector to (un)protect, typicaly 0.
|
||||
* @param last The last sector to (un)project, typically N-1.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
|
||||
|
||||
/* use the flash_driver_write() wrapper to invoke. */
|
||||
int (*write)(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
/**
|
||||
* Program data into the flash. Note CPU address will be
|
||||
* "bank->base + offset", while the physical address is
|
||||
* dependent upon current target MMU mappings.
|
||||
*
|
||||
* @param bank The bank to program
|
||||
* @param buffer The data bytes to write.
|
||||
* @param offset The offset into the chip to program.
|
||||
* @param count The number of bytes to write.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*write)(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
|
||||
/**
|
||||
* Probe to determine what kind of flash is present.
|
||||
* This is invoked by the "probe" script command.
|
||||
*
|
||||
* @param bank The bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*probe)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Check the erasure status of a flash bank.
|
||||
* When called, the driver routine must perform the required
|
||||
* checks and then set the @c flash_sector_s::is_erased field
|
||||
* for each of the flash banks's sectors.
|
||||
*
|
||||
* @param bank The bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*erase_check)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Determine if the specific bank is "protected" or not.
|
||||
* When called, the driver routine must must perform the
|
||||
* required protection check(s) and then set the @c
|
||||
* flash_sector_s::is_protected field for each of the flash
|
||||
* bank's sectors.
|
||||
*
|
||||
* @param bank - the bank to check
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*protect_check)(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Display human-readable information about the flash
|
||||
* bank into the given buffer. Drivers must be careful to avoid
|
||||
* overflowing the buffer.
|
||||
*
|
||||
* @param bank - the bank to get info about
|
||||
* @param char - where to put the text for the human to read
|
||||
* @param buf_size - the size of the human buffer.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* A more gentle flavor of filash_driver_s::probe, performing
|
||||
* setup with less noise. Generally, driver routines should test
|
||||
* to seee if the bank has already been probed; if it has, the
|
||||
* driver probably should not perform its probe a second time.
|
||||
*
|
||||
* This callback is often called from the inside of other
|
||||
* routines (e.g. GDB flash downloads) to autoprobe the flash as
|
||||
* it is programing the flash.
|
||||
*
|
||||
* @param bank - the bank to probe
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
int (*auto_probe)(struct flash_bank_s *bank);
|
||||
} flash_driver_t;
|
||||
|
||||
/**
|
||||
* Provides details of a flash bank, available either on-chip or through
|
||||
* a major interface.
|
||||
*
|
||||
* This structure will be passed as a parameter to the callbacks in the
|
||||
* flash_driver_s structure, some of which may modify the contents of
|
||||
* this structure of the area of flash that it defines. Driver writers
|
||||
* may use the @c driver_priv member to store additional data on a
|
||||
* per-bank basis, if required.
|
||||
*/
|
||||
typedef struct flash_bank_s
|
||||
{
|
||||
target_t *target;
|
||||
flash_driver_t *driver;
|
||||
void *driver_priv;
|
||||
int bank_number;
|
||||
u32 base;
|
||||
u32 size;
|
||||
int chip_width;
|
||||
int bus_width;
|
||||
struct target_s *target; /**< Target to which this bank belongs. */
|
||||
|
||||
flash_driver_t *driver; /**< Driver for this bank. */
|
||||
void *driver_priv; /**< Private driver storage pointer */
|
||||
|
||||
int bank_number; /**< The 'bank' (or chip number) of this instance. */
|
||||
uint32_t base; /**< The base address of this bank */
|
||||
uint32_t size; /**< The size of this chip bank, in bytes */
|
||||
|
||||
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
|
||||
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
|
||||
|
||||
/**
|
||||
* The number of sectors on this chip. This value will
|
||||
* be set intially to 0, and the flash driver must set this to
|
||||
* some non-zero value during "probe()" or "auto_probe()".
|
||||
*/
|
||||
int num_sectors;
|
||||
/// Array of sectors, allocated and initilized by the flash driver
|
||||
flash_sector_t *sectors;
|
||||
struct flash_bank_s *next;
|
||||
|
||||
struct flash_bank_s *next; /**< The next flash bank on this chip */
|
||||
} flash_bank_t;
|
||||
|
||||
/// Registers the 'flash' subsystem commands
|
||||
extern int flash_register_commands(struct command_context_s *cmd_ctx);
|
||||
/// Initializes the 'flash' subsystem drivers
|
||||
extern int flash_init_drivers(struct command_context_s *cmd_ctx);
|
||||
|
||||
extern int flash_erase_address_range(target_t *target, u32 addr, u32 length);
|
||||
extern int flash_write(target_t *target, image_t *image, u32 *written, int erase);
|
||||
/**
|
||||
* Erases @a length bytes in the @a target flash, starting at @a addr.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int flash_erase_address_range(struct target_s *target, uint32_t addr, uint32_t length);
|
||||
/**
|
||||
* Writes @a image into the @a target flash. The @a written parameter
|
||||
* will contain the
|
||||
* @param target The target with the flash to be programmed.
|
||||
* @param image The image that will be programmed to flash.
|
||||
* @param written On return, contains the number of bytes written.
|
||||
* @param erase If non-zero, indicates the flash driver should first
|
||||
* erase the corresponding banks or sectors before programming.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int flash_write(struct target_s *target, struct image_s *image, uint32_t *written, int erase);
|
||||
/**
|
||||
* Forces targets to re-examine their erase/protection state.
|
||||
* This routine must be called when the system may modify the status.
|
||||
*/
|
||||
extern void flash_set_dirty(void);
|
||||
/// @returns The number of flash banks currently defined.
|
||||
extern int flash_get_bank_count(void);
|
||||
/**
|
||||
* Provides default erased-bank check handling. Checks to see if
|
||||
* the flash driver knows they are erased; if things look uncertain,
|
||||
* this routine will call default_flash_mem_blank_check() to confirm.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int default_flash_blank_check(struct flash_bank_s *bank);
|
||||
/**
|
||||
* Provides a default blank flash memory check. Ensures the contents
|
||||
* of the given bank have truly been erased.
|
||||
* @param bank The flash bank.
|
||||
* @returns ERROR_OK if successful; otherwise, an error code.
|
||||
*/
|
||||
extern int default_flash_mem_blank_check(struct flash_bank_s *bank);
|
||||
|
||||
/**
|
||||
* Returns a flash bank by the specified flash_bank_s bank_number, @a num.
|
||||
* @param num The flash bank number.
|
||||
* @returns A flash_bank_t for flash bank @a num, or NULL
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_num(int num);
|
||||
/**
|
||||
* Returns the flash bank like get_flash_bank_by_num(), without probing.
|
||||
* @param num The flash bank number.
|
||||
* @returns A flash_bank_t for flash bank @a num, or NULL.
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_num_noprobe(int num);
|
||||
extern flash_bank_t *get_flash_bank_by_addr(target_t *target, u32 addr);
|
||||
/**
|
||||
* Returns the flash bank located at a specified address.
|
||||
* @param target The target, presumed to contain one or more banks.
|
||||
* @param addr An address that is within the range of the bank.
|
||||
* @returns The flash_bank_t located at @a addr, or NULL.
|
||||
*/
|
||||
extern flash_bank_t *get_flash_bank_by_addr(struct target_s *target, uint32_t addr);
|
||||
|
||||
#define ERROR_FLASH_BANK_INVALID (-900)
|
||||
#define ERROR_FLASH_SECTOR_INVALID (-901)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
|
||||
* didele.deze@gmail.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -17,51 +20,50 @@
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "lpc2000.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "armv4_5.h"
|
||||
#include "algorithm.h"
|
||||
#include "armv7m.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* flash programming support for Philips LPC2xxx devices
|
||||
/* flash programming support for NXP LPC17xx and LPC2xxx devices
|
||||
* currently supported devices:
|
||||
* variant 1 (lpc2000_v1):
|
||||
* - 2104|5|6
|
||||
* - 2114|9
|
||||
* - 2124|9
|
||||
* - 2104 | 5 | 6
|
||||
* - 2114 | 9
|
||||
* - 2124 | 9
|
||||
* - 2194
|
||||
* - 2212|4
|
||||
* - 2292|4
|
||||
* - 2212 | 4
|
||||
* - 2292 | 4
|
||||
*
|
||||
* variant 2 (lpc2000_v2):
|
||||
* - 213x
|
||||
* - 214x
|
||||
* - 2101|2|3
|
||||
* - 2364|6|8
|
||||
* - 2101 | 2 | 3
|
||||
* - 2364 | 6 | 8
|
||||
* - 2378
|
||||
*
|
||||
* lpc1700:
|
||||
* - 175x
|
||||
* - 176x (tested with LPC1768)
|
||||
*/
|
||||
|
||||
int lpc2000_register_commands(struct command_context_s *cmd_ctx);
|
||||
int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int lpc2000_probe(struct flash_bank_s *bank);
|
||||
int lpc2000_erase_check(struct flash_bank_s *bank);
|
||||
int lpc2000_protect_check(struct flash_bank_s *bank);
|
||||
int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int lpc2000_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int lpc2000_probe(struct flash_bank_s *bank);
|
||||
static int lpc2000_erase_check(struct flash_bank_s *bank);
|
||||
static int lpc2000_protect_check(struct flash_bank_s *bank);
|
||||
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t lpc2000_flash =
|
||||
{
|
||||
@@ -78,7 +80,7 @@ flash_driver_t lpc2000_flash =
|
||||
.info = lpc2000_info
|
||||
};
|
||||
|
||||
int lpc2000_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int lpc2000_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
@@ -88,18 +90,17 @@ int lpc2000_register_commands(struct command_context_s *cmd_ctx)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
static int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
int i;
|
||||
uint32_t offset = 0;
|
||||
|
||||
/* default to a 4096 write buffer */
|
||||
lpc2000_info->cmd51_max_buffer = 4096;
|
||||
|
||||
if (lpc2000_info->variant == 1)
|
||||
if (lpc2000_info->variant == lpc2000_v1)
|
||||
{
|
||||
int i = 0;
|
||||
u32 offset = 0;
|
||||
|
||||
/* variant 1 has different layout for 128kb and 256kb flashes */
|
||||
if (bank->size == 128 * 1024)
|
||||
{
|
||||
@@ -150,41 +151,37 @@ int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
else if (lpc2000_info->variant == 2)
|
||||
else if (lpc2000_info->variant == lpc2000_v2)
|
||||
{
|
||||
int num_sectors;
|
||||
int i;
|
||||
u32 offset = 0;
|
||||
|
||||
/* variant 2 has a uniform layout, only number of sectors differs */
|
||||
switch (bank->size)
|
||||
{
|
||||
case 4 * 1024:
|
||||
lpc2000_info->cmd51_max_buffer = 1024;
|
||||
num_sectors = 1;
|
||||
bank->num_sectors = 1;
|
||||
break;
|
||||
case 8 * 1024:
|
||||
lpc2000_info->cmd51_max_buffer = 1024;
|
||||
num_sectors = 2;
|
||||
bank->num_sectors = 2;
|
||||
break;
|
||||
case 16 * 1024:
|
||||
num_sectors = 4;
|
||||
bank->num_sectors = 4;
|
||||
break;
|
||||
case 32 * 1024:
|
||||
num_sectors = 8;
|
||||
bank->num_sectors = 8;
|
||||
break;
|
||||
case 64 * 1024:
|
||||
num_sectors = 9;
|
||||
bank->num_sectors = 9;
|
||||
break;
|
||||
case 128 * 1024:
|
||||
num_sectors = 11;
|
||||
bank->num_sectors = 11;
|
||||
break;
|
||||
case 256 * 1024:
|
||||
num_sectors = 15;
|
||||
bank->num_sectors = 15;
|
||||
break;
|
||||
case 512 * 1024:
|
||||
case 500 * 1024:
|
||||
num_sectors = 27;
|
||||
bank->num_sectors = 27;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||
@@ -192,10 +189,9 @@ int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
break;
|
||||
}
|
||||
|
||||
bank->num_sectors = num_sectors;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
|
||||
for (i = 0; i < num_sectors; i++)
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
if ((i >= 0) && (i < 8))
|
||||
{
|
||||
@@ -223,6 +219,42 @@ int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lpc2000_info->variant == lpc1700)
|
||||
{
|
||||
switch(bank->size)
|
||||
{
|
||||
case 32 * 1024:
|
||||
bank->num_sectors = 8;
|
||||
break;
|
||||
case 64 * 1024:
|
||||
bank->num_sectors = 16;
|
||||
break;
|
||||
case 128 * 1024:
|
||||
bank->num_sectors = 18;
|
||||
break;
|
||||
case 256 * 1024:
|
||||
bank->num_sectors = 22;
|
||||
break;
|
||||
case 512 * 1024:
|
||||
bank->num_sectors = 30;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
|
||||
|
||||
for(i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].offset = offset;
|
||||
/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
|
||||
bank->sectors[i].size = (i < 16)? 4 * 1024 : 32 * 1024;
|
||||
offset += bank->sectors[i].size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
|
||||
@@ -232,83 +264,141 @@ int lpc2000_build_sector_list(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* call LPC2000 IAP function
|
||||
* uses 172 bytes working area
|
||||
/* call LPC1700/LPC2000 IAP function
|
||||
* uses 180 bytes working area
|
||||
* 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
|
||||
* 0x8 to 0x1f: command parameter table
|
||||
* 0x20 to 0x2b: command result table
|
||||
* 0x2c to 0xac: stack (only 128b needed)
|
||||
* 0x8 to 0x1f: command parameter table (1+5 words)
|
||||
* 0x20 to 0x33: command result table (1+4 words)
|
||||
* 0x34 to 0xb3: stack (only 128b needed)
|
||||
*/
|
||||
int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])
|
||||
static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
|
||||
{
|
||||
int retval;
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
mem_param_t mem_params[2];
|
||||
reg_param_t reg_params[5];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
u32 status_code;
|
||||
armv4_5_algorithm_t armv4_5_info; /* for LPC2000 */
|
||||
armv7m_algorithm_t armv7m_info; /* for LPC1700 */
|
||||
uint32_t status_code;
|
||||
uint32_t iap_entry_point = 0; /* to make compiler happier */
|
||||
|
||||
/* regrab previously allocated working_area, or allocate a new one */
|
||||
if (!lpc2000_info->iap_working_area)
|
||||
{
|
||||
u8 jump_gate[8];
|
||||
uint8_t jump_gate[8];
|
||||
|
||||
/* make sure we have a working area */
|
||||
if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)
|
||||
if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* write IAP code to working area */
|
||||
target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
|
||||
if((retval = target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
case lpc1700:
|
||||
target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
|
||||
target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown bank->size encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ((retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
case lpc1700:
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARMV7M_MODE_ANY;
|
||||
iap_entry_point = 0x1fff1ff1;
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
|
||||
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
|
||||
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
|
||||
iap_entry_point = 0x7ffffff1;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown lpc2000->variant encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* command parameter table */
|
||||
init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);
|
||||
init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT);
|
||||
target_buffer_set_u32(target, mem_params[0].value, code);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x4, param_table[0]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x8, param_table[1]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0xc, param_table[2]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
|
||||
target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);
|
||||
|
||||
/* command result table */
|
||||
init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);
|
||||
init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
|
||||
|
||||
/* IAP entry point */
|
||||
init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);
|
||||
|
||||
/* IAP stack */
|
||||
init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);
|
||||
switch(lpc2000_info->variant)
|
||||
{
|
||||
case lpc1700:
|
||||
/* IAP stack */
|
||||
init_reg_param(®_params[3], "sp", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
|
||||
|
||||
/* return address */
|
||||
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);
|
||||
/* return address */
|
||||
init_reg_param(®_params[4], "lr", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
|
||||
|
||||
target->type->run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
|
||||
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
|
||||
break;
|
||||
case lpc2000_v1:
|
||||
case lpc2000_v2:
|
||||
/* IAP stack */
|
||||
init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
|
||||
|
||||
status_code = buf_get_u32(mem_params[1].value, 0, 32);
|
||||
result_table[0] = target_buffer_get_u32(target, mem_params[1].value);
|
||||
result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 4);
|
||||
/* return address */
|
||||
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04);
|
||||
|
||||
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown lpc2000->variant encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
status_code = target_buffer_get_u32(target, mem_params[1].value);
|
||||
result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
|
||||
result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
|
||||
result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
|
||||
result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);
|
||||
|
||||
LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32", 0x%8.8" PRIx32") completed with result = %8.8" PRIx32,
|
||||
code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);
|
||||
|
||||
destroy_mem_param(&mem_params[0]);
|
||||
destroy_mem_param(&mem_params[1]);
|
||||
@@ -322,14 +412,14 @@ int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 resul
|
||||
return status_code;
|
||||
}
|
||||
|
||||
int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
int i;
|
||||
|
||||
if ((first < 0) || (last > bank->num_sectors))
|
||||
if ((first < 0) || (last >= bank->num_sectors))
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
@@ -355,7 +445,7 @@ int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_FLASH_BUSY;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown LPC2000 status code");
|
||||
LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@@ -363,9 +453,10 @@ int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
|
||||
/*
|
||||
* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
|
||||
*/
|
||||
int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info;
|
||||
|
||||
@@ -380,21 +471,31 @@ int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
|
||||
if (strcmp(args[6], "lpc2000_v1") == 0)
|
||||
{
|
||||
lpc2000_info->variant = 1;
|
||||
lpc2000_info->variant = lpc2000_v1;
|
||||
lpc2000_info->cmd51_dst_boundary = 512;
|
||||
lpc2000_info->cmd51_can_256b = 0;
|
||||
lpc2000_info->cmd51_can_8192b = 1;
|
||||
lpc2000_info->checksum_vector = 5;
|
||||
}
|
||||
else if (strcmp(args[6], "lpc2000_v2") == 0)
|
||||
{
|
||||
lpc2000_info->variant = 2;
|
||||
lpc2000_info->variant = lpc2000_v2;
|
||||
lpc2000_info->cmd51_dst_boundary = 256;
|
||||
lpc2000_info->cmd51_can_256b = 1;
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
lpc2000_info->checksum_vector = 5;
|
||||
}
|
||||
else if (strcmp(args[6], "lpc1700") == 0)
|
||||
{
|
||||
lpc2000_info->variant = lpc1700;
|
||||
lpc2000_info->cmd51_dst_boundary = 256;
|
||||
lpc2000_info->cmd51_can_256b = 1;
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
lpc2000_info->checksum_vector = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("unknown LPC2000 variant");
|
||||
LOG_ERROR("unknown LPC2000 variant: %s", args[6]);
|
||||
free(lpc2000_info);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
@@ -413,11 +514,11 @@ int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -465,23 +566,23 @@ int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
/* can't protect/unprotect on the lpc2000 */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 dst_min_alignment;
|
||||
u32 bytes_remaining = count;
|
||||
u32 bytes_written = 0;
|
||||
uint32_t dst_min_alignment;
|
||||
uint32_t bytes_remaining = count;
|
||||
uint32_t bytes_written = 0;
|
||||
int first_sector = 0;
|
||||
int last_sector = 0;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
int i;
|
||||
working_area_t *download_area;
|
||||
@@ -496,14 +597,11 @@ int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
if (offset + count > bank->size)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
|
||||
if (lpc2000_info->cmd51_can_256b)
|
||||
dst_min_alignment = 256;
|
||||
else
|
||||
dst_min_alignment = 512;
|
||||
dst_min_alignment = lpc2000_info->cmd51_dst_boundary;
|
||||
|
||||
if (offset % dst_min_alignment)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
@@ -520,17 +618,26 @@ int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
/* check if exception vectors should be flashed */
|
||||
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
||||
{
|
||||
u32 checksum = 0;
|
||||
int i = 0;
|
||||
uint32_t checksum = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
LOG_DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||
if (i != 5)
|
||||
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||
if (i != lpc2000_info->checksum_vector)
|
||||
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
||||
}
|
||||
checksum = 0 - checksum;
|
||||
LOG_DEBUG("checksum: 0x%8.8x", checksum);
|
||||
buf_set_u32(buffer + 0x14, 0, 32, checksum);
|
||||
LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum);
|
||||
|
||||
uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32);
|
||||
if (original_value != checksum)
|
||||
{
|
||||
LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is different from calculated vector checksum (0x%8.8" PRIx32 ").",
|
||||
original_value, checksum);
|
||||
LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector checksum.");
|
||||
}
|
||||
|
||||
buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum);
|
||||
}
|
||||
|
||||
/* allocate a working area */
|
||||
@@ -542,7 +649,7 @@ int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
u32 thisrun_bytes;
|
||||
uint32_t thisrun_bytes;
|
||||
if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
|
||||
thisrun_bytes = lpc2000_info->cmd51_max_buffer;
|
||||
else if (bytes_remaining >= 1024)
|
||||
@@ -586,16 +693,14 @@ int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *last_buffer = malloc(thisrun_bytes);
|
||||
int i;
|
||||
uint8_t *last_buffer = malloc(thisrun_bytes);
|
||||
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
||||
for (i = bytes_remaining; i < thisrun_bytes; i++)
|
||||
last_buffer[i] = 0xff;
|
||||
memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining);
|
||||
target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer);
|
||||
free(last_buffer);
|
||||
}
|
||||
|
||||
LOG_DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);
|
||||
LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32 , thisrun_bytes, bank->base + offset + bytes_written);
|
||||
|
||||
/* Write data */
|
||||
param_table[0] = bank->base + offset + bytes_written;
|
||||
@@ -635,7 +740,7 @@ int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int lpc2000_probe(struct flash_bank_s *bank)
|
||||
static int lpc2000_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we can't probe on an lpc2000
|
||||
* if this is an lpc2xxx, it has the configured flash
|
||||
@@ -643,7 +748,7 @@ int lpc2000_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
static int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -654,26 +759,26 @@ int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
|
||||
}
|
||||
|
||||
int lpc2000_protect_check(struct flash_bank_s *bank)
|
||||
static int lpc2000_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
/* sectors are always protected */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
|
||||
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
|
||||
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
uint32_t param_table[5];
|
||||
uint32_t result_table[4];
|
||||
int status_code;
|
||||
|
||||
if (argc < 1)
|
||||
@@ -705,7 +810,7 @@ int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);
|
||||
command_print(cmd_ctx, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
|
||||
* didele.deze@gmail.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
@@ -21,18 +24,25 @@
|
||||
#define LPC2000_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
lpc2000_v1,
|
||||
lpc2000_v2,
|
||||
lpc1700
|
||||
} lpc2000_variant;
|
||||
|
||||
typedef struct lpc2000_flash_bank_s
|
||||
{
|
||||
int variant;
|
||||
lpc2000_variant variant;
|
||||
struct working_area_s *iap_working_area;
|
||||
u32 cclk;
|
||||
uint32_t cclk;
|
||||
int cmd51_dst_boundary;
|
||||
int cmd51_can_256b;
|
||||
int cmd51_can_8192b;
|
||||
int calc_checksum;
|
||||
int cmd51_max_buffer;
|
||||
uint32_t cmd51_max_buffer;
|
||||
int checksum_vector;
|
||||
} lpc2000_flash_bank_t;
|
||||
|
||||
enum lpc2000_status_codes
|
||||
@@ -48,7 +58,16 @@ enum lpc2000_status_codes
|
||||
LPC2000_SECTOR_NOT_BLANK = 8,
|
||||
LPC2000_SECTOR_NOT_PREPARED = 9,
|
||||
LPC2000_COMPARE_ERROR = 10,
|
||||
LPC2000_BUSY = 11
|
||||
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
|
||||
|
||||
};
|
||||
|
||||
#endif /* LPC2000_H */
|
||||
|
||||
@@ -31,19 +31,9 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "lpc288x.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LOAD_TIMER_ERASE 0
|
||||
#define LOAD_TIMER_WRITE 1
|
||||
@@ -94,22 +84,19 @@
|
||||
/* F_CLK_TIME */
|
||||
#define FCT_CLK_DIV_MASK 0x0FFF
|
||||
|
||||
int lpc288x_register_commands(struct command_context_s *cmd_ctx);
|
||||
int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int lpc288x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int lpc288x_probe(struct flash_bank_s *bank);
|
||||
int lpc288x_auto_probe(struct flash_bank_s *bank);
|
||||
int lpc288x_erase_check(struct flash_bank_s *bank);
|
||||
int lpc288x_protect_check(struct flash_bank_s *bank);
|
||||
int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
void lpc288x_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode);
|
||||
u32 lpc288x_wait_status_busy(flash_bank_t *bank, int timeout);
|
||||
void lpc288x_load_timer(int erase, struct target_s *target);
|
||||
void lpc288x_set_flash_clk(struct flash_bank_s *bank);
|
||||
u32 lpc288x_system_ready(struct flash_bank_s *bank);
|
||||
int lpc288x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int lpc288x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int lpc288x_probe(struct flash_bank_s *bank);
|
||||
static int lpc288x_erase_check(struct flash_bank_s *bank);
|
||||
static int lpc288x_protect_check(struct flash_bank_s *bank);
|
||||
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout);
|
||||
static void lpc288x_load_timer(int erase, struct target_s *target);
|
||||
static void lpc288x_set_flash_clk(struct flash_bank_s *bank);
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t lpc288x_flash =
|
||||
{
|
||||
@@ -126,23 +113,23 @@ flash_driver_t lpc288x_flash =
|
||||
.info = lpc288x_info
|
||||
};
|
||||
|
||||
int lpc288x_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int lpc288x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
target_t *target = bank->target;
|
||||
do
|
||||
{
|
||||
alive_sleep(1);
|
||||
timeout--;
|
||||
target_read_u32(target, F_STAT, &status);
|
||||
}while (((status & FS_DONE) == 0) && timeout);
|
||||
} while (((status & FS_DONE) == 0) && timeout);
|
||||
|
||||
if(timeout == 0)
|
||||
if (timeout == 0)
|
||||
{
|
||||
LOG_DEBUG("Timedout!");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -151,14 +138,14 @@ u32 lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
}
|
||||
|
||||
/* Read device id register and fill in driver info structure */
|
||||
int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
static int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 cidr;
|
||||
uint32_t cidr;
|
||||
|
||||
int i = 0;
|
||||
u32 offset;
|
||||
uint32_t offset;
|
||||
|
||||
if (lpc288x_info->cidr == 0x0102100A)
|
||||
return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */
|
||||
@@ -168,7 +155,7 @@ int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
|
||||
if (cidr != 0x0102100A)
|
||||
{
|
||||
LOG_WARNING("Cannot identify target as an LPC288X (%08X)",cidr);
|
||||
LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")",cidr);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -201,13 +188,13 @@ int lpc288x_read_part_info(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_protect_check(struct flash_bank_s *bank)
|
||||
static int lpc288x_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
|
||||
int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info;
|
||||
|
||||
@@ -227,14 +214,14 @@ int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* The frequency is the AHB clock frequency divided by (CLK_DIV ×3) + 1.
|
||||
* This must be programmed such that the Flash Programming clock frequency is 66 kHz ± 20%.
|
||||
/* The frequency is the AHB clock frequency divided by (CLK_DIV ×3) + 1.
|
||||
* This must be programmed such that the Flash Programming clock frequency is 66 kHz ± 20%.
|
||||
* AHB = 12 MHz ?
|
||||
* 12000000/66000 = 182
|
||||
* CLK_DIV = 60 ? */
|
||||
void lpc288x_set_flash_clk(struct flash_bank_s *bank)
|
||||
static void lpc288x_set_flash_clk(struct flash_bank_s *bank)
|
||||
{
|
||||
u32 clk_time;
|
||||
uint32_t clk_time;
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
clk_time = (lpc288x_info->cclk / 66000) / 3;
|
||||
target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
|
||||
@@ -243,11 +230,11 @@ void lpc288x_set_flash_clk(struct flash_bank_s *bank)
|
||||
|
||||
/* AHB tcyc (in ns) 83 ns
|
||||
* LOAD_TIMER_ERASE FPT_TIME = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512
|
||||
* = 9412 (9500) (AN10548 9375)
|
||||
* = 9412 (9500) (AN10548 9375)
|
||||
* LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
|
||||
* = 23 (75) (AN10548 72 - is this wrong?)
|
||||
* = 23 (75) (AN10548 72 - is this wrong?)
|
||||
* TODO: Sort out timing calcs ;) */
|
||||
void lpc288x_load_timer(int erase, struct target_s *target)
|
||||
static void lpc288x_load_timer(int erase, struct target_s *target)
|
||||
{
|
||||
if (erase == LOAD_TIMER_ERASE)
|
||||
{
|
||||
@@ -259,7 +246,7 @@ void lpc288x_load_timer(int erase, struct target_s *target)
|
||||
}
|
||||
}
|
||||
|
||||
u32 lpc288x_system_ready(struct flash_bank_s *bank)
|
||||
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank)
|
||||
{
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
if (lpc288x_info->cidr == 0)
|
||||
@@ -275,9 +262,9 @@ u32 lpc288x_system_ready(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_erase_check(struct flash_bank_s *bank)
|
||||
static int lpc288x_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
u32 status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
|
||||
if (status != ERROR_OK)
|
||||
{
|
||||
LOG_INFO("Processor not halted/not probed");
|
||||
@@ -287,9 +274,9 @@ int lpc288x_erase_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
int sector;
|
||||
target_t *target = bank->target;
|
||||
|
||||
@@ -328,13 +315,14 @@ int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
u8 page_buffer[FLASH_PAGE_SIZE];
|
||||
u32 i, status, source_offset,dest_offset;
|
||||
uint8_t page_buffer[FLASH_PAGE_SIZE];
|
||||
uint32_t status, source_offset,dest_offset;
|
||||
target_t *target = bank->target;
|
||||
u32 bytes_remaining = count;
|
||||
u32 first_sector, last_sector, sector, page;
|
||||
uint32_t bytes_remaining = count;
|
||||
uint32_t first_sector, last_sector, sector, page;
|
||||
int i;
|
||||
|
||||
/* probed? halted? */
|
||||
status = lpc288x_system_ready(bank);
|
||||
@@ -357,7 +345,7 @@ int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
/* all writes must start on a sector boundary... */
|
||||
if (offset % bank->sectors[i].size)
|
||||
{
|
||||
LOG_INFO("offset 0x%x breaks required alignment 0x%x", offset, bank->sectors[i].size);
|
||||
LOG_INFO("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
}
|
||||
@@ -372,7 +360,7 @@ int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
/* Range check... */
|
||||
if (first_sector == 0xffffffff || last_sector == 0xffffffff)
|
||||
{
|
||||
LOG_INFO("Range check failed %x %x", offset, count);
|
||||
LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
}
|
||||
|
||||
@@ -418,9 +406,9 @@ int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
* it seems not to be a LOT slower....
|
||||
* bulk_write_memory() is no quicker :(*/
|
||||
#if 1
|
||||
if (target->type->write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)
|
||||
if (target_write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("Write failed s %x p %x", sector, page);
|
||||
LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
#else
|
||||
@@ -443,7 +431,7 @@ int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_probe(struct flash_bank_s *bank)
|
||||
static int lpc288x_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we only deal with LPC2888 so flash config is fixed */
|
||||
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
|
||||
@@ -466,16 +454,16 @@ int lpc288x_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "lpc288x flash driver");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
int lockregion, status;
|
||||
u32 value;
|
||||
uint32_t value;
|
||||
target_t *target = bank->target;
|
||||
|
||||
/* probed? halted? */
|
||||
|
||||
@@ -22,19 +22,18 @@
|
||||
#define lpc288x_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct lpc288x_flash_bank_s
|
||||
{
|
||||
u32 working_area;
|
||||
u32 working_area_size;
|
||||
uint32_t working_area;
|
||||
uint32_t working_area_size;
|
||||
|
||||
/* chip id register */
|
||||
u32 cidr;
|
||||
uint32_t cidr;
|
||||
char * target_name;
|
||||
u32 cclk;
|
||||
uint32_t cclk;
|
||||
|
||||
u32 sector_size_break;
|
||||
uint32_t sector_size_break;
|
||||
} lpc288x_flash_bank_t;
|
||||
|
||||
#endif /* lpc288x_H */
|
||||
|
||||
1928
src/flash/lpc2900.c
Normal file
1928
src/flash/lpc2900.c
Normal file
File diff suppressed because it is too large
Load Diff
27
src/flash/lpc2900.h
Normal file
27
src/flash/lpc2900.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by *
|
||||
* Rolf Meeser <rolfm_9dq@yahoo.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 lpc2900_H
|
||||
#define lpc2900_H
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
|
||||
#endif /* lpc2900_H */
|
||||
@@ -22,30 +22,22 @@
|
||||
#endif
|
||||
|
||||
#include "lpc3180_nand_controller.h"
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "target.h"
|
||||
|
||||
int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int lpc3180_register_commands(struct command_context_s *cmd_ctx);
|
||||
int lpc3180_init(struct nand_device_s *device);
|
||||
int lpc3180_reset(struct nand_device_s *device);
|
||||
int lpc3180_command(struct nand_device_s *device, u8 command);
|
||||
int lpc3180_address(struct nand_device_s *device, u8 address);
|
||||
int lpc3180_write_data(struct nand_device_s *device, u16 data);
|
||||
int lpc3180_read_data(struct nand_device_s *device, void *data);
|
||||
int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
|
||||
int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
|
||||
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int lpc3180_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int lpc3180_init(struct nand_device_s *device);
|
||||
static int lpc3180_reset(struct nand_device_s *device);
|
||||
static int lpc3180_command(struct nand_device_s *device, uint8_t command);
|
||||
static int lpc3180_address(struct nand_device_s *device, uint8_t address);
|
||||
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data);
|
||||
static int lpc3180_read_data(struct nand_device_s *device, void *data);
|
||||
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
|
||||
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
nand_flash_controller_t lpc3180_nand_controller =
|
||||
{
|
||||
@@ -66,7 +58,7 @@ nand_flash_controller_t lpc3180_nand_controller =
|
||||
|
||||
/* nand device lpc3180 <target#> <oscillator_frequency>
|
||||
*/
|
||||
int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
|
||||
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info;
|
||||
|
||||
@@ -79,10 +71,10 @@ int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));
|
||||
device->controller_priv = lpc3180_info;
|
||||
|
||||
lpc3180_info->target = get_target_by_num(strtoul(args[1], NULL, 0));
|
||||
lpc3180_info->target = get_target(args[1]);
|
||||
if (!lpc3180_info->target)
|
||||
{
|
||||
LOG_ERROR("no target '%s' configured", args[1]);
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
@@ -99,7 +91,7 @@ int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, ch
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int lpc3180_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");
|
||||
|
||||
@@ -108,7 +100,7 @@ int lpc3180_register_commands(struct command_context_s *cmd_ctx)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_pll(int fclkin, u32 pll_ctrl)
|
||||
static int lpc3180_pll(int fclkin, uint32_t pll_ctrl)
|
||||
{
|
||||
int bypass = (pll_ctrl & 0x8000) >> 15;
|
||||
int direct = (pll_ctrl & 0x4000) >> 14;
|
||||
@@ -136,10 +128,10 @@ int lpc3180_pll(int fclkin, u32 pll_ctrl)
|
||||
return (m / (2 * p)) * (fclkin / n);
|
||||
}
|
||||
|
||||
float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
|
||||
static float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
|
||||
{
|
||||
target_t *target = lpc3180_info->target;
|
||||
u32 sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
|
||||
uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
|
||||
int sysclk;
|
||||
int hclk;
|
||||
int hclk_pll;
|
||||
@@ -186,7 +178,7 @@ float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
|
||||
return cycle;
|
||||
}
|
||||
|
||||
int lpc3180_init(struct nand_device_s *device)
|
||||
static int lpc3180_init(struct nand_device_s *device)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -239,7 +231,7 @@ int lpc3180_init(struct nand_device_s *device)
|
||||
|
||||
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
u32 mlc_icr_value = 0x0;
|
||||
uint32_t mlc_icr_value = 0x0;
|
||||
float cycle;
|
||||
int twp, twh, trp, treh, trhz, trbwb, tcea;
|
||||
|
||||
@@ -316,7 +308,7 @@ int lpc3180_init(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_reset(struct nand_device_s *device)
|
||||
static int lpc3180_reset(struct nand_device_s *device)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -358,7 +350,7 @@ int lpc3180_reset(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_command(struct nand_device_s *device, u8 command)
|
||||
static int lpc3180_command(struct nand_device_s *device, uint8_t command)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -388,7 +380,7 @@ int lpc3180_command(struct nand_device_s *device, u8 command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_address(struct nand_device_s *device, u8 address)
|
||||
static int lpc3180_address(struct nand_device_s *device, uint8_t address)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -418,7 +410,7 @@ int lpc3180_address(struct nand_device_s *device, u8 address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_write_data(struct nand_device_s *device, u16 data)
|
||||
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -448,7 +440,7 @@ int lpc3180_write_data(struct nand_device_s *device, u16 data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
static int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -469,12 +461,12 @@ int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
/* data = MLC_DATA, use sized access */
|
||||
if (device->bus_width == 8)
|
||||
{
|
||||
u8 *data8 = data;
|
||||
uint8_t *data8 = data;
|
||||
target_read_u8(target, 0x200b0000, data8);
|
||||
}
|
||||
else if (device->bus_width == 16)
|
||||
{
|
||||
u16 *data16 = data;
|
||||
uint16_t *data16 = data;
|
||||
target_read_u16(target, 0x200b0000, data16);
|
||||
}
|
||||
else
|
||||
@@ -485,19 +477,19 @@ int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
u32 data32;
|
||||
uint32_t data32;
|
||||
|
||||
/* data = SLC_DATA, must use 32-bit access */
|
||||
target_read_u32(target, 0x20020000, &data32);
|
||||
|
||||
if (device->bus_width == 8)
|
||||
{
|
||||
u8 *data8 = data;
|
||||
uint8_t *data8 = data;
|
||||
*data8 = data32 & 0xff;
|
||||
}
|
||||
else if (device->bus_width == 16)
|
||||
{
|
||||
u16 *data16 = data;
|
||||
uint16_t *data16 = data;
|
||||
*data16 = data32 & 0xffff;
|
||||
}
|
||||
else
|
||||
@@ -510,12 +502,12 @@ int lpc3180_read_data(struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
int retval;
|
||||
u8 status;
|
||||
uint8_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -530,8 +522,8 @@ int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
u8 *page_buffer;
|
||||
u8 *oob_buffer;
|
||||
uint8_t *page_buffer;
|
||||
uint8_t *oob_buffer;
|
||||
int quarter, num_quarters;
|
||||
|
||||
if (!data && oob)
|
||||
@@ -546,7 +538,7 @@ int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (data_size > device->page_size)
|
||||
if (data_size > (uint32_t)device->page_size)
|
||||
{
|
||||
LOG_ERROR("data size exceeds page size");
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
@@ -610,8 +602,8 @@ int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
/* write MLC_ECC_ENC_REG to start encode cycle */
|
||||
target_write_u32(target, 0x200b8008, 0x0);
|
||||
|
||||
target->type->write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
|
||||
target->type->write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
|
||||
target_write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
|
||||
target_write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
|
||||
|
||||
/* write MLC_ECC_AUTO_ENC_REG to start auto encode */
|
||||
target_write_u32(target, 0x200b8010, 0x0);
|
||||
@@ -649,7 +641,7 @@ int lpc3180_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -667,11 +659,11 @@ int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
u8 *page_buffer;
|
||||
u8 *oob_buffer;
|
||||
u32 page_bytes_done = 0;
|
||||
u32 oob_bytes_done = 0;
|
||||
u32 mlc_isr;
|
||||
uint8_t *page_buffer;
|
||||
uint8_t *oob_buffer;
|
||||
uint32_t page_bytes_done = 0;
|
||||
uint32_t oob_bytes_done = 0;
|
||||
uint32_t mlc_isr;
|
||||
|
||||
#if 0
|
||||
if (oob && (oob_size > 6))
|
||||
@@ -681,7 +673,7 @@ int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data_size > device->page_size)
|
||||
if (data_size > (uint32_t)device->page_size)
|
||||
{
|
||||
LOG_ERROR("data size exceeds page size");
|
||||
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
|
||||
@@ -741,7 +733,7 @@ int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data
|
||||
target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);
|
||||
}
|
||||
|
||||
while (page_bytes_done < device->page_size)
|
||||
while (page_bytes_done < (uint32_t)device->page_size)
|
||||
{
|
||||
/* MLC_ECC_AUTO_DEC_REG = dummy */
|
||||
target_write_u32(target, 0x200b8014, 0xaa55aa55);
|
||||
@@ -758,21 +750,21 @@ int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data
|
||||
{
|
||||
if (mlc_isr & 0x40)
|
||||
{
|
||||
LOG_ERROR("uncorrectable error detected: 0x%2.2x", mlc_isr);
|
||||
LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_WARNING("%i symbol error detected and corrected", ((mlc_isr & 0x30) >> 4) + 1);
|
||||
LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1)));
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
target->type->read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);
|
||||
target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);
|
||||
}
|
||||
|
||||
if (oob)
|
||||
{
|
||||
target->type->read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);
|
||||
target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);
|
||||
}
|
||||
|
||||
page_bytes_done += 512;
|
||||
@@ -796,11 +788,11 @@ int lpc3180_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
u8 status = 0x0;
|
||||
uint8_t status = 0x0;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -830,7 +822,7 @@ int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
|
||||
target_t *target = lpc3180_info->target;
|
||||
@@ -845,7 +837,7 @@ int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
|
||||
{
|
||||
u8 status = 0x0;
|
||||
uint8_t status = 0x0;
|
||||
|
||||
/* Read MLC_ISR, wait for NAND flash device to become ready */
|
||||
target_read_u8(target, 0x200b8048, &status);
|
||||
@@ -855,7 +847,7 @@ int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
}
|
||||
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
|
||||
{
|
||||
u32 status = 0x0;
|
||||
uint32_t status = 0x0;
|
||||
|
||||
/* Read SLC_STAT and check READY bit */
|
||||
target_read_u32(target, 0x20020018, &status);
|
||||
@@ -870,7 +862,7 @@ int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *device = NULL;
|
||||
lpc3180_nand_controller_t *lpc3180_info = NULL;
|
||||
|
||||
@@ -35,8 +35,8 @@ typedef struct lpc3180_nand_controller_s
|
||||
int osc_freq;
|
||||
enum lpc3180_selected_controller selected_controller;
|
||||
int sw_write_protection;
|
||||
u32 sw_wp_lower_bound;
|
||||
u32 sw_wp_upper_bound;
|
||||
uint32_t sw_wp_lower_bound;
|
||||
uint32_t sw_wp_upper_bound;
|
||||
} lpc3180_nand_controller_t;
|
||||
|
||||
#endif /*LPC3180_NAND_CONTROLLER_H */
|
||||
|
||||
1090
src/flash/mflash.c
1090
src/flash/mflash.c
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,8 @@
|
||||
#ifndef _MFLASH_H
|
||||
#define _MFLASH_H
|
||||
|
||||
#include "target.h"
|
||||
|
||||
typedef unsigned long mg_io_uint32;
|
||||
typedef unsigned short mg_io_uint16;
|
||||
typedef unsigned char mg_io_uint8;
|
||||
@@ -34,7 +36,7 @@ typedef struct mflash_gpio_drv_s
|
||||
{
|
||||
char *name;
|
||||
int (*set_gpio_to_output) (mflash_gpio_num_t gpio);
|
||||
int (*set_gpio_output_val) (mflash_gpio_num_t gpio, u8 val);
|
||||
int (*set_gpio_output_val) (mflash_gpio_num_t gpio, uint8_t val);
|
||||
} mflash_gpio_drv_t;
|
||||
|
||||
typedef struct _mg_io_type_drv_info {
|
||||
@@ -46,7 +48,7 @@ typedef struct _mg_io_type_drv_info {
|
||||
mg_io_uint16 unformatted_bytes_per_track; /* 04 */
|
||||
mg_io_uint16 unformatted_bytes_per_sector; /* 05 */
|
||||
mg_io_uint16 sectors_per_track; /* 06 */
|
||||
mg_io_uint8 vendor_unique1[6]; /* 07/08/09 */
|
||||
mg_io_uint16 vendor_unique1[3]; /* 07/08/09 */
|
||||
|
||||
mg_io_uint8 serial_number[20]; /* 10~19 */
|
||||
|
||||
@@ -115,26 +117,28 @@ typedef struct _mg_io_type_drv_info {
|
||||
|
||||
} mg_io_type_drv_info;
|
||||
|
||||
typedef struct _mg_pll_t
|
||||
{
|
||||
unsigned int lock_cyc;
|
||||
unsigned short feedback_div; /* 9bit divider */
|
||||
unsigned char input_div; /* 5bit divider */
|
||||
unsigned char output_div; /* 2bit divider */
|
||||
} mg_pll_t;
|
||||
|
||||
typedef struct mg_drv_info_s {
|
||||
mg_io_type_drv_info drv_id;
|
||||
u32 tot_sects;
|
||||
uint32_t tot_sects;
|
||||
} mg_drv_info_t;
|
||||
|
||||
typedef struct mflash_bank_s
|
||||
{
|
||||
u32 base;
|
||||
u32 chip_width;
|
||||
u32 bus_width;
|
||||
uint32_t base;
|
||||
|
||||
mflash_gpio_num_t rst_pin;
|
||||
mflash_gpio_num_t wp_pin;
|
||||
mflash_gpio_num_t dpd_pin;
|
||||
|
||||
mflash_gpio_drv_t *gpio_drv;
|
||||
target_t *target;
|
||||
mg_drv_info_t *drv_info;
|
||||
|
||||
u8 proved;
|
||||
} mflash_bank_t;
|
||||
|
||||
extern int mflash_register_commands(struct command_context_s *cmd_ctx);
|
||||
@@ -162,6 +166,25 @@ extern int mflash_init_drivers(struct command_context_s *cmd_ctx);
|
||||
#define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 /* msec */
|
||||
#define MG_OEM_DISK_WAIT_TIME_SHORT 1000 /* msec */
|
||||
|
||||
#define MG_PLL_CLK_OUT 66000000.0 /* 66Mhz */
|
||||
#define MG_PLL_MAX_FEEDBACKDIV_VAL 512
|
||||
#define MG_PLL_MAX_INPUTDIV_VAL 32
|
||||
#define MG_PLL_MAX_OUTPUTDIV_VAL 4
|
||||
|
||||
#define MG_PLL_STD_INPUTCLK 12000000.0 /* 12Mhz */
|
||||
#define MG_PLL_STD_LOCKCYCLE 10000
|
||||
|
||||
#define MG_UNLOCK_OTP_AREA 0xFF
|
||||
|
||||
#define MG_FILEIO_CHUNK 1048576
|
||||
|
||||
#define ERROR_MG_IO (-1600)
|
||||
#define ERROR_MG_TIMEOUT (-1601)
|
||||
#define ERROR_MG_INVALID_PLL (-1603)
|
||||
#define ERROR_MG_INTERFACE (-1604)
|
||||
#define ERROR_MG_INVALID_OSC (-1605)
|
||||
#define ERROR_MG_UNSUPPORTED_SOC (-1606)
|
||||
|
||||
typedef enum _mg_io_type_wait{
|
||||
|
||||
mg_io_wait_bsy = 1,
|
||||
@@ -242,4 +265,37 @@ typedef enum _mg_io_type_cmd
|
||||
|
||||
} mg_io_type_cmd;
|
||||
|
||||
typedef enum _mg_feature_id
|
||||
{
|
||||
mg_feature_id_transmode = 0x3
|
||||
} mg_feature_id;
|
||||
|
||||
typedef enum _mg_feature_val
|
||||
{
|
||||
mg_feature_val_trans_default = 0x0,
|
||||
mg_feature_val_trans_vcmd = 0x3,
|
||||
mg_feature_val_trand_vcmds = 0x2
|
||||
} mg_feature_val;
|
||||
|
||||
typedef enum _mg_vcmd
|
||||
{
|
||||
mg_vcmd_update_xipinfo = 0xFA, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_verify_fwpatch = 0xFB, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_update_stgdrvinfo = 0xFC, /* IOM identificatin info program command */
|
||||
mg_vcmd_prep_fwpatch = 0xFD, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_exe_fwpatch = 0xFE, /* FWPATCH commmand through IOM I/O */
|
||||
mg_vcmd_wr_pll = 0x8B,
|
||||
mg_vcmd_purge_nand = 0x8C, /* Only for Seagle */
|
||||
mg_vcmd_lock_otp = 0x8D,
|
||||
mg_vcmd_rd_otp = 0x8E,
|
||||
mg_vcmd_wr_otp = 0x8F
|
||||
} mg_vcmd;
|
||||
|
||||
typedef enum _mg_opmode
|
||||
{
|
||||
mg_op_mode_xip = 1, /* TRUE XIP */
|
||||
mg_op_mode_snd = 2, /* BOOT + Storage */
|
||||
mg_op_mode_stg = 0 /* Only Storage */
|
||||
} mg_opmode;
|
||||
|
||||
#endif
|
||||
|
||||
902
src/flash/mx3_nand.c
Normal file
902
src/flash/mx3_nand.c
Normal file
@@ -0,0 +1,902 @@
|
||||
|
||||
/***************************************************************************
|
||||
* 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 iMX3* OpenOCD NAND Flash controller support.
|
||||
*
|
||||
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||
*/
|
||||
|
||||
/*
|
||||
driver tested with STMicro NAND512W3A @imx31
|
||||
tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", "nand write # file 0"
|
||||
get_next_halfword_from_sram_buffer() not tested
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mx3_nand.h"
|
||||
|
||||
static const char target_not_halted_err_msg[] =
|
||||
"target must be halted to use mx3 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;
|
||||
unsigned char sign_of_sequental_byte_read;
|
||||
|
||||
static int test_iomux_settings (target_t * target, uint32_t value,
|
||||
uint32_t mask, const char *text);
|
||||
static int initialize_nf_controller (struct nand_device_s *device);
|
||||
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value);
|
||||
static int get_next_halfword_from_sram_buffer (target_t * target,
|
||||
uint16_t * value);
|
||||
static int poll_for_complete_op (target_t * target, const char *text);
|
||||
static int validate_target_state (struct nand_device_s *device);
|
||||
static int do_data_output (struct nand_device_s *device);
|
||||
|
||||
static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct nand_device_s *device);
|
||||
static int imx31_init (struct nand_device_s *device);
|
||||
static int imx31_read_data (struct nand_device_s *device, void *data);
|
||||
static int imx31_write_data (struct nand_device_s *device, uint16_t data);
|
||||
static int imx31_nand_ready (struct nand_device_s *device, int timeout);
|
||||
static int imx31_register_commands (struct command_context_s *cmd_ctx);
|
||||
static int imx31_reset (struct nand_device_s *device);
|
||||
static int imx31_command (struct nand_device_s *device, uint8_t command);
|
||||
static int imx31_address (struct nand_device_s *device, uint8_t address);
|
||||
static int imx31_controller_ready (struct nand_device_s *device, int tout);
|
||||
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size);
|
||||
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size);
|
||||
|
||||
nand_flash_controller_t imx31_nand_flash_controller = {
|
||||
.name = "imx31",
|
||||
.nand_device_command = imx31_nand_device_command,
|
||||
.register_commands = imx31_register_commands,
|
||||
.init = imx31_init,
|
||||
.reset = imx31_reset,
|
||||
.command = imx31_command,
|
||||
.address = imx31_address,
|
||||
.write_data = imx31_write_data,
|
||||
.read_data = imx31_read_data,
|
||||
.write_page = imx31_write_page,
|
||||
.read_page = imx31_read_page,
|
||||
.controller_ready = imx31_controller_ready,
|
||||
.nand_ready = imx31_nand_ready,
|
||||
};
|
||||
|
||||
static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
|
||||
char *cmd, char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info;
|
||||
mx3_nf_info = malloc (sizeof (mx3_nf_controller_t));
|
||||
if (mx3_nf_info == NULL)
|
||||
{
|
||||
LOG_ERROR ("no memory for nand controller");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
device->controller_priv = mx3_nf_info;
|
||||
|
||||
mx3_nf_info->target = get_target (args[1]);
|
||||
if (mx3_nf_info->target == NULL)
|
||||
{
|
||||
LOG_ERROR ("target '%s' not defined", args[1]);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (argc < 3)
|
||||
{
|
||||
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
/*
|
||||
* check hwecc requirements
|
||||
*/
|
||||
{
|
||||
int hwecc_needed;
|
||||
hwecc_needed = strcmp (args[2], "hwecc");
|
||||
if (hwecc_needed == 0)
|
||||
{
|
||||
mx3_nf_info->flags.hw_ecc_enabled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx3_nf_info->flags.hw_ecc_enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
||||
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
||||
mx3_nf_info->flags.target_little_endian =
|
||||
(mx3_nf_info->target->endianness == TARGET_LITTLE_ENDIAN);
|
||||
/*
|
||||
* testing host endianess
|
||||
*/
|
||||
{
|
||||
int x = 1;
|
||||
if (*(char *) &x == 1)
|
||||
{
|
||||
mx3_nf_info->flags.host_little_endian = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx3_nf_info->flags.host_little_endian = 0;
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_init (struct nand_device_s *device)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint16_t buffsize_register_content;
|
||||
target_read_u16 (target, MX3_NF_BUFSIZ, &buffsize_register_content);
|
||||
mx3_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t pcsr_register_content;
|
||||
target_read_u32 (target, MX3_PCSR, &pcsr_register_content);
|
||||
if (!device->bus_width)
|
||||
{
|
||||
device->bus_width =
|
||||
(pcsr_register_content & 0x80000000) ? 16 : 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcsr_register_content |=
|
||||
((device->bus_width == 16) ? 0x80000000 : 0x00000000);
|
||||
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
|
||||
}
|
||||
|
||||
if (!device->page_size)
|
||||
{
|
||||
device->page_size =
|
||||
(pcsr_register_content & 0x40000000) ? 2048 : 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcsr_register_content |=
|
||||
((device->page_size == 2048) ? 0x40000000 : 0x00000000);
|
||||
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
|
||||
}
|
||||
if (mx3_nf_info->flags.one_kb_sram && (device->page_size == 2048))
|
||||
{
|
||||
LOG_ERROR
|
||||
("NAND controller have only 1 kb SRAM, so pagesize 2048 is incompatible with it");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t cgr_register_content;
|
||||
target_read_u32 (target, MX3_CCM_CGR2, &cgr_register_content);
|
||||
if (!(cgr_register_content & 0x00000300))
|
||||
{
|
||||
LOG_ERROR ("clock gating to EMI disabled");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t gpr_register_content;
|
||||
target_read_u32 (target, MX3_GPR, &gpr_register_content);
|
||||
if (gpr_register_content & 0x00000060)
|
||||
{
|
||||
LOG_ERROR ("pins mode overrided by GPR");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* testing IOMUX settings; must be in "functional-mode output and
|
||||
* functional-mode input" mode
|
||||
*/
|
||||
int test_iomux;
|
||||
test_iomux = ERROR_OK;
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7");
|
||||
if (device->bus_width == 16)
|
||||
{
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00,
|
||||
"d8,d9,d10");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0cc, 0x7f7f7f7f,
|
||||
"d11,d12,d13,d14");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0d0, 0x0000007f, "d15");
|
||||
}
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0d0, 0x7f7f7f00,
|
||||
"nfwp,nfce,nfrb");
|
||||
test_iomux |=
|
||||
test_iomux_settings (target, 0x43fac0d4, 0x7f7f7f7f,
|
||||
"nfwe,nfre,nfale,nfcle");
|
||||
if (test_iomux != ERROR_OK)
|
||||
{
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
initialize_nf_controller (device);
|
||||
|
||||
{
|
||||
int retval;
|
||||
uint16_t nand_status_content;
|
||||
retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_STATUS);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= do_data_output (device);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR (get_status_register_err_msg);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
||||
if (!(nand_status_content & 0x0080))
|
||||
{
|
||||
/*
|
||||
* is host-big-endian correctly ??
|
||||
*/
|
||||
LOG_INFO ("NAND read-only");
|
||||
mx3_nf_info->flags.nand_readonly = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx3_nf_info->flags.nand_readonly = 0;
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_read_data (struct nand_device_s *device, void *data)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* get data from nand chip
|
||||
*/
|
||||
int try_data_output_from_nand_chip;
|
||||
try_data_output_from_nand_chip = do_data_output (device);
|
||||
if (try_data_output_from_nand_chip != ERROR_OK)
|
||||
{
|
||||
return try_data_output_from_nand_chip;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->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 imx31_write_data (struct nand_device_s *device, uint16_t data)
|
||||
{
|
||||
LOG_ERROR ("write_data() not implemented");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
static int imx31_nand_ready (struct nand_device_s *device, int timeout)
|
||||
{
|
||||
return imx31_controller_ready (device, timeout);
|
||||
}
|
||||
|
||||
static int imx31_register_commands (struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_reset (struct nand_device_s *device)
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
initialize_nf_controller (device);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_command (struct nand_device_s *device, uint8_t command)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case NAND_CMD_READOOB:
|
||||
command = NAND_CMD_READ0;
|
||||
in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for
|
||||
* data_read() and
|
||||
* read_block_data() to
|
||||
* spare area in SRAM
|
||||
* buffer */
|
||||
break;
|
||||
case NAND_CMD_READ1:
|
||||
command = NAND_CMD_READ0;
|
||||
/*
|
||||
* offset == one half of page size
|
||||
*/
|
||||
in_sram_address =
|
||||
MX3_NF_MAIN_BUFFER0 + (device->page_size >> 1);
|
||||
default:
|
||||
in_sram_address = MX3_NF_MAIN_BUFFER0;
|
||||
}
|
||||
|
||||
target_write_u16 (target, MX3_NF_FCMD, command);
|
||||
/*
|
||||
* start command input operation (set MX3_NF_BIT_OP_DONE==0)
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FCI);
|
||||
{
|
||||
int poll_result;
|
||||
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;
|
||||
switch (command)
|
||||
{
|
||||
case NAND_CMD_READID:
|
||||
mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID;
|
||||
mx3_nf_info->fin = MX3_NF_FIN_DATAOUT;
|
||||
break;
|
||||
case NAND_CMD_STATUS:
|
||||
mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS;
|
||||
mx3_nf_info->fin = MX3_NF_FIN_DATAOUT;
|
||||
break;
|
||||
case NAND_CMD_READ0:
|
||||
mx3_nf_info->fin = MX3_NF_FIN_DATAOUT;
|
||||
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
||||
break;
|
||||
default:
|
||||
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_address (struct nand_device_s *device, uint8_t address)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
}
|
||||
|
||||
target_write_u16 (target, MX3_NF_FADDR, address);
|
||||
/*
|
||||
* start address input operation (set MX3_NF_BIT_OP_DONE==0)
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FAI);
|
||||
{
|
||||
int poll_result;
|
||||
poll_result = poll_for_complete_op (target, "address");
|
||||
if (poll_result != ERROR_OK)
|
||||
{
|
||||
return poll_result;
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_controller_ready (struct nand_device_s *device, int tout)
|
||||
{
|
||||
uint16_t poll_complete_status;
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
|
||||
{
|
||||
/*
|
||||
* validate target state
|
||||
*/
|
||||
int validate_target_result;
|
||||
validate_target_result = validate_target_state (device);
|
||||
if (validate_target_result != ERROR_OK)
|
||||
{
|
||||
return validate_target_result;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status);
|
||||
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
||||
{
|
||||
return tout;
|
||||
}
|
||||
alive_sleep (1);
|
||||
}
|
||||
while (tout-- > 0);
|
||||
return tout;
|
||||
}
|
||||
|
||||
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
|
||||
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
|
||||
*/
|
||||
int retval;
|
||||
retval = validate_target_state (device);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_SEQIN);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= imx31_address (device, page & 0xff);
|
||||
retval |= imx31_address (device, (page >> 8) & 0xff);
|
||||
if (device->address_cycles >= 4)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 16) & 0xff);
|
||||
if (device->address_cycles >= 5)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
target_write_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, data);
|
||||
if (oob)
|
||||
{
|
||||
if (mx3_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, MX3_NF_SPARE_BUFFER0, oob_size,
|
||||
oob);
|
||||
}
|
||||
/*
|
||||
* start data input operation (set MX3_NF_BIT_OP_DONE==0)
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_OP_FDI);
|
||||
{
|
||||
int poll_result;
|
||||
poll_result = poll_for_complete_op (target, "data input");
|
||||
if (poll_result != ERROR_OK)
|
||||
{
|
||||
return poll_result;
|
||||
}
|
||||
}
|
||||
retval |= imx31_command (device, NAND_CMD_PAGEPROG);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* check status register
|
||||
*/
|
||||
{
|
||||
uint16_t nand_status_content;
|
||||
retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_STATUS);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= do_data_output (device);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR (get_status_register_err_msg);
|
||||
return retval;
|
||||
}
|
||||
target_read_u16 (target, MX3_NF_MAIN_BUFFER0, &nand_status_content);
|
||||
if (nand_status_content & 0x0001)
|
||||
{
|
||||
/*
|
||||
* is host-big-endian correctly ??
|
||||
*/
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
|
||||
uint8_t * data, uint32_t data_size, uint8_t * oob,
|
||||
uint32_t oob_size)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
|
||||
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
|
||||
*/
|
||||
int retval;
|
||||
retval = validate_target_state (device);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
retval |= imx31_command (device, NAND_CMD_READ0);
|
||||
retval |= imx31_address (device, 0x00);
|
||||
retval |= imx31_address (device, page & 0xff);
|
||||
retval |= imx31_address (device, (page >> 8) & 0xff);
|
||||
if (device->address_cycles >= 4)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 16) & 0xff);
|
||||
if (device->address_cycles >= 5)
|
||||
{
|
||||
retval |= imx31_address (device, (page >> 24) & 0xff);
|
||||
retval |= imx31_command (device, NAND_CMD_READSTART);
|
||||
}
|
||||
}
|
||||
retval |= do_data_output (device);
|
||||
if (retval != ERROR_OK)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
target_read_buffer (target, MX3_NF_MAIN_BUFFER0, data_size,
|
||||
data);
|
||||
}
|
||||
if (oob)
|
||||
{
|
||||
target_read_buffer (target, MX3_NF_SPARE_BUFFER0, oob_size,
|
||||
oob);
|
||||
}
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int test_iomux_settings (target_t * target, uint32_t address,
|
||||
uint32_t mask, const char *text)
|
||||
{
|
||||
uint32_t register_content;
|
||||
target_read_u32 (target, address, ®ister_content);
|
||||
if ((register_content & mask) != (0x12121212 & mask))
|
||||
{
|
||||
LOG_ERROR ("IOMUX for {%s} is bad", text);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int initialize_nf_controller (struct nand_device_s *device)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
/*
|
||||
* resets NAND flash controller in zero time ? I dont know.
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_CFG1, MX3_NF_BIT_RESET_EN);
|
||||
{
|
||||
uint16_t work_mode;
|
||||
work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */
|
||||
if (target->endianness == TARGET_BIG_ENDIAN)
|
||||
{
|
||||
work_mode |= MX3_NF_BIT_BE_EN;
|
||||
}
|
||||
if (mx3_nf_info->flags.hw_ecc_enabled)
|
||||
{
|
||||
work_mode |= MX3_NF_BIT_ECC_EN;
|
||||
}
|
||||
target_write_u16 (target, MX3_NF_CFG1, work_mode);
|
||||
}
|
||||
/*
|
||||
* unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_BUFCFG, 2);
|
||||
{
|
||||
uint16_t temp;
|
||||
target_read_u16 (target, MX3_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, MX3_NF_FWP, 4);
|
||||
target_write_u16 (target, MX3_NF_LOCKSTART, 0x0000);
|
||||
target_write_u16 (target, MX3_NF_LOCKEND, 0xFFFF);
|
||||
/*
|
||||
* 0x0000 means that first SRAM buffer @0xB800_0000 will be used
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_BUFADDR, 0x0000);
|
||||
/*
|
||||
* address of SRAM buffer
|
||||
*/
|
||||
in_sram_address = MX3_NF_MAIN_BUFFER0;
|
||||
sign_of_sequental_byte_read = 0;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value)
|
||||
{
|
||||
static uint8_t even_byte = 0;
|
||||
/*
|
||||
* host-big_endian ??
|
||||
*/
|
||||
if (sign_of_sequental_byte_read == 0)
|
||||
{
|
||||
even_byte = 0;
|
||||
}
|
||||
if (in_sram_address > MX3_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
|
||||
{
|
||||
uint16_t temp;
|
||||
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 (target_t * target,
|
||||
uint16_t * value)
|
||||
{
|
||||
if (in_sram_address > MX3_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 (target_t * target, const char *text)
|
||||
{
|
||||
uint16_t poll_complete_status;
|
||||
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++)
|
||||
{
|
||||
usleep (25);
|
||||
target_read_u16 (target, MX3_NF_CFG2, &poll_complete_status);
|
||||
if (poll_complete_status & MX3_NF_BIT_OP_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(poll_complete_status & MX3_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_s *device)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
LOG_ERROR (target_not_halted_err_msg);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (mx3_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_s *device)
|
||||
{
|
||||
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
|
||||
target_t *target = mx3_nf_info->target;
|
||||
switch (mx3_nf_info->fin)
|
||||
{
|
||||
case MX3_NF_FIN_DATAOUT:
|
||||
/*
|
||||
* start data output operation (set MX3_NF_BIT_OP_DONE==0)
|
||||
*/
|
||||
target_write_u16 (target, MX3_NF_CFG2,
|
||||
MX3_NF_BIT_DATAOUT_TYPE (mx3_nf_info->
|
||||
optype));
|
||||
{
|
||||
int poll_result;
|
||||
poll_result = poll_for_complete_op (target, "data output");
|
||||
if (poll_result != ERROR_OK)
|
||||
{
|
||||
return poll_result;
|
||||
}
|
||||
}
|
||||
mx3_nf_info->fin = MX3_NF_FIN_NONE;
|
||||
/*
|
||||
* ECC stuff
|
||||
*/
|
||||
if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE)
|
||||
&& mx3_nf_info->flags.hw_ecc_enabled)
|
||||
{
|
||||
uint16_t ecc_status;
|
||||
target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status);
|
||||
switch (ecc_status & 0x000c)
|
||||
{
|
||||
case 1 << 2:
|
||||
LOG_DEBUG
|
||||
("main area readed with 1 (correctable) error");
|
||||
break;
|
||||
case 2 << 2:
|
||||
LOG_DEBUG
|
||||
("main area readed with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
switch (ecc_status & 0x0003)
|
||||
{
|
||||
case 1:
|
||||
LOG_DEBUG
|
||||
("spare area readed with 1 (correctable) error");
|
||||
break;
|
||||
case 2:
|
||||
LOG_DEBUG
|
||||
("main area readed with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MX3_NF_FIN_NONE:
|
||||
break;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
117
src/flash/mx3_nand.h
Normal file
117
src/flash/mx3_nand.h
Normal file
@@ -0,0 +1,117 @@
|
||||
|
||||
/***************************************************************************
|
||||
* 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 iMX3* OpenOCD NAND Flash controller support.
|
||||
*
|
||||
* Many thanks to Ben Dooks for writing s3c24xx driver.
|
||||
*/
|
||||
#include <nand.h>
|
||||
|
||||
#define MX3_NF_BASE_ADDR 0xb8000000
|
||||
#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00)
|
||||
#define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04)
|
||||
#define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06)
|
||||
#define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08)
|
||||
#define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a)
|
||||
#define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c)
|
||||
#define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e)
|
||||
#define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10)
|
||||
#define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12)
|
||||
#define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14)
|
||||
#define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16)
|
||||
#define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18)
|
||||
/*
|
||||
* all bits not marked as self-clearing bit
|
||||
*/
|
||||
#define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a)
|
||||
#define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c)
|
||||
|
||||
#define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000)
|
||||
#define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200)
|
||||
#define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400)
|
||||
#define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600)
|
||||
#define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800)
|
||||
#define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810)
|
||||
#define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820)
|
||||
#define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830)
|
||||
#define MX3_NF_MAIN_BUFFER_LEN 512
|
||||
#define MX3_NF_SPARE_BUFFER_LEN 16
|
||||
#define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2)
|
||||
|
||||
/* bits in MX3_NF_CFG1 register */
|
||||
#define MX3_NF_BIT_SPARE_ONLY_EN (1<<2)
|
||||
#define MX3_NF_BIT_ECC_EN (1<<3)
|
||||
#define MX3_NF_BIT_INT_DIS (1<<4)
|
||||
#define MX3_NF_BIT_BE_EN (1<<5)
|
||||
#define MX3_NF_BIT_RESET_EN (1<<6)
|
||||
#define MX3_NF_BIT_FORCE_CE (1<<7)
|
||||
|
||||
/* bits in MX3_NF_CFG2 register */
|
||||
|
||||
/*Flash Command Input*/
|
||||
#define MX3_NF_BIT_OP_FCI (1<<0)
|
||||
/*
|
||||
* Flash Address Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FAI (1<<1)
|
||||
/*
|
||||
* Flash Data Input
|
||||
*/
|
||||
#define MX3_NF_BIT_OP_FDI (1<<2)
|
||||
|
||||
/* see "enum mx_dataout_type" below */
|
||||
#define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3)
|
||||
#define MX3_NF_BIT_OP_DONE (1<<15)
|
||||
|
||||
#define MX3_CCM_CGR2 0x53f80028
|
||||
#define MX3_GPR 0x43fac008
|
||||
#define MX3_PCSR 0x53f8000c
|
||||
|
||||
enum mx_dataout_type
|
||||
{
|
||||
MX3_NF_DATAOUT_PAGE = 1,
|
||||
MX3_NF_DATAOUT_NANDID = 2,
|
||||
MX3_NF_DATAOUT_NANDSTATUS = 4,
|
||||
};
|
||||
enum mx_nf_finalize_action
|
||||
{
|
||||
MX3_NF_FIN_NONE,
|
||||
MX3_NF_FIN_DATAOUT,
|
||||
};
|
||||
|
||||
struct mx3_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;
|
||||
};
|
||||
|
||||
typedef struct mx3_nf_controller_s
|
||||
{
|
||||
struct target_s *target;
|
||||
enum mx_dataout_type optype;
|
||||
enum mx_nf_finalize_action fin;
|
||||
struct mx3_nf_flags flags;
|
||||
} mx3_nf_controller_t;
|
||||
508
src/flash/nand.c
508
src/flash/nand.c
@@ -24,63 +24,54 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "flash.h"
|
||||
#include "time_support.h"
|
||||
#include "fileio.h"
|
||||
#include "image.h"
|
||||
|
||||
int nand_register_commands(struct command_context_s *cmd_ctx);
|
||||
int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size);
|
||||
static int nand_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
//static int nand_read_plain(struct nand_device_s *device, uint32_t address, uint8_t *data, uint32_t data_size);
|
||||
|
||||
int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
static int nand_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
|
||||
/* NAND flash controller
|
||||
*/
|
||||
extern nand_flash_controller_t davinci_nand_controller;
|
||||
extern nand_flash_controller_t lpc3180_nand_controller;
|
||||
extern nand_flash_controller_t orion_nand_controller;
|
||||
extern nand_flash_controller_t s3c2410_nand_controller;
|
||||
extern nand_flash_controller_t s3c2412_nand_controller;
|
||||
extern nand_flash_controller_t s3c2440_nand_controller;
|
||||
extern nand_flash_controller_t s3c2443_nand_controller;
|
||||
extern nand_flash_controller_t imx31_nand_flash_controller;
|
||||
|
||||
/* extern nand_flash_controller_t boundary_scan_nand_controller; */
|
||||
|
||||
nand_flash_controller_t *nand_flash_controllers[] =
|
||||
static nand_flash_controller_t *nand_flash_controllers[] =
|
||||
{
|
||||
&davinci_nand_controller,
|
||||
&lpc3180_nand_controller,
|
||||
&orion_nand_controller,
|
||||
&s3c2410_nand_controller,
|
||||
&s3c2412_nand_controller,
|
||||
&s3c2440_nand_controller,
|
||||
&s3c2443_nand_controller,
|
||||
&imx31_nand_flash_controller,
|
||||
/* &boundary_scan_nand_controller, */
|
||||
NULL
|
||||
};
|
||||
|
||||
/* configured NAND devices and NAND Flash command handler */
|
||||
nand_device_t *nand_devices = NULL;
|
||||
static nand_device_t *nand_devices = NULL;
|
||||
static command_t *nand_cmd;
|
||||
|
||||
/* Chip ID list
|
||||
@@ -93,8 +84,9 @@ static command_t *nand_cmd;
|
||||
* 256 256 Byte page size
|
||||
* 512 512 Byte page size
|
||||
*/
|
||||
nand_info_t nand_flash_ids[] =
|
||||
static nand_info_t nand_flash_ids[] =
|
||||
{
|
||||
/* start "museum" IDs */
|
||||
{"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
|
||||
{"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
|
||||
{"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
|
||||
@@ -110,6 +102,7 @@ nand_info_t nand_flash_ids[] =
|
||||
{"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
|
||||
{"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
{"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
|
||||
/* end "museum" IDs */
|
||||
|
||||
{"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
|
||||
{"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
|
||||
@@ -166,12 +159,12 @@ nand_info_t nand_flash_ids[] =
|
||||
{"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
|
||||
{"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
|
||||
|
||||
{NULL, 0,}
|
||||
{NULL, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* Manufacturer ID list
|
||||
*/
|
||||
nand_manufacturer_t nand_manuf_ids[] =
|
||||
static nand_manufacturer_t nand_manuf_ids[] =
|
||||
{
|
||||
{0x0, "unknown"},
|
||||
{NAND_MFR_TOSHIBA, "Toshiba"},
|
||||
@@ -181,12 +174,48 @@ nand_manufacturer_t nand_manuf_ids[] =
|
||||
{NAND_MFR_RENESAS, "Renesas"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix"},
|
||||
{NAND_MFR_MICRON, "Micron"},
|
||||
{0x0, NULL},
|
||||
};
|
||||
|
||||
/*
|
||||
* Define default oob placement schemes for large and small page devices
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static nand_ecclayout_t nand_oob_8 = {
|
||||
.eccbytes = 3,
|
||||
.eccpos = {0, 1, 2},
|
||||
.oobfree = {
|
||||
{.offset = 3,
|
||||
.length = 2},
|
||||
{.offset = 6,
|
||||
.length = 2}}
|
||||
};
|
||||
#endif
|
||||
|
||||
static nand_ecclayout_t nand_oob_16 = {
|
||||
.eccbytes = 6,
|
||||
.eccpos = {0, 1, 2, 3, 6, 7},
|
||||
.oobfree = {
|
||||
{.offset = 8,
|
||||
. length = 8}}
|
||||
};
|
||||
|
||||
static nand_ecclayout_t nand_oob_64 = {
|
||||
.eccbytes = 24,
|
||||
.eccpos = {
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63},
|
||||
.oobfree = {
|
||||
{.offset = 2,
|
||||
.length = 38}}
|
||||
};
|
||||
|
||||
/* nand device <nand_controller> [controller options]
|
||||
*/
|
||||
int handle_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
int i;
|
||||
int retval;
|
||||
@@ -279,15 +308,15 @@ int nand_init(struct command_context_s *cmd_ctx)
|
||||
register_command(cmd_ctx, nand_cmd, "probe", handle_nand_probe_command, COMMAND_EXEC,
|
||||
"identify NAND flash device <num>");
|
||||
register_command(cmd_ctx, nand_cmd, "check_bad_blocks", handle_nand_check_bad_blocks_command, COMMAND_EXEC,
|
||||
"check NAND flash device <num> for bad blocks [<first> <last>]");
|
||||
register_command(cmd_ctx, nand_cmd, "erase", handle_nand_erase_command, COMMAND_EXEC,
|
||||
"erase blocks on NAND flash device <num> <first> <last>");
|
||||
register_command(cmd_ctx, nand_cmd, "copy", handle_nand_copy_command, COMMAND_EXEC,
|
||||
"copy from NAND flash device <num> <offset> <length> <ram-address>");
|
||||
"check NAND flash device <num> for bad blocks [<offset> <length>]");
|
||||
register_command(cmd_ctx, nand_cmd, "erase",
|
||||
handle_nand_erase_command, COMMAND_EXEC,
|
||||
"erase blocks on NAND flash device <num> [<offset> <length>]");
|
||||
register_command(cmd_ctx, nand_cmd, "dump", handle_nand_dump_command, COMMAND_EXEC,
|
||||
"dump from NAND flash device <num> <filename> <offset> <size> [options]");
|
||||
"dump from NAND flash device <num> <filename> "
|
||||
"<offset> <length> [oob_raw | oob_only]");
|
||||
register_command(cmd_ctx, nand_cmd, "write", handle_nand_write_command, COMMAND_EXEC,
|
||||
"write to NAND flash device <num> <filename> <offset> [options]");
|
||||
"write to NAND flash device <num> <filename> <offset> [oob_raw | oob_only | oob_softecc | oob_softecc_kw]");
|
||||
register_command(cmd_ctx, nand_cmd, "raw_access", handle_nand_raw_access_command, COMMAND_EXEC,
|
||||
"raw access to NAND flash device <num> ['enable'|'disable']");
|
||||
}
|
||||
@@ -311,13 +340,11 @@ nand_device_t *get_nand_device_by_num(int num)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nand_build_bbt(struct nand_device_s *device, int first, int last)
|
||||
static int nand_build_bbt(struct nand_device_s *device, int first, int last)
|
||||
{
|
||||
u32 page = 0x0;
|
||||
uint32_t page = 0x0;
|
||||
int i;
|
||||
u8 *oob;
|
||||
|
||||
oob = malloc(6);
|
||||
uint8_t oob[6];
|
||||
|
||||
if ((first < 0) || (first >= device->num_blocks))
|
||||
first = 0;
|
||||
@@ -333,7 +360,7 @@ int nand_build_bbt(struct nand_device_s *device, int first, int last)
|
||||
|| (((device->page_size == 512) && (oob[5] != 0xff)) ||
|
||||
((device->page_size == 2048) && (oob[0] != 0xff))))
|
||||
{
|
||||
LOG_WARNING("invalid block: %i", i);
|
||||
LOG_WARNING("bad block: %i", i);
|
||||
device->blocks[i].is_bad = 1;
|
||||
}
|
||||
else
|
||||
@@ -347,7 +374,7 @@ int nand_build_bbt(struct nand_device_s *device, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_read_status(struct nand_device_s *device, u8 *status)
|
||||
int nand_read_status(struct nand_device_s *device, uint8_t *status)
|
||||
{
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -360,7 +387,7 @@ int nand_read_status(struct nand_device_s *device, u8 *status)
|
||||
/* read status */
|
||||
if (device->device->options & NAND_BUSWIDTH_16)
|
||||
{
|
||||
u16 data;
|
||||
uint16_t data;
|
||||
device->controller->read_data(device, &data);
|
||||
*status = data & 0xff;
|
||||
}
|
||||
@@ -372,10 +399,31 @@ int nand_read_status(struct nand_device_s *device, u8 *status)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int nand_poll_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
device->controller->command(device, NAND_CMD_STATUS);
|
||||
do {
|
||||
if (device->device->options & NAND_BUSWIDTH_16) {
|
||||
uint16_t data;
|
||||
device->controller->read_data(device, &data);
|
||||
status = data & 0xff;
|
||||
} else {
|
||||
device->controller->read_data(device, &status);
|
||||
}
|
||||
if (status & NAND_STATUS_READY)
|
||||
break;
|
||||
alive_sleep(1);
|
||||
} while (timeout--);
|
||||
|
||||
return (status & NAND_STATUS_READY) != 0;
|
||||
}
|
||||
|
||||
int nand_probe(struct nand_device_s *device)
|
||||
{
|
||||
u8 manufacturer_id, device_id;
|
||||
u8 id_buff[6];
|
||||
uint8_t manufacturer_id, device_id;
|
||||
uint8_t id_buff[6];
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
@@ -419,7 +467,7 @@ int nand_probe(struct nand_device_s *device)
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 data_buf;
|
||||
uint16_t data_buf;
|
||||
device->controller->read_data(device, &data_buf);
|
||||
manufacturer_id = data_buf & 0xff;
|
||||
device->controller->read_data(device, &data_buf);
|
||||
@@ -473,13 +521,13 @@ int nand_probe(struct nand_device_s *device)
|
||||
{
|
||||
if (device->bus_width == 8)
|
||||
{
|
||||
device->controller->read_data(device, id_buff+3);
|
||||
device->controller->read_data(device, id_buff+4);
|
||||
device->controller->read_data(device, id_buff+5);
|
||||
device->controller->read_data(device, id_buff + 3);
|
||||
device->controller->read_data(device, id_buff + 4);
|
||||
device->controller->read_data(device, id_buff + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 data_buf;
|
||||
uint16_t data_buf;
|
||||
|
||||
device->controller->read_data(device, &data_buf);
|
||||
id_buff[3] = data_buf;
|
||||
@@ -530,7 +578,7 @@ int nand_probe(struct nand_device_s *device)
|
||||
device->address_cycles = 5;
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: small page NAND device with more than 32 GiB encountered");
|
||||
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
|
||||
device->address_cycles = 6;
|
||||
}
|
||||
}
|
||||
@@ -590,11 +638,11 @@ int nand_probe(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_erase(struct nand_device_s *device, int first_block, int last_block)
|
||||
static int nand_erase(struct nand_device_s *device, int first_block, int last_block)
|
||||
{
|
||||
int i;
|
||||
u32 page;
|
||||
u8 status;
|
||||
uint32_t page;
|
||||
uint8_t status;
|
||||
int retval;
|
||||
|
||||
if (!device->device)
|
||||
@@ -649,8 +697,10 @@ int nand_erase(struct nand_device_s *device, int first_block, int last_block)
|
||||
/* Send erase confirm command */
|
||||
device->controller->command(device, NAND_CMD_ERASE2);
|
||||
|
||||
if (!device->controller->nand_ready(device, 1000))
|
||||
{
|
||||
retval = device->controller->nand_ready ?
|
||||
device->controller->nand_ready(device, 1000) :
|
||||
nand_poll_ready(device, 1000);
|
||||
if (!retval) {
|
||||
LOG_ERROR("timeout waiting for NAND flash block erase to complete");
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
}
|
||||
@@ -663,17 +713,23 @@ int nand_erase(struct nand_device_s *device, int first_block, int last_block)
|
||||
|
||||
if (status & 0x1)
|
||||
{
|
||||
LOG_ERROR("erase operation didn't pass, status: 0x%2.2x", status);
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
|
||||
(device->blocks[i].is_bad == 1)
|
||||
? "bad " : "",
|
||||
i, status);
|
||||
/* continue; other blocks might still be erasable */
|
||||
}
|
||||
|
||||
device->blocks[i].is_erased = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
|
||||
#if 0
|
||||
static int nand_read_plain(struct nand_device_s *device, uint32_t address, uint8_t *data, uint32_t data_size)
|
||||
{
|
||||
u8 *page;
|
||||
uint8_t *page;
|
||||
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -686,10 +742,10 @@ int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 dat
|
||||
|
||||
page = malloc(device->page_size);
|
||||
|
||||
while (data_size > 0 )
|
||||
while (data_size > 0)
|
||||
{
|
||||
u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
|
||||
u32 page_address;
|
||||
uint32_t thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
|
||||
uint32_t page_address;
|
||||
|
||||
|
||||
page_address = address / device->page_size;
|
||||
@@ -708,9 +764,9 @@ int nand_read_plain(struct nand_device_s *device, u32 address, u8 *data, u32 dat
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 data_size)
|
||||
static int nand_write_plain(struct nand_device_s *device, uint32_t address, uint8_t *data, uint32_t data_size)
|
||||
{
|
||||
u8 *page;
|
||||
uint8_t *page;
|
||||
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -723,10 +779,10 @@ int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 da
|
||||
|
||||
page = malloc(device->page_size);
|
||||
|
||||
while (data_size > 0 )
|
||||
while (data_size > 0)
|
||||
{
|
||||
u32 thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
|
||||
u32 page_address;
|
||||
uint32_t thisrun_size = (data_size > device->page_size) ? device->page_size : data_size;
|
||||
uint32_t page_address;
|
||||
|
||||
memset(page, 0xff, device->page_size);
|
||||
memcpy(page, data, thisrun_size);
|
||||
@@ -744,19 +800,26 @@ int nand_write_plain(struct nand_device_s *device, u32 address, u8 *data, u32 da
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int nand_write_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
int nand_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
uint32_t block;
|
||||
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
block = page / (device->erase_size / device->page_size);
|
||||
if (device->blocks[block].is_erased == 1)
|
||||
device->blocks[block].is_erased = 0;
|
||||
|
||||
if (device->use_raw || device->controller->write_page == NULL)
|
||||
return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
|
||||
else
|
||||
return device->controller->write_page(device, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
static int nand_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -767,9 +830,9 @@ int nand_read_page(struct nand_device_s *device, u32 page, u8 *data, u32 data_si
|
||||
return device->controller->read_page(device, page, data, data_size, oob, oob_size);
|
||||
}
|
||||
|
||||
int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
int nand_read_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -823,8 +886,12 @@ int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
device->controller->command(device, NAND_CMD_READSTART);
|
||||
}
|
||||
|
||||
if (!device->controller->nand_ready(device, 100))
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
if (device->controller->nand_ready) {
|
||||
if (!device->controller->nand_ready(device, 100))
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
} else {
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
@@ -877,11 +944,11 @@ int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 dat
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size)
|
||||
int nand_write_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
|
||||
{
|
||||
int i;
|
||||
uint32_t i;
|
||||
int retval;
|
||||
u8 status;
|
||||
uint8_t status;
|
||||
|
||||
if (!device->device)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
@@ -911,7 +978,10 @@ int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 da
|
||||
* or 2048 for the beginning of OOB area)
|
||||
*/
|
||||
device->controller->address(device, 0x0);
|
||||
device->controller->address(device, 0x8);
|
||||
if (data)
|
||||
device->controller->address(device, 0x0);
|
||||
else
|
||||
device->controller->address(device, 0x8);
|
||||
|
||||
/* row */
|
||||
device->controller->address(device, page & 0xff);
|
||||
@@ -932,7 +1002,7 @@ int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 da
|
||||
{
|
||||
if (device->device->options & NAND_BUSWIDTH_16)
|
||||
{
|
||||
u16 data_buf = le_to_h_u16(data);
|
||||
uint16_t data_buf = le_to_h_u16(data);
|
||||
device->controller->write_data(device, data_buf);
|
||||
data += 2;
|
||||
i += 2;
|
||||
@@ -957,7 +1027,7 @@ int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 da
|
||||
{
|
||||
if (device->device->options & NAND_BUSWIDTH_16)
|
||||
{
|
||||
u16 oob_buf = le_to_h_u16(data);
|
||||
uint16_t oob_buf = le_to_h_u16(data);
|
||||
device->controller->write_data(device, oob_buf);
|
||||
oob += 2;
|
||||
i += 2;
|
||||
@@ -974,7 +1044,10 @@ int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 da
|
||||
|
||||
device->controller->command(device, NAND_CMD_PAGEPROG);
|
||||
|
||||
if (!device->controller->nand_ready(device, 100))
|
||||
retval = device->controller->nand_ready ?
|
||||
device->controller->nand_ready(device, 100) :
|
||||
nand_poll_ready(device, 100);
|
||||
if (!retval)
|
||||
return ERROR_NAND_OPERATION_TIMEOUT;
|
||||
|
||||
if ((retval = nand_read_status(device, &status)) != ERROR_OK)
|
||||
@@ -995,7 +1068,7 @@ int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 da
|
||||
int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
if (!nand_devices)
|
||||
{
|
||||
@@ -1003,19 +1076,23 @@ int handle_nand_list_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
for (p = nand_devices; p; p = p->next)
|
||||
for (p = nand_devices, i = 0; p; p = p->next, i++)
|
||||
{
|
||||
if (p->device)
|
||||
command_print(cmd_ctx, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i",
|
||||
i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size);
|
||||
command_print(cmd_ctx, "#%i: %s (%s) "
|
||||
"pagesize: %i, buswidth: %i,\n\t"
|
||||
"blocksize: %i, blocks: %i",
|
||||
i, p->device->name, p->manufacturer->name,
|
||||
p->page_size, p->bus_width,
|
||||
p->erase_size, p->num_blocks);
|
||||
else
|
||||
command_print(cmd_ctx, "#%i: not probed");
|
||||
command_print(cmd_ctx, "#%i: not probed", i);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
int i = 0;
|
||||
@@ -1023,20 +1100,20 @@ int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
|
||||
if ((argc < 1) || (argc > 3))
|
||||
{
|
||||
switch (argc) {
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
}
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
case 1:
|
||||
first = 0;
|
||||
last = INT32_MAX;
|
||||
break;
|
||||
case 2:
|
||||
first = last = strtoul(args[1], NULL, 0);
|
||||
}
|
||||
else if (argc == 3)
|
||||
{
|
||||
break;
|
||||
case 3:
|
||||
first = strtoul(args[1], NULL, 0);
|
||||
last = strtoul(args[2], NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
@@ -1071,21 +1148,25 @@ int handle_nand_info_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
else
|
||||
bad_state = " (block condition unknown)";
|
||||
|
||||
command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s%s",
|
||||
j, p->blocks[j].offset, p->blocks[j].size / 1024,
|
||||
erase_state, bad_state);
|
||||
command_print(cmd_ctx,
|
||||
"\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s",
|
||||
j,
|
||||
p->blocks[j].offset,
|
||||
p->blocks[j].size / 1024,
|
||||
erase_state,
|
||||
bad_state);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "#%i: not probed");
|
||||
command_print(cmd_ctx, "#%s: not probed", args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
int retval;
|
||||
@@ -1119,12 +1200,12 @@ int handle_nand_probe_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
int retval;
|
||||
|
||||
if (argc != 3)
|
||||
if (argc != 1 && argc != 3)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
@@ -1133,12 +1214,41 @@ int handle_nand_erase_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (p)
|
||||
{
|
||||
int first = strtoul(args[1], NULL, 0);
|
||||
int last = strtoul(args[2], NULL, 0);
|
||||
char *cp;
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
|
||||
if ((retval = nand_erase(p, first, last)) == ERROR_OK)
|
||||
/* erase specified part of the chip; or else everything */
|
||||
if (argc == 3) {
|
||||
unsigned long size = p->erase_size * p->num_blocks;
|
||||
|
||||
offset = strtoul(args[1], &cp, 0);
|
||||
if (*cp || (offset == ULONG_MAX)
|
||||
|| (offset % p->erase_size) != 0
|
||||
|| offset >= size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
length = strtoul(args[2], &cp, 0);
|
||||
if (*cp || (length == ULONG_MAX)
|
||||
|| (length == 0)
|
||||
|| (length % p->erase_size) != 0
|
||||
|| (length + offset) > size)
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
offset /= p->erase_size;
|
||||
length /= p->erase_size;
|
||||
} else {
|
||||
offset = 0;
|
||||
length = p->num_blocks;
|
||||
}
|
||||
|
||||
retval = nand_erase(p, offset, offset + length - 1);
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "successfully erased blocks %i to %i on NAND flash device '%s'", first, last, p->device->name);
|
||||
command_print(cmd_ctx, "erased blocks %lu to %lu "
|
||||
"on NAND flash device #%s '%s'",
|
||||
offset, offset + length,
|
||||
args[0], p->device->name);
|
||||
}
|
||||
else if (retval == ERROR_NAND_OPERATION_FAILED)
|
||||
{
|
||||
@@ -1170,64 +1280,63 @@ int handle_nand_check_bad_blocks_command(struct command_context_s *cmd_ctx, char
|
||||
|
||||
}
|
||||
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!p) {
|
||||
command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds",
|
||||
args[0]);
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (argc == 3)
|
||||
{
|
||||
first = strtoul(args[1], NULL, 0);
|
||||
last = strtoul(args[2], NULL, 0);
|
||||
char *cp;
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
|
||||
offset = strtoul(args[1], &cp, 0);
|
||||
if (*cp || offset == ULONG_MAX || offset % p->erase_size)
|
||||
{
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
offset /= p->erase_size;
|
||||
|
||||
length = strtoul(args[2], &cp, 0);
|
||||
if (*cp || length == ULONG_MAX || length % p->erase_size)
|
||||
{
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
length -= 1;
|
||||
length /= p->erase_size;
|
||||
|
||||
first = offset;
|
||||
last = offset + length;
|
||||
}
|
||||
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (p)
|
||||
retval = nand_build_bbt(p, first, last);
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
if ((retval = nand_build_bbt(p, first, last)) == ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "checked NAND flash device for bad blocks, use \"nand info\" command to list blocks", p->device->name);
|
||||
}
|
||||
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");
|
||||
}
|
||||
command_print(cmd_ctx, "checked NAND flash device for bad blocks, "
|
||||
"use \"nand info\" command to list blocks");
|
||||
}
|
||||
else if (retval == ERROR_NAND_OPERATION_FAILED)
|
||||
{
|
||||
command_print(cmd_ctx, "error when checking for bad blocks on "
|
||||
"NAND flash device");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
|
||||
command_print(cmd_ctx, "unknown error when checking for bad "
|
||||
"blocks on NAND flash device");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_copy_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
}
|
||||
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (p)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "NAND flash device '#%s' is out of bounds", args[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
u32 offset;
|
||||
u32 binary_size;
|
||||
u32 buf_cnt;
|
||||
uint32_t offset;
|
||||
uint32_t binary_size;
|
||||
uint32_t buf_cnt;
|
||||
enum oob_formats oob_format = NAND_OOB_NONE;
|
||||
|
||||
fileio_t fileio;
|
||||
@@ -1246,12 +1355,12 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
p = get_nand_device_by_num(strtoul(args[0], NULL, 0));
|
||||
if (p)
|
||||
{
|
||||
u8 *page = NULL;
|
||||
u32 page_size = 0;
|
||||
u8 *oob = NULL;
|
||||
u32 oob_size = 0;
|
||||
uint8_t *page = NULL;
|
||||
uint32_t page_size = 0;
|
||||
uint8_t *oob = NULL;
|
||||
uint32_t oob_size = 0;
|
||||
const int *eccpos = NULL;
|
||||
|
||||
duration_start_measure(&duration);
|
||||
offset = strtoul(args[2], NULL, 0);
|
||||
|
||||
if (argc > 3)
|
||||
@@ -1263,13 +1372,20 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
oob_format |= NAND_OOB_RAW;
|
||||
else if (!strcmp(args[i], "oob_only"))
|
||||
oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
|
||||
else if (!strcmp(args[i], "oob_softecc"))
|
||||
oob_format |= NAND_OOB_SW_ECC;
|
||||
else if (!strcmp(args[i], "oob_softecc_kw"))
|
||||
oob_format |= NAND_OOB_SW_ECC_KW;
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "unknown option: %s", args[i]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration_start_measure(&duration);
|
||||
|
||||
if (fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
|
||||
{
|
||||
return ERROR_OK;
|
||||
@@ -1283,12 +1399,15 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
page = malloc(p->page_size);
|
||||
}
|
||||
|
||||
if (oob_format & NAND_OOB_RAW)
|
||||
if (oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
|
||||
{
|
||||
if (p->page_size == 512)
|
||||
if (p->page_size == 512) {
|
||||
oob_size = 16;
|
||||
else if (p->page_size == 2048)
|
||||
eccpos = nand_oob_16.eccpos;
|
||||
} else if (p->page_size == 2048) {
|
||||
oob_size = 64;
|
||||
eccpos = nand_oob_64.eccpos;
|
||||
}
|
||||
oob = malloc(oob_size);
|
||||
}
|
||||
|
||||
@@ -1303,7 +1422,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
|
||||
while (buf_cnt > 0)
|
||||
{
|
||||
u32 size_read;
|
||||
uint32_t size_read;
|
||||
|
||||
if (NULL != page)
|
||||
{
|
||||
@@ -1315,7 +1434,34 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != oob)
|
||||
if (oob_format & NAND_OOB_SW_ECC)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint8_t ecc[3];
|
||||
memset(oob, 0xff, oob_size);
|
||||
for (i = 0, j = 0; i < page_size; i += 256) {
|
||||
nand_calculate_ecc(p, page + i, ecc);
|
||||
oob[eccpos[j++]] = ecc[0];
|
||||
oob[eccpos[j++]] = ecc[1];
|
||||
oob[eccpos[j++]] = ecc[2];
|
||||
}
|
||||
} else if (oob_format & NAND_OOB_SW_ECC_KW)
|
||||
{
|
||||
/*
|
||||
* In this case eccpos is not used as
|
||||
* the ECC data is always stored contigously
|
||||
* at the end of the OOB area. It consists
|
||||
* of 10 bytes per 512-byte data block.
|
||||
*/
|
||||
uint32_t i;
|
||||
uint8_t *ecc = oob + oob_size - page_size/512 * 10;
|
||||
memset(oob, 0xff, oob_size);
|
||||
for (i = 0; i < page_size; i += 512) {
|
||||
nand_calculate_ecc_kw(p, page + i, ecc);
|
||||
ecc += 10;
|
||||
}
|
||||
}
|
||||
else if (NULL != oob)
|
||||
{
|
||||
fileio_read(&fileio, oob_size, oob, &size_read);
|
||||
buf_cnt -= size_read;
|
||||
@@ -1327,7 +1473,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
|
||||
if (nand_write_page(p, offset / p->page_size, page, page_size, oob, oob_size) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8x",
|
||||
command_print(cmd_ctx, "failed writing file %s to NAND flash %s at offset 0x%8.8" PRIx32 "",
|
||||
args[1], args[0], offset);
|
||||
|
||||
fileio_close(&fileio);
|
||||
@@ -1345,7 +1491,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
oob = NULL;
|
||||
page = NULL;
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
command_print(cmd_ctx, "wrote file %s to NAND flash %s at offset 0x%8.8x in %s",
|
||||
command_print(cmd_ctx, "wrote file %s to NAND flash %s up to offset 0x%8.8" PRIx32 " in %s",
|
||||
args[1], args[0], offset, duration_text);
|
||||
free(duration_text);
|
||||
duration_text = NULL;
|
||||
@@ -1358,7 +1504,7 @@ int handle_nand_write_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
|
||||
@@ -1377,13 +1523,13 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
char *duration_text;
|
||||
int retval;
|
||||
|
||||
u8 *page = NULL;
|
||||
u32 page_size = 0;
|
||||
u8 *oob = NULL;
|
||||
u32 oob_size = 0;
|
||||
u32 address = strtoul(args[2], NULL, 0);
|
||||
u32 size = strtoul(args[3], NULL, 0);
|
||||
u32 bytes_done = 0;
|
||||
uint8_t *page = NULL;
|
||||
uint32_t page_size = 0;
|
||||
uint8_t *oob = NULL;
|
||||
uint32_t oob_size = 0;
|
||||
uint32_t address = strtoul(args[2], NULL, 0);
|
||||
uint32_t size = strtoul(args[3], NULL, 0);
|
||||
uint32_t bytes_done = 0;
|
||||
enum oob_formats oob_format = NAND_OOB_NONE;
|
||||
|
||||
if (argc > 4)
|
||||
@@ -1430,7 +1576,7 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
u32 size_written;
|
||||
uint32_t size_written;
|
||||
if ((retval = nand_read_page(p, address / p->page_size, page, page_size, oob, oob_size)) != ERROR_OK)
|
||||
{
|
||||
command_print(cmd_ctx, "reading NAND flash page failed");
|
||||
@@ -1463,13 +1609,13 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
fileio_close(&fileio);
|
||||
|
||||
duration_stop_measure(&duration, &duration_text);
|
||||
command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text);
|
||||
command_print(cmd_ctx, "dumped %lld byte in %s", fileio.size, duration_text);
|
||||
free(duration_text);
|
||||
duration_text = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "#%i: not probed");
|
||||
command_print(cmd_ctx, "#%s: not probed", args[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1480,7 +1626,7 @@ int handle_nand_dump_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
nand_device_t *p;
|
||||
|
||||
@@ -1514,7 +1660,7 @@ int handle_nand_raw_access_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "#%i: not probed");
|
||||
command_print(cmd_ctx, "#%s: not probed", args[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -36,26 +36,38 @@ typedef struct nand_flash_controller_s
|
||||
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||
int (*init)(struct nand_device_s *device);
|
||||
int (*reset)(struct nand_device_s *device);
|
||||
int (*command)(struct nand_device_s *device, u8 command);
|
||||
int (*address)(struct nand_device_s *device, u8 address);
|
||||
int (*write_data)(struct nand_device_s *device, u16 data);
|
||||
int (*command)(struct nand_device_s *device, uint8_t command);
|
||||
int (*address)(struct nand_device_s *device, uint8_t address);
|
||||
int (*write_data)(struct nand_device_s *device, uint16_t data);
|
||||
int (*read_data)(struct nand_device_s *device, void *data);
|
||||
int (*write_block_data)(struct nand_device_s *device, u8 *data, int size);
|
||||
int (*read_block_data)(struct nand_device_s *device, u8 *data, int size);
|
||||
int (*write_page)(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int (*read_page)(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
int (*write_block_data)(struct nand_device_s *device, uint8_t *data, int size);
|
||||
int (*read_block_data)(struct nand_device_s *device, uint8_t *data, int size);
|
||||
int (*write_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int (*read_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
int (*controller_ready)(struct nand_device_s *device, int timeout);
|
||||
int (*nand_ready)(struct nand_device_s *device, int timeout);
|
||||
} nand_flash_controller_t;
|
||||
|
||||
typedef struct nand_block_s
|
||||
{
|
||||
u32 offset;
|
||||
u32 size;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
int is_erased;
|
||||
int is_bad;
|
||||
} nand_block_t;
|
||||
|
||||
struct nand_oobfree {
|
||||
int offset;
|
||||
int length;
|
||||
};
|
||||
|
||||
typedef struct nand_ecclayout_s {
|
||||
int eccbytes;
|
||||
int eccpos[64];
|
||||
int oobavail;
|
||||
struct nand_oobfree oobfree[2];
|
||||
} nand_ecclayout_t;
|
||||
|
||||
typedef struct nand_device_s
|
||||
{
|
||||
nand_flash_controller_t *controller;
|
||||
@@ -83,11 +95,12 @@ enum
|
||||
NAND_MFR_RENESAS = 0x07,
|
||||
NAND_MFR_STMICRO = 0x20,
|
||||
NAND_MFR_HYNIX = 0xad,
|
||||
NAND_MFR_MICRON = 0x2c,
|
||||
};
|
||||
|
||||
typedef struct nand_manufacturer_s
|
||||
{
|
||||
int id;
|
||||
int id;
|
||||
char *name;
|
||||
} nand_manufacturer_t;
|
||||
|
||||
@@ -188,15 +201,18 @@ enum oob_formats
|
||||
NAND_OOB_ONLY = 0x2, /* only OOB data */
|
||||
NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */
|
||||
NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */
|
||||
NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */
|
||||
NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */
|
||||
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
|
||||
};
|
||||
|
||||
/* Function prototypes */
|
||||
extern nand_device_t *get_nand_device_by_num(int num);
|
||||
extern int nand_read_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
extern int nand_write_page_raw(struct nand_device_s *device, u32 page, u8 *data, u32 data_size, u8 *oob, u32 oob_size);
|
||||
extern int nand_read_status(struct nand_device_s *device, u8 *status);
|
||||
extern int nand_read_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
extern int nand_write_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
|
||||
extern int nand_read_status(struct nand_device_s *device, uint8_t *status);
|
||||
extern int nand_calculate_ecc(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
|
||||
extern int nand_calculate_ecc_kw(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
|
||||
|
||||
extern int nand_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int nand_init(struct command_context_s *cmd_ctx);
|
||||
@@ -207,5 +223,6 @@ extern int nand_init(struct command_context_s *cmd_ctx);
|
||||
#define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103)
|
||||
#define ERROR_NAND_DEVICE_NOT_PROBED (-1104)
|
||||
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
|
||||
#define ERROR_NAND_NO_BUFFER (-1106)
|
||||
|
||||
#endif /* NAND_H */
|
||||
|
||||
122
src/flash/nand_ecc.c
Normal file
122
src/flash/nand_ecc.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file contains an ECC algorithm from Toshiba that allows for detection
|
||||
* and correction of 1-bit errors in a 256 byte block of data.
|
||||
*
|
||||
* [ Extracted from the initial code found in some early Linux versions.
|
||||
* The current Linux code is bigger while being faster, but this is of
|
||||
* no real benefit when the bottleneck largely remains the JTAG link. ]
|
||||
*
|
||||
* Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com)
|
||||
* Toshiba America Electronics Components, Inc.
|
||||
*
|
||||
* Copyright (C) 2006 Thomas Gleixner <tglx at linutronix.de>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This file 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 file; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* As a special exception, if other files instantiate templates or use
|
||||
* macros or inline functions from these files, or you compile these
|
||||
* files and link them with other works to produce a work based on these
|
||||
* files, these files do not by themselves cause the resulting work to be
|
||||
* covered by the GNU General Public License. However the source code for
|
||||
* these files must still be made available in accordance with section (3)
|
||||
* of the GNU General Public License.
|
||||
*
|
||||
* This exception does not invalidate any other reasons why a work based on
|
||||
* this file might be covered by the GNU General Public License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "nand.h"
|
||||
|
||||
/*
|
||||
* Pre-calculated 256-way 1 byte column parity
|
||||
*/
|
||||
static const uint8_t nand_ecc_precalc_table[] = {
|
||||
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
|
||||
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
|
||||
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
|
||||
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
|
||||
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
|
||||
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
|
||||
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
|
||||
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
|
||||
0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
|
||||
0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
|
||||
0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
|
||||
0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
|
||||
0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
|
||||
0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
|
||||
0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
|
||||
0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block
|
||||
*/
|
||||
int nand_calculate_ecc(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code)
|
||||
{
|
||||
uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
|
||||
int i;
|
||||
|
||||
/* Initialize variables */
|
||||
reg1 = reg2 = reg3 = 0;
|
||||
|
||||
/* Build up column parity */
|
||||
for (i = 0; i < 256; i++) {
|
||||
/* Get CP0 - CP5 from table */
|
||||
idx = nand_ecc_precalc_table[*dat++];
|
||||
reg1 ^= (idx & 0x3f);
|
||||
|
||||
/* All bit XOR = 1 ? */
|
||||
if (idx & 0x40) {
|
||||
reg3 ^= (uint8_t) i;
|
||||
reg2 ^= ~((uint8_t) i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create non-inverted ECC code from line parity */
|
||||
tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */
|
||||
tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */
|
||||
tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */
|
||||
tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */
|
||||
tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */
|
||||
tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */
|
||||
tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */
|
||||
tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */
|
||||
|
||||
tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */
|
||||
tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */
|
||||
tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */
|
||||
tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */
|
||||
tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */
|
||||
tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */
|
||||
tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */
|
||||
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
|
||||
|
||||
/* Calculate final ECC code */
|
||||
#ifdef NAND_ECC_SMC
|
||||
ecc_code[0] = ~tmp2;
|
||||
ecc_code[1] = ~tmp1;
|
||||
#else
|
||||
ecc_code[0] = ~tmp1;
|
||||
ecc_code[1] = ~tmp2;
|
||||
#endif
|
||||
ecc_code[2] = ((~reg1) << 2) | 0x03;
|
||||
|
||||
return 0;
|
||||
}
|
||||
174
src/flash/nand_ecc_kw.c
Normal file
174
src/flash/nand_ecc_kw.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Reed-Solomon ECC handling for the Marvell Kirkwood SOC
|
||||
* Copyright (C) 2009 Marvell Semiconductor, Inc.
|
||||
*
|
||||
* Authors: Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
* Nicolas Pitre <nico@fluxnic.net>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This file 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "nand.h"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1.
|
||||
*
|
||||
* For multiplication, a discrete log/exponent table is used, with
|
||||
* primitive element x (F is a primitive field, so x is primitive).
|
||||
*/
|
||||
#define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */
|
||||
|
||||
/*
|
||||
* Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in
|
||||
* GF(2^10) mod x^10 + x^3 + 1 such that b = x ^ a. There's two
|
||||
* identical copies of this array back-to-back so that we can save
|
||||
* the mod 1023 operation when doing a GF multiplication.
|
||||
*/
|
||||
static uint16_t gf_exp[1023 + 1023];
|
||||
|
||||
/*
|
||||
* Maps a polynomial b in GF(2^10) mod x^10 + x^3 + 1 to an index
|
||||
* a = gf_log[b] in [0..1022] such that b = x ^ a.
|
||||
*/
|
||||
static uint16_t gf_log[1024];
|
||||
|
||||
static void gf_build_log_exp_table(void)
|
||||
{
|
||||
int i;
|
||||
int p_i;
|
||||
|
||||
/*
|
||||
* p_i = x ^ i
|
||||
*
|
||||
* Initialise to 1 for i = 0.
|
||||
*/
|
||||
p_i = 1;
|
||||
|
||||
for (i = 0; i < 1023; i++) {
|
||||
gf_exp[i] = p_i;
|
||||
gf_exp[i + 1023] = p_i;
|
||||
gf_log[p_i] = i;
|
||||
|
||||
/*
|
||||
* p_i = p_i * x
|
||||
*/
|
||||
p_i <<= 1;
|
||||
if (p_i & (1 << 10))
|
||||
p_i ^= MODPOLY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Reed-Solomon code
|
||||
*
|
||||
* This implements a (1023,1015) Reed-Solomon ECC code over GF(2^10)
|
||||
* mod x^10 + x^3 + 1, shortened to (520,512). The ECC data consists
|
||||
* of 8 10-bit symbols, or 10 8-bit bytes.
|
||||
*
|
||||
* Given 512 bytes of data, computes 10 bytes of ECC.
|
||||
*
|
||||
* This is done by converting the 512 bytes to 512 10-bit symbols
|
||||
* (elements of F), interpreting those symbols as a polynomial in F[X]
|
||||
* by taking symbol 0 as the coefficient of X^8 and symbol 511 as the
|
||||
* coefficient of X^519, and calculating the residue of that polynomial
|
||||
* divided by the generator polynomial, which gives us the 8 ECC symbols
|
||||
* as the remainder. Finally, we convert the 8 10-bit ECC symbols to 10
|
||||
* 8-bit bytes.
|
||||
*
|
||||
* The generator polynomial is hardcoded, as that is faster, but it
|
||||
* can be computed by taking the primitive element a = x (in F), and
|
||||
* constructing a polynomial in F[X] with roots a, a^2, a^3, ..., a^8
|
||||
* by multiplying the minimal polynomials for those roots (which are
|
||||
* just 'x - a^i' for each i).
|
||||
*
|
||||
* Note: due to unfortunate circumstances, the bootrom in the Kirkwood SOC
|
||||
* expects the ECC to be computed backward, i.e. from the last byte down
|
||||
* to the first one.
|
||||
*/
|
||||
int nand_calculate_ecc_kw(struct nand_device_s *device, const uint8_t *data, uint8_t *ecc)
|
||||
{
|
||||
unsigned int r7, r6, r5, r4, r3, r2, r1, r0;
|
||||
int i;
|
||||
static int tables_initialized = 0;
|
||||
|
||||
if (!tables_initialized) {
|
||||
gf_build_log_exp_table();
|
||||
tables_initialized = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load bytes 504..511 of the data into r.
|
||||
*/
|
||||
r0 = data[504];
|
||||
r1 = data[505];
|
||||
r2 = data[506];
|
||||
r3 = data[507];
|
||||
r4 = data[508];
|
||||
r5 = data[509];
|
||||
r6 = data[510];
|
||||
r7 = data[511];
|
||||
|
||||
|
||||
/*
|
||||
* Shift bytes 503..0 (in that order) into r0, followed
|
||||
* by eight zero bytes, while reducing the polynomial by the
|
||||
* generator polynomial in every step.
|
||||
*/
|
||||
for (i = 503; i >= -8; i--) {
|
||||
unsigned int d;
|
||||
|
||||
d = 0;
|
||||
if (i >= 0)
|
||||
d = data[i];
|
||||
|
||||
if (r7) {
|
||||
uint16_t *t = gf_exp + gf_log[r7];
|
||||
|
||||
r7 = r6 ^ t[0x21c];
|
||||
r6 = r5 ^ t[0x181];
|
||||
r5 = r4 ^ t[0x18e];
|
||||
r4 = r3 ^ t[0x25f];
|
||||
r3 = r2 ^ t[0x197];
|
||||
r2 = r1 ^ t[0x193];
|
||||
r1 = r0 ^ t[0x237];
|
||||
r0 = d ^ t[0x024];
|
||||
} else {
|
||||
r7 = r6;
|
||||
r6 = r5;
|
||||
r5 = r4;
|
||||
r4 = r3;
|
||||
r3 = r2;
|
||||
r2 = r1;
|
||||
r1 = r0;
|
||||
r0 = d;
|
||||
}
|
||||
}
|
||||
|
||||
ecc[0] = r0;
|
||||
ecc[1] = (r0 >> 8) | (r1 << 2);
|
||||
ecc[2] = (r1 >> 6) | (r2 << 4);
|
||||
ecc[3] = (r2 >> 4) | (r3 << 6);
|
||||
ecc[4] = (r3 >> 2);
|
||||
ecc[5] = r4;
|
||||
ecc[6] = (r4 >> 8) | (r5 << 2);
|
||||
ecc[7] = (r5 >> 6) | (r6 << 4);
|
||||
ecc[8] = (r6 >> 4) | (r7 << 6);
|
||||
ecc[9] = (r7 >> 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* Copyright (C) 2009 Michael Schwingen *
|
||||
* michael@schwingen.org *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
@@ -21,220 +23,378 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "cfi.h"
|
||||
#include "non_cfi.h"
|
||||
#include "cfi.h"
|
||||
|
||||
|
||||
#define KB 1024
|
||||
#define MB (1024*1024)
|
||||
#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
|
||||
|
||||
/* non-CFI compatible flashes */
|
||||
non_cfi_t non_cfi_flashes[] = {
|
||||
static non_cfi_t non_cfi_flashes[] = {
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0xd4,
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x10, /* 2^16 = 64KB */
|
||||
.dev_size = 64*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 =
|
||||
{
|
||||
0x0010000f, /* 16x 4KB */
|
||||
0x00000000
|
||||
ERASE_REGION(16, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0xd5,
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x11, /* 2^17 = 128KB */
|
||||
.dev_size = 128*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 =
|
||||
{
|
||||
0x0010001f,
|
||||
0x00000000
|
||||
ERASE_REGION(32, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0xd6,
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x12, /* 2^18 = 256KB */
|
||||
.dev_size = 256*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 =
|
||||
{
|
||||
0x0010003f,
|
||||
0x00000000
|
||||
ERASE_REGION(64, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0xd7,
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.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 =
|
||||
{
|
||||
0x0010007f,
|
||||
0x00000000
|
||||
ERASE_REGION(128, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x2780,
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.dev_size = 512*KB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 1,
|
||||
.erase_region_info =
|
||||
{
|
||||
0x0010007f,
|
||||
0x00000000
|
||||
ERASE_REGION(128, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_ST,
|
||||
.id = 0xd6, /* ST29F400BB */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.dev_size = 512*KB,
|
||||
.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 =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x01000006, /* 7x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(7, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_ST,
|
||||
.id = 0xd5, /* ST29F400BT */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.dev_size = 512*KB,
|
||||
.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 =
|
||||
{
|
||||
0x01000006, /* 7x 64KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00000000
|
||||
ERASE_REGION(7, 64*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 16*KB)
|
||||
}
|
||||
},
|
||||
|
||||
/* SST 39VF* do not support DQ5 status polling - this currently is
|
||||
only supported by the host algorithm, not by the target code using
|
||||
the work area.
|
||||
Only true for 8-bit and 32-bit wide memories. 16-bit wide memories
|
||||
without DQ5 status polling are supported by the target code.
|
||||
*/
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x2782, /* SST39xF160 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||
.num_erase_regions = 1,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(512, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x2783, /* SST39VF320 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 4*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(1024, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x234b, /* SST39VF1601 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||
.num_erase_regions = 1,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(512, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x234a, /* SST39VF1602 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
|
||||
.num_erase_regions = 1,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(512, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x235b, /* SST39VF3201 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 4*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(1024, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_SST,
|
||||
.id = 0x235a, /* SST39VF3202 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 4*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(1024, 4*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_AMD,
|
||||
.id = 0x22ab, /* AM29F400BB */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.dev_size = 512*KB,
|
||||
.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 =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x01000006, /* 7x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(7, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_AMD,
|
||||
.id = 0x2223, /* AM29F400BT */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x13, /* 2^19 = 512KB */
|
||||
.dev_size = 512*KB,
|
||||
.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 =
|
||||
{
|
||||
0x01000006, /* 7x 64KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00000000
|
||||
ERASE_REGION(7, 64*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 16*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_FUJITSU,
|
||||
.id = 0x226b, /* AM29SL800DB */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x14, /* 2^20 = 1MB */
|
||||
.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 =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x0100000e, /* 15x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(15, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_AMIC,
|
||||
.id = 0xb31a, /* A29L800A */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x14,
|
||||
.dev_size = 1*MB,
|
||||
.interface_desc = 0x2,
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 4,
|
||||
.erase_region_info =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x0100000e, /* 15x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(15, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_MX,
|
||||
.id = 0x225b, /* MX29LV800B */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x14, /* 2^20 = 1MB */
|
||||
.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 =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x0100000e, /* 15x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(15, 64*KB)
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
.mfr = CFI_MFR_MX,
|
||||
.id = 0x2249, /* MX29LV160AB: 2MB */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 4,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(31, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_MX,
|
||||
.id = 0x22C4, /* MX29LV160AT: 2MB */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 4,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(31, 64*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 16*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_ATMEL,
|
||||
.id = 0x00c0, /* Atmel 49BV1614 */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 3,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(8, 8*KB),
|
||||
ERASE_REGION(2, 32*KB),
|
||||
ERASE_REGION(30, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_ATMEL,
|
||||
.id = 0xC2, /* Atmel 49BV1614T */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 2*MB,
|
||||
.interface_desc = 0x2, /* x8 or x16 device with nBYTE */
|
||||
.max_buf_write_size = 0x0,
|
||||
.status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
|
||||
.num_erase_regions = 3,
|
||||
.erase_region_info =
|
||||
{
|
||||
ERASE_REGION(30, 64*KB),
|
||||
ERASE_REGION(2, 32*KB),
|
||||
ERASE_REGION(8, 8*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
.mfr = CFI_MFR_AMD,
|
||||
.id = 0x225b, /* S29AL008D */
|
||||
.pri_id = 0x02,
|
||||
.dev_size = 0x14, /* 2^20 = 1MB */
|
||||
.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 =
|
||||
{
|
||||
0x00400000, /* 1x 16KB */
|
||||
0x00200001, /* 2x 8KB */
|
||||
0x00800000, /* 1x 32KB */
|
||||
0x0100000e, /* 15x 64KB */
|
||||
0x00000000
|
||||
ERASE_REGION(1, 16*KB),
|
||||
ERASE_REGION(2, 8*KB),
|
||||
ERASE_REGION(1, 32*KB),
|
||||
ERASE_REGION(15, 64*KB)
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -243,21 +403,24 @@ non_cfi_t non_cfi_flashes[] = {
|
||||
}
|
||||
};
|
||||
|
||||
void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
|
||||
void cfi_fixup_non_cfi(flash_bank_t *bank)
|
||||
{
|
||||
cfi_flash_bank_t *cfi_info = bank->driver_priv;
|
||||
non_cfi_t *non_cfi = non_cfi_flashes;
|
||||
|
||||
while (non_cfi->mfr)
|
||||
for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
|
||||
{
|
||||
if ((cfi_info->manufacturer == non_cfi->mfr)
|
||||
&& (cfi_info->device_id == non_cfi->id))
|
||||
{
|
||||
break;
|
||||
}
|
||||
non_cfi++;
|
||||
}
|
||||
|
||||
/* only fixup jedec flashs found in table */
|
||||
if (!non_cfi->mfr)
|
||||
return;
|
||||
|
||||
cfi_info->not_cfi = 1;
|
||||
|
||||
/* fill in defaults for non-critical data */
|
||||
@@ -286,8 +449,10 @@ void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
|
||||
|
||||
cfi_info->interface_desc = non_cfi->interface_desc;
|
||||
cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
|
||||
cfi_info->status_poll_mask = non_cfi->status_poll_mask;
|
||||
cfi_info->num_erase_regions = non_cfi->num_erase_regions;
|
||||
cfi_info->erase_region_info = non_cfi->erase_region_info;
|
||||
cfi_info->dev_size = non_cfi->dev_size;
|
||||
|
||||
if (cfi_info->pri_id == 0x2)
|
||||
{
|
||||
@@ -313,6 +478,8 @@ void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
|
||||
pri_ext->VppMax = 0x0;
|
||||
pri_ext->TopBottom = 0x0;
|
||||
|
||||
pri_ext->_unlock1 = 0x5555;
|
||||
pri_ext->_unlock2 = 0x2AAA;
|
||||
pri_ext->_reversed_geometry = 0;
|
||||
|
||||
cfi_info->pri_ext = pri_ext;
|
||||
|
||||
@@ -20,21 +20,21 @@
|
||||
#ifndef NON_CFI_H
|
||||
#define NON_CFI_H
|
||||
|
||||
#include "types.h"
|
||||
#include "flash.h"
|
||||
|
||||
typedef struct non_cfi_s
|
||||
{
|
||||
u16 mfr;
|
||||
u16 id;
|
||||
u16 pri_id;
|
||||
u8 dev_size;
|
||||
u16 interface_desc;
|
||||
u16 max_buf_write_size;
|
||||
u8 num_erase_regions;
|
||||
u32 erase_region_info[6];
|
||||
uint16_t mfr;
|
||||
uint16_t id;
|
||||
uint16_t pri_id;
|
||||
uint32_t dev_size;
|
||||
uint16_t interface_desc;
|
||||
uint16_t max_buf_write_size;
|
||||
uint8_t num_erase_regions;
|
||||
uint32_t erase_region_info[6];
|
||||
uint8_t status_poll_mask;
|
||||
} non_cfi_t;
|
||||
|
||||
extern non_cfi_t non_cfi_flashes[];
|
||||
extern void cfi_fixup_non_cfi(flash_bank_t *bank, void *param);
|
||||
extern void cfi_fixup_non_cfi(flash_bank_t *bank);
|
||||
|
||||
#endif /* NON_CFI_H */
|
||||
|
||||
@@ -21,32 +21,21 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "ocl.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "types.h"
|
||||
#include "embeddedice.h"
|
||||
#include "arm7_9_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int ocl_register_commands(struct command_context_s *cmd_ctx);
|
||||
int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int ocl_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int ocl_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int ocl_probe(struct flash_bank_s *bank);
|
||||
int ocl_erase_check(struct flash_bank_s *bank);
|
||||
int ocl_protect_check(struct flash_bank_s *bank);
|
||||
int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
int ocl_auto_probe(struct flash_bank_s *bank);
|
||||
static int ocl_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int ocl_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int ocl_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int ocl_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int ocl_probe(struct flash_bank_s *bank);
|
||||
static int ocl_erase_check(struct flash_bank_s *bank);
|
||||
static int ocl_protect_check(struct flash_bank_s *bank);
|
||||
static int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int ocl_auto_probe(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t ocl_flash =
|
||||
{
|
||||
@@ -66,27 +55,27 @@ flash_driver_t ocl_flash =
|
||||
typedef struct ocl_priv_s
|
||||
{
|
||||
arm_jtag_t *jtag_info;
|
||||
int buflen;
|
||||
int bufalign;
|
||||
unsigned int buflen;
|
||||
unsigned int bufalign;
|
||||
} ocl_priv_t;
|
||||
|
||||
int ocl_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int ocl_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_erase_check(struct flash_bank_s *bank)
|
||||
static int ocl_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_protect_check(struct flash_bank_s *bank)
|
||||
static int ocl_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank ocl 0 0 0 0 <target#> */
|
||||
int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
int retval;
|
||||
armv4_5_common_t *armv4_5;
|
||||
@@ -110,11 +99,11 @@ int ocl_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int ocl_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
u32 dcc_buffer[3];
|
||||
uint32_t dcc_buffer[3];
|
||||
|
||||
/* check preconditions */
|
||||
if (bank->num_sectors == 0)
|
||||
@@ -150,40 +139,40 @@ int ocl_erase(struct flash_bank_s *bank, int first, int last)
|
||||
}
|
||||
|
||||
/* receive response */
|
||||
if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer+1, 1) != ERROR_OK))
|
||||
if ((retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1) != ERROR_OK))
|
||||
return retval;
|
||||
|
||||
if (dcc_buffer[1] != OCL_CMD_DONE)
|
||||
{
|
||||
if (dcc_buffer[0] == OCL_ERASE_ALL)
|
||||
LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08X", dcc_buffer[1]);
|
||||
LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]);
|
||||
else
|
||||
LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08X", dcc_buffer[1]);
|
||||
LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int ocl_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int ocl_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
u32 *dcc_buffer;
|
||||
u32 *dcc_bufptr;
|
||||
uint32_t *dcc_buffer;
|
||||
uint32_t *dcc_bufptr;
|
||||
int byteofs;
|
||||
int runlen;
|
||||
u32 chksum;
|
||||
uint32_t chksum;
|
||||
|
||||
int i;
|
||||
|
||||
/* check preconditions */
|
||||
if (ocl->buflen == 0 || ocl->bufalign==0)
|
||||
if (ocl->buflen == 0 || ocl->bufalign == 0)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
if (bank->target->state != TARGET_RUNNING)
|
||||
@@ -193,7 +182,7 @@ int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
}
|
||||
|
||||
/* allocate buffer for max. ocl buffer + overhead */
|
||||
dcc_buffer = malloc(sizeof(u32)*(ocl->buflen/4+3));
|
||||
dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3));
|
||||
|
||||
while (count)
|
||||
{
|
||||
@@ -211,7 +200,7 @@ int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
chksum = OCL_CHKS_INIT;
|
||||
|
||||
/* copy data to DCC buffer in proper byte order and properly aligned */
|
||||
for (i=0; i<runlen; i++)
|
||||
for (i = 0; i < runlen; i++)
|
||||
{
|
||||
switch (byteofs++)
|
||||
{
|
||||
@@ -219,13 +208,13 @@ int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
*dcc_bufptr &= *(buffer++) | 0xffffff00;
|
||||
break;
|
||||
case 1:
|
||||
*dcc_bufptr &= ((*(buffer++))<<8) | 0xffff00ff;
|
||||
*dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff;
|
||||
break;
|
||||
case 2:
|
||||
*dcc_bufptr &= ((*(buffer++))<<16) | 0xff00ffff;
|
||||
*dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff;
|
||||
break;
|
||||
case 3:
|
||||
*dcc_bufptr &= ((*(buffer++))<<24) | 0x00ffffff;
|
||||
*dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff;
|
||||
chksum ^= *(dcc_bufptr++);
|
||||
*dcc_bufptr = 0xffffffff;
|
||||
byteofs = 0;
|
||||
@@ -264,7 +253,7 @@ int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (dcc_buffer[0] != OCL_CMD_DONE)
|
||||
{
|
||||
LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08X", dcc_buffer[0]);
|
||||
LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]);
|
||||
free(dcc_buffer);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
@@ -277,11 +266,11 @@ int ocl_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_probe(struct flash_bank_s *bank)
|
||||
static int ocl_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
int retval;
|
||||
u32 dcc_buffer[1];
|
||||
uint32_t dcc_buffer[1];
|
||||
int sectsize;
|
||||
int i;
|
||||
|
||||
@@ -306,7 +295,7 @@ int ocl_probe(struct flash_bank_s *bank)
|
||||
|
||||
if (dcc_buffer[0] != OCL_CMD_DONE)
|
||||
{
|
||||
LOG_ERROR("loader response to OCL_PROBE 0x%08X", dcc_buffer[0]);
|
||||
LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -343,7 +332,7 @@ int ocl_probe(struct flash_bank_s *bank)
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
sectsize = bank->size / bank->num_sectors;
|
||||
for (i=0; i<bank->num_sectors; i++)
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
bank->sectors[i].offset = i * sectsize;
|
||||
bank->sectors[i].size = sectsize;
|
||||
@@ -375,16 +364,16 @@ int ocl_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int ocl_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ocl_auto_probe(struct flash_bank_s *bank)
|
||||
static int ocl_auto_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
ocl_priv_t *ocl = bank->driver_priv;
|
||||
|
||||
if (ocl->buflen == 0 || ocl->bufalign==0)
|
||||
if (ocl->buflen == 0 || ocl->bufalign == 0)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -26,10 +26,10 @@ uint32 dcc_rd(void)
|
||||
volatile uint32 dcc_reg;
|
||||
|
||||
do {
|
||||
asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) : );
|
||||
} while ((dcc_reg&1)==0);
|
||||
asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) :);
|
||||
} while ((dcc_reg&1) == 0);
|
||||
|
||||
asm volatile ("mrc p14, 0, %0, C1, C0" : "=r" (dcc_reg) : );
|
||||
asm volatile ("mrc p14, 0, %0, C1, C0" : "=r" (dcc_reg) :);
|
||||
return dcc_reg;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ int dcc_wr(uint32 data)
|
||||
volatile uint32 dcc_reg;
|
||||
|
||||
do {
|
||||
asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) : );
|
||||
asm volatile ("mrc p14, 0, %0, C0, C0" : "=r" (dcc_reg) :);
|
||||
/* operation controled by master, cancel operation
|
||||
upon reception of data for immediate response */
|
||||
if (dcc_reg&1) return -1;
|
||||
|
||||
@@ -39,40 +39,40 @@ void cmd_flash(uint32 cmd)
|
||||
int pagenum;
|
||||
int result;
|
||||
|
||||
adr=dcc_rd();
|
||||
len=cmd&0xffff;
|
||||
ofs=adr%flash_page_size;
|
||||
bi_start=ofs/4;
|
||||
bi_end=(ofs+len+3)/4;
|
||||
adr = dcc_rd();
|
||||
len = cmd&0xffff;
|
||||
ofs = adr%flash_page_size;
|
||||
bi_start = ofs/4;
|
||||
bi_end = (ofs + len + 3)/4;
|
||||
|
||||
if (bi_end>BUFSIZE) {
|
||||
if (bi_end > BUFSIZE) {
|
||||
dcc_wr(OCL_BUFF_OVER);
|
||||
return;
|
||||
}
|
||||
|
||||
chksum=OCL_CHKS_INIT;
|
||||
for (bi=0; bi<bi_end; bi++) chksum^=buffer[bi]=dcc_rd();
|
||||
chksum = OCL_CHKS_INIT;
|
||||
for (bi = 0; bi < bi_end; bi++) chksum^=buffer[bi]=dcc_rd();
|
||||
|
||||
if (dcc_rd()!=chksum) {
|
||||
if (dcc_rd() != chksum) {
|
||||
dcc_wr(OCL_CHKS_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill in unused positions with unprogrammed values */
|
||||
for (bi=0; bi<bi_start; bi++) buffer[bi]=0xffffffff;
|
||||
for (bi=bi_end; bi%flash_page_size; bi++) buffer[bi]=0xffffffff;
|
||||
for (bi = 0; bi < bi_start; bi++) buffer[bi]=0xffffffff;
|
||||
for (bi = bi_end; bi%flash_page_size; bi++) buffer[bi]=0xffffffff;
|
||||
|
||||
result=0;
|
||||
pagenum=adr/flash_page_size;
|
||||
for (bi=0; bi<bi_end; bi+=flash_page_size/4) {
|
||||
result=flash_page_program(buffer+bi, pagenum++);
|
||||
result = 0;
|
||||
pagenum = adr/flash_page_size;
|
||||
for (bi = 0; bi < bi_end; bi += flash_page_size/4) {
|
||||
result = flash_page_program(buffer + bi, pagenum++);
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
/* verify written data */
|
||||
if (!result) result=flash_verify(adr, len, ((uint8 *)buffer)+ofs);
|
||||
if (!result) result = flash_verify(adr, len, ((uint8 *)buffer) + ofs);
|
||||
|
||||
dcc_wr(OCL_CMD_DONE|result);
|
||||
dcc_wr(OCL_CMD_DONE | result);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,17 +81,17 @@ int main (void)
|
||||
uint32 cmd;
|
||||
|
||||
for (;;) {
|
||||
cmd=dcc_rd();
|
||||
cmd = dcc_rd();
|
||||
switch (cmd&OCL_CMD_MASK) {
|
||||
case OCL_PROBE:
|
||||
dcc_wr(OCL_CMD_DONE|flash_init());
|
||||
dcc_wr(OCL_CMD_DONE | flash_init());
|
||||
dcc_wr(0x100000); /* base */
|
||||
dcc_wr(flash_page_count*flash_page_size); /* size */
|
||||
dcc_wr(1); /* num_sectors */
|
||||
dcc_wr(4096 | ((unsigned long) flash_page_size<<16)); /* buflen and bufalign */
|
||||
dcc_wr(4096 | ((unsigned long) flash_page_size << 16)); /* buflen and bufalign */
|
||||
break;
|
||||
case OCL_ERASE_ALL:
|
||||
dcc_wr(OCL_CMD_DONE|flash_erase_all());
|
||||
dcc_wr(OCL_CMD_DONE | flash_erase_all());
|
||||
break;
|
||||
case OCL_FLASH_BLOCK:
|
||||
cmd_flash(cmd);
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#include "samflash.h"
|
||||
|
||||
|
||||
unsigned int flash_page_count=1024;
|
||||
unsigned int flash_page_size=256;
|
||||
unsigned int flash_page_count = 1024;
|
||||
unsigned int flash_page_size = 256;
|
||||
|
||||
/* pages per lock bit */
|
||||
unsigned int flash_lock_pages=1024/16;
|
||||
unsigned int flash_lock_pages = 1024/16;
|
||||
|
||||
|
||||
/* detect chip and set loader parameters */
|
||||
@@ -32,38 +32,38 @@ int flash_init(void)
|
||||
{
|
||||
unsigned int nvpsiz;
|
||||
|
||||
nvpsiz=(inr(DBGU_CIDR)>>8)&0xf;
|
||||
nvpsiz = (inr(DBGU_CIDR) >> 8)&0xf;
|
||||
|
||||
switch (nvpsiz) {
|
||||
case 3:
|
||||
/* AT91SAM7x32 */
|
||||
flash_page_count=256;
|
||||
flash_page_size=128;
|
||||
flash_lock_pages=256/8;
|
||||
flash_page_count = 256;
|
||||
flash_page_size = 128;
|
||||
flash_lock_pages = 256/8;
|
||||
break;
|
||||
case 5:
|
||||
/* AT91SAM7x64 */
|
||||
flash_page_count=512;
|
||||
flash_page_size=128;
|
||||
flash_lock_pages=512/16;
|
||||
flash_page_count = 512;
|
||||
flash_page_size = 128;
|
||||
flash_lock_pages = 512/16;
|
||||
break;
|
||||
case 7:
|
||||
/* AT91SAM7x128*/
|
||||
flash_page_count=512;
|
||||
flash_page_size=256;
|
||||
flash_lock_pages=512/8;
|
||||
flash_page_count = 512;
|
||||
flash_page_size = 256;
|
||||
flash_lock_pages = 512/8;
|
||||
break;
|
||||
case 9:
|
||||
/* AT91SAM7x256 */
|
||||
flash_page_count=1024;
|
||||
flash_page_size=256;
|
||||
flash_lock_pages=1024/16;
|
||||
flash_page_count = 1024;
|
||||
flash_page_size = 256;
|
||||
flash_lock_pages = 1024/16;
|
||||
break;
|
||||
case 10:
|
||||
/* AT91SAM7x512 */
|
||||
flash_page_count=2048;
|
||||
flash_page_size=256;
|
||||
flash_lock_pages=2048/32;
|
||||
flash_page_count = 2048;
|
||||
flash_page_size = 256;
|
||||
flash_lock_pages = 2048/32;
|
||||
break;
|
||||
default:
|
||||
return FLASH_STAT_INITE;
|
||||
@@ -82,39 +82,39 @@ int flash_page_program(uint32 *data, int page_num)
|
||||
uint32 *data_ptr;
|
||||
|
||||
/* select proper controller */
|
||||
if (page_num>=1024) efc_ofs=0x10;
|
||||
else efc_ofs=0;
|
||||
if (page_num >= 1024) efc_ofs = 0x10;
|
||||
else efc_ofs = 0;
|
||||
|
||||
/* wait until FLASH is ready, just for sure */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
/* calculate page address, only lower 8 bits are used to address the latch,
|
||||
but the upper part of address is needed for writing to proper EFC */
|
||||
flash_ptr=(uint32 *)(FLASH_AREA_ADDR+(page_num*flash_page_size));
|
||||
data_ptr=data;
|
||||
flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size));
|
||||
data_ptr = data;
|
||||
|
||||
/* copy data to latch */
|
||||
for (i=flash_page_size/4; i; i--) {
|
||||
for (i = flash_page_size/4; i; i--) {
|
||||
/* we do not use memcpy to be sure that only 32 bit access is used */
|
||||
*(flash_ptr++)=*(data_ptr++);
|
||||
}
|
||||
|
||||
/* page number and page write command to FCR */
|
||||
outr(MC_FCR+efc_ofs, ((page_num&0x3ff)<<8) | MC_KEY | MC_FCMD_WP);
|
||||
outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | MC_KEY | MC_FCMD_WP);
|
||||
|
||||
/* wait until it's done */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
/* check for errors */
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
|
||||
#if 0
|
||||
/* verify written data */
|
||||
flash_ptr=(uint32 *)(FLASH_AREA_ADDR+(page_num*flash_page_size));
|
||||
data_ptr=data;
|
||||
flash_ptr = (uint32 *)(FLASH_AREA_ADDR + (page_num*flash_page_size));
|
||||
data_ptr = data;
|
||||
|
||||
for (i=flash_page_size/4; i; i--) {
|
||||
for (i = flash_page_size/4; i; i--) {
|
||||
if (*(flash_ptr++)!=*(data_ptr++)) return FLASH_STAT_VERIFE;
|
||||
}
|
||||
#endif
|
||||
@@ -128,43 +128,43 @@ int flash_erase_plane(int efc_ofs)
|
||||
unsigned int lockbits;
|
||||
int page_num;
|
||||
|
||||
page_num=0;
|
||||
lockbits=inr(MC_FSR+efc_ofs)>>16;
|
||||
page_num = 0;
|
||||
lockbits = inr(MC_FSR + efc_ofs) >> 16;
|
||||
while (lockbits) {
|
||||
if (lockbits&1) {
|
||||
|
||||
/* wait until FLASH is ready, just for sure */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
outr(MC_FCR+efc_ofs, ((page_num&0x3ff)<<8) | 0x5a000004);
|
||||
outr(MC_FCR + efc_ofs, ((page_num&0x3ff) << 8) | 0x5a000004);
|
||||
|
||||
/* wait until it's done */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
/* check for errors */
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
|
||||
}
|
||||
if ((page_num+=flash_lock_pages)>flash_page_count) break;
|
||||
if ((page_num += flash_lock_pages) > flash_page_count) break;
|
||||
lockbits>>=1;
|
||||
}
|
||||
|
||||
/* wait until FLASH is ready, just for sure */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
/* erase all command to FCR */
|
||||
outr(MC_FCR+efc_ofs, 0x5a000008);
|
||||
outr(MC_FCR + efc_ofs, 0x5a000008);
|
||||
|
||||
/* wait until it's done */
|
||||
while ((inr(MC_FSR+efc_ofs)&MC_FRDY)==0);
|
||||
while ((inr(MC_FSR + efc_ofs)&MC_FRDY) == 0);
|
||||
|
||||
/* check for errors */
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR+efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_PROGE)) return FLASH_STAT_PROGE;
|
||||
if ((inr(MC_FSR + efc_ofs)&MC_LOCKE)) return FLASH_STAT_LOCKE;
|
||||
|
||||
/* set no erase before programming */
|
||||
outr(MC_FMR+efc_ofs, inr(MC_FMR+efc_ofs)|0x80);
|
||||
outr(MC_FMR + efc_ofs, inr(MC_FMR + efc_ofs) | 0x80);
|
||||
|
||||
return FLASH_STAT_OK;
|
||||
}
|
||||
@@ -175,10 +175,10 @@ int flash_erase_all(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result=flash_erase_plane(0))!=FLASH_STAT_OK) return result;
|
||||
if ((result = flash_erase_plane(0)) != FLASH_STAT_OK) return result;
|
||||
|
||||
/* the second flash controller, if any */
|
||||
if (flash_page_count>1024) result=flash_erase_plane(0x10);
|
||||
if (flash_page_count > 1024) result = flash_erase_plane(0x10);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -188,8 +188,8 @@ int flash_verify(uint32 adr, unsigned int len, uint8 *src)
|
||||
{
|
||||
unsigned char *flash_ptr;
|
||||
|
||||
flash_ptr=(uint8 *)FLASH_AREA_ADDR+adr;
|
||||
for ( ;len; len--) {
|
||||
flash_ptr = (uint8 *)FLASH_AREA_ADDR + adr;
|
||||
for (;len; len--) {
|
||||
if (*(flash_ptr++)!=*(src++)) return FLASH_STAT_VERIFE;
|
||||
}
|
||||
return FLASH_STAT_OK;
|
||||
|
||||
188
src/flash/orion_nand.c
Normal file
188
src/flash/orion_nand.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Marvell Semiconductors, Inc. *
|
||||
* Written by Nicolas Pitre <nico at marvell.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. *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* NAND controller interface for Marvell Orion/Kirkwood SoCs.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arm_nandio.h"
|
||||
#include "armv4_5.h"
|
||||
|
||||
|
||||
typedef struct orion_nand_controller_s
|
||||
{
|
||||
struct target_s *target;
|
||||
|
||||
struct arm_nand_data io;
|
||||
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t data;
|
||||
} orion_nand_controller_t;
|
||||
|
||||
#define CHECK_HALTED \
|
||||
do { \
|
||||
if (target->state != TARGET_HALTED) { \
|
||||
LOG_ERROR("NAND flash access requires halted target"); \
|
||||
return ERROR_NAND_OPERATION_FAILED; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int orion_nand_command(struct nand_device_s *device, uint8_t command)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->cmd, command);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_address(struct nand_device_s *device, uint8_t address)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->addr, address);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_read(struct nand_device_s *device, void *data)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_read_u8(target, hw->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_write(struct nand_device_s *device, uint16_t data)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
target_t *target = hw->target;
|
||||
|
||||
CHECK_HALTED;
|
||||
target_write_u8(target, hw->data, data);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_slow_block_write(struct nand_device_s *device, uint8_t *data, int size)
|
||||
{
|
||||
while (size--)
|
||||
orion_nand_write(device, *data++);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_fast_block_write(struct nand_device_s *device, uint8_t *data, int size)
|
||||
{
|
||||
orion_nand_controller_t *hw = device->controller_priv;
|
||||
int retval;
|
||||
|
||||
hw->io.chunk_size = device->page_size;
|
||||
|
||||
retval = arm_nandwrite(&hw->io, data, size);
|
||||
if (retval == ERROR_NAND_NO_BUFFER)
|
||||
retval = orion_nand_slow_block_write(device, data, size);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int orion_nand_reset(struct nand_device_s *device)
|
||||
{
|
||||
return orion_nand_command(device, NAND_CMD_RESET);
|
||||
}
|
||||
|
||||
static int orion_nand_controller_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int orion_nand_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int orion_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
orion_nand_controller_t *hw;
|
||||
uint32_t base;
|
||||
uint8_t ale, cle;
|
||||
|
||||
if (argc != 3) {
|
||||
LOG_ERROR("arguments must be: <target_id> <NAND_address>\n");
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
hw = calloc(1, sizeof(*hw));
|
||||
if (!hw) {
|
||||
LOG_ERROR("no memory for nand controller\n");
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
device->controller_priv = hw;
|
||||
hw->target = get_target(args[1]);
|
||||
if (!hw->target) {
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
free(hw);
|
||||
return ERROR_NAND_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
base = strtoul(args[2], NULL, 0);
|
||||
cle = 0;
|
||||
ale = 1;
|
||||
|
||||
hw->data = base;
|
||||
hw->cmd = base + (1 << cle);
|
||||
hw->addr = base + (1 << ale);
|
||||
|
||||
hw->io.target = hw->target;
|
||||
hw->io.data = hw->data;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int orion_nand_init(struct nand_device_s *device)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
nand_flash_controller_t orion_nand_controller =
|
||||
{
|
||||
.name = "orion",
|
||||
.command = orion_nand_command,
|
||||
.address = orion_nand_address,
|
||||
.read_data = orion_nand_read,
|
||||
.write_data = orion_nand_write,
|
||||
.write_block_data = orion_nand_fast_block_write,
|
||||
.reset = orion_nand_reset,
|
||||
.controller_ready = orion_nand_controller_ready,
|
||||
.nand_device_command = orion_nand_device_command,
|
||||
.register_commands = orion_nand_register_commands,
|
||||
.init = orion_nand_init,
|
||||
};
|
||||
|
||||
@@ -27,24 +27,15 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "pic32mx.h"
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "mips32.h"
|
||||
#include "algorithm.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static
|
||||
struct pic32mx_devs_s {
|
||||
u8 devid;
|
||||
uint8_t devid;
|
||||
char *name;
|
||||
u32 pfm_size;
|
||||
uint32_t pfm_size;
|
||||
} pic32mx_devs[] = {
|
||||
{ 0x78, "460F512L USB", 512 },
|
||||
{ 0x74, "460F256L USB", 256 },
|
||||
@@ -66,26 +57,26 @@ struct pic32mx_devs_s {
|
||||
{ 0x00, NULL, 0 }
|
||||
};
|
||||
|
||||
int pic32mx_register_commands(struct command_context_s *cmd_ctx);
|
||||
int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int pic32mx_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int pic32mx_write_row(struct flash_bank_s *bank, u32 address, u32 srcaddr);
|
||||
int pic32mx_write_word(struct flash_bank_s *bank, u32 address, u32 word);
|
||||
int pic32mx_probe(struct flash_bank_s *bank);
|
||||
int pic32mx_auto_probe(struct flash_bank_s *bank);
|
||||
int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int pic32mx_protect_check(struct flash_bank_s *bank);
|
||||
int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int pic32mx_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int pic32mx_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int pic32mx_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int pic32mx_write_row(struct flash_bank_s *bank, uint32_t address, uint32_t srcaddr);
|
||||
static int pic32mx_write_word(struct flash_bank_s *bank, uint32_t address, uint32_t word);
|
||||
static int pic32mx_probe(struct flash_bank_s *bank);
|
||||
static int pic32mx_auto_probe(struct flash_bank_s *bank);
|
||||
//static int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int pic32mx_protect_check(struct flash_bank_s *bank);
|
||||
static int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
#if 0
|
||||
int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
#endif
|
||||
int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int pic32mx_chip_erase(struct flash_bank_s *bank);
|
||||
static int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
//static int pic32mx_chip_erase(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t pic32mx_flash =
|
||||
{
|
||||
@@ -102,7 +93,7 @@ flash_driver_t pic32mx_flash =
|
||||
.info = pic32mx_info
|
||||
};
|
||||
|
||||
int pic32mx_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int pic32mx_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *pic32mx_cmd = register_command(cmd_ctx, NULL, "pic32mx", NULL, COMMAND_ANY, "pic32mx flash specific commands");
|
||||
|
||||
@@ -121,7 +112,7 @@ int pic32mx_register_commands(struct command_context_s *cmd_ctx)
|
||||
|
||||
/* flash bank pic32mx <base> <size> 0 0 <target#>
|
||||
*/
|
||||
int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info;
|
||||
|
||||
@@ -140,38 +131,38 @@ int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 pic32mx_get_flash_status(flash_bank_t *bank)
|
||||
static uint32_t pic32mx_get_flash_status(flash_bank_t *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
target_read_u32(target, PIC32MX_NVMCON, &status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
u32 pic32mx_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t pic32mx_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
/* wait for busy to clear */
|
||||
while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0))
|
||||
{
|
||||
LOG_DEBUG("status: 0x%x", status);
|
||||
LOG_DEBUG("status: 0x%" PRIx32, status);
|
||||
alive_sleep(1);
|
||||
}
|
||||
if(timeout <= 0)
|
||||
LOG_DEBUG("timeout: status: 0x%x", status);
|
||||
if (timeout <= 0)
|
||||
LOG_DEBUG("timeout: status: 0x%" PRIx32, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int pic32mx_nvm_exec(struct flash_bank_s *bank, u32 op, u32 timeout)
|
||||
static int pic32mx_nvm_exec(struct flash_bank_s *bank, uint32_t op, uint32_t timeout)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN|op);
|
||||
target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op);
|
||||
|
||||
/* unlock flash registers */
|
||||
target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);
|
||||
@@ -188,11 +179,11 @@ int pic32mx_nvm_exec(struct flash_bank_s *bank, u32 op, u32 timeout)
|
||||
return status;
|
||||
}
|
||||
|
||||
int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
static int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
|
||||
u32 devcfg0;
|
||||
uint32_t devcfg0;
|
||||
int s;
|
||||
int num_pages;
|
||||
|
||||
@@ -203,11 +194,11 @@ int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
}
|
||||
|
||||
target_read_u32(target, PIC32MX_DEVCFG0, &devcfg0);
|
||||
if((devcfg0 & (1<<28)) == 0) /* code protect bit */
|
||||
if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */
|
||||
num_pages = 0xffff; /* All pages protected */
|
||||
else if(bank->base == PIC32MX_KSEG1_BOOT_FLASH)
|
||||
else if (bank->base == PIC32MX_KSEG1_BOOT_FLASH)
|
||||
{
|
||||
if(devcfg0 & (1<<24))
|
||||
if (devcfg0 & (1 << 24))
|
||||
num_pages = 0; /* All pages unprotected */
|
||||
else
|
||||
num_pages = 0xffff; /* All pages protected */
|
||||
@@ -222,11 +213,11 @@ int pic32mx_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
int i;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -238,25 +229,25 @@ int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
LOG_DEBUG("Erasing entire program flash");
|
||||
status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);
|
||||
if( status & NVMCON_NVMERR )
|
||||
if (status & NVMCON_NVMERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & NVMCON_LVDERR )
|
||||
if (status & NVMCON_LVDERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
if(bank->base >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(bank->base + bank->sectors[i].offset));
|
||||
else
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(bank->base + bank->sectors[i].offset));
|
||||
|
||||
status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);
|
||||
|
||||
if( status & NVMCON_NVMERR )
|
||||
if (status & NVMCON_NVMERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & NVMCON_LVDERR )
|
||||
if (status & NVMCON_LVDERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
@@ -264,14 +255,16 @@ int pic32mx_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
u16 prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
#if 0
|
||||
uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
int i, reg, bit;
|
||||
int status;
|
||||
u32 protection;
|
||||
uint32_t protection;
|
||||
#endif
|
||||
|
||||
pic32mx_info = bank->driver_priv;
|
||||
|
||||
@@ -292,10 +285,10 @@ int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
* high density - each bit refers to a 2bank protection */
|
||||
target_read_u32(target, PIC32MX_FLASH_WRPR, &protection);
|
||||
|
||||
prot_reg[0] = (u16)protection;
|
||||
prot_reg[1] = (u16)(protection >> 8);
|
||||
prot_reg[2] = (u16)(protection >> 16);
|
||||
prot_reg[3] = (u16)(protection >> 24);
|
||||
prot_reg[0] = (uint16_t)protection;
|
||||
prot_reg[1] = (uint16_t)(protection >> 8);
|
||||
prot_reg[2] = (uint16_t)(protection >> 16);
|
||||
prot_reg[3] = (uint16_t)(protection >> 24);
|
||||
|
||||
if (pic32mx_info->ppage_size == 2)
|
||||
{
|
||||
@@ -320,7 +313,7 @@ int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
reg = (i / pic32mx_info->ppage_size) / 8;
|
||||
bit = (i / pic32mx_info->ppage_size) - (reg * 8);
|
||||
|
||||
if( set )
|
||||
if (set)
|
||||
prot_reg[reg] &= ~(1 << bit);
|
||||
else
|
||||
prot_reg[reg] |= (1 << bit);
|
||||
@@ -334,7 +327,7 @@ int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
reg = (i / pic32mx_info->ppage_size) / 8;
|
||||
bit = (i / pic32mx_info->ppage_size) - (reg * 8);
|
||||
|
||||
if( set )
|
||||
if (set)
|
||||
prot_reg[reg] &= ~(1 << bit);
|
||||
else
|
||||
prot_reg[reg] |= (1 << bit);
|
||||
@@ -355,18 +348,18 @@ int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
#endif
|
||||
}
|
||||
|
||||
int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int pic32mx_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 buffer_size = 512;
|
||||
uint32_t buffer_size = 512;
|
||||
working_area_t *source;
|
||||
u32 address = bank->base + offset;
|
||||
uint32_t address = bank->base + offset;
|
||||
int retval = ERROR_OK;
|
||||
#if 0
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
armv7m_algorithm_t armv7m_info;
|
||||
|
||||
u8 pic32mx_flash_write_code[] = {
|
||||
uint8_t pic32mx_flash_write_code[] = {
|
||||
/* write: */
|
||||
0xDF, 0xF8, 0x24, 0x40, /* ldr r4, PIC32MX_FLASH_CR */
|
||||
0x09, 0x4D, /* ldr r5, PIC32MX_FLASH_SR */
|
||||
@@ -395,7 +388,7 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
|
||||
if ((retval=target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code))!=ERROR_OK)
|
||||
if ((retval = target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code)) != ERROR_OK)
|
||||
return retval;
|
||||
#endif
|
||||
|
||||
@@ -414,10 +407,10 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
|
||||
while (count >= buffer_size/4)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
if ((retval = target_write_buffer(target, source->address, buffer_size, buffer))!=ERROR_OK) {
|
||||
LOG_ERROR("Failed to write row buffer (%d words) to RAM", buffer_size/4);
|
||||
if ((retval = target_write_buffer(target, source->address, buffer_size, buffer)) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to write row buffer (%d words) to RAM", (int)(buffer_size/4));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -426,7 +419,7 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
buf_set_u32(reg_params[1].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, buffer_size/4);
|
||||
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \
|
||||
pic32mx_info->write_algorithm->address + (sizeof(pic32mx_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error executing pic32mx flash write algorithm");
|
||||
@@ -441,13 +434,13 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
}
|
||||
#endif
|
||||
status = pic32mx_write_row(bank, address, source->address);
|
||||
if( status & NVMCON_NVMERR ) {
|
||||
LOG_ERROR("Flash write error NVMERR (status=0x%08x)", status);
|
||||
if (status & NVMCON_NVMERR) {
|
||||
LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
if( status & NVMCON_LVDERR ) {
|
||||
LOG_ERROR("Flash write error LVDERR (status=0x%08x)", status);
|
||||
if (status & NVMCON_LVDERR) {
|
||||
LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
@@ -459,18 +452,19 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
|
||||
target_free_working_area(target, source);
|
||||
|
||||
while(count > 0)
|
||||
while (count > 0)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t value;
|
||||
memcpy(&value, buffer, sizeof(uint32_t));
|
||||
|
||||
status = pic32mx_write_word(bank, address, *(u32*)buffer);
|
||||
if( status & NVMCON_NVMERR ) {
|
||||
LOG_ERROR("Flash write error NVMERR (status=0x%08x)", status);
|
||||
uint32_t status = pic32mx_write_word(bank, address, value);
|
||||
if (status & NVMCON_NVMERR) {
|
||||
LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
if( status & NVMCON_LVDERR ) {
|
||||
LOG_ERROR("Flash write error LVDERR (status=0x%08x)", status);
|
||||
if (status & NVMCON_LVDERR) {
|
||||
LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
@@ -483,11 +477,11 @@ int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 c
|
||||
return retval;
|
||||
}
|
||||
|
||||
int pic32mx_write_word(struct flash_bank_s *bank, u32 address, u32 word)
|
||||
static int pic32mx_write_word(struct flash_bank_s *bank, uint32_t address, uint32_t word)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
|
||||
if(bank->base >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
if (bank->base >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
|
||||
else
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(address));
|
||||
@@ -499,17 +493,17 @@ int pic32mx_write_word(struct flash_bank_s *bank, u32 address, u32 word)
|
||||
/*
|
||||
* Write a 128 word (512 byte) row to flash address from RAM srcaddr.
|
||||
*/
|
||||
int pic32mx_write_row(struct flash_bank_s *bank, u32 address, u32 srcaddr)
|
||||
static int pic32mx_write_row(struct flash_bank_s *bank, uint32_t address, uint32_t srcaddr)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
|
||||
LOG_DEBUG("addr: 0x%08x srcaddr: 0x%08x", address, srcaddr);
|
||||
LOG_DEBUG("addr: 0x%08" PRIx32 " srcaddr: 0x%08" PRIx32 "", address, srcaddr);
|
||||
|
||||
if(address >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
if (address >= PIC32MX_KSEG1_PGM_FLASH)
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS1Virt2Phys(address));
|
||||
else
|
||||
target_write_u32(target, PIC32MX_NVMADDR, KS0Virt2Phys(address));
|
||||
if(srcaddr >= PIC32MX_KSEG1_RAM)
|
||||
if (srcaddr >= PIC32MX_KSEG1_RAM)
|
||||
target_write_u32(target, PIC32MX_NVMSRCADDR, KS1Virt2Phys(srcaddr));
|
||||
else
|
||||
target_write_u32(target, PIC32MX_NVMSRCADDR, KS0Virt2Phys(srcaddr));
|
||||
@@ -517,14 +511,14 @@ int pic32mx_write_row(struct flash_bank_s *bank, u32 address, u32 srcaddr)
|
||||
return pic32mx_nvm_exec(bank, NVMCON_OP_ROW_PROG, 100);
|
||||
}
|
||||
|
||||
int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int pic32mx_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
u32 words_remaining = (count / 4);
|
||||
u32 bytes_remaining = (count & 0x00000003);
|
||||
u32 address = bank->base + offset;
|
||||
u32 bytes_written = 0;
|
||||
u32 status;
|
||||
u32 retval;
|
||||
uint32_t words_remaining = (count / 4);
|
||||
uint32_t bytes_remaining = (count & 0x00000003);
|
||||
uint32_t address = bank->base + offset;
|
||||
uint32_t bytes_written = 0;
|
||||
uint32_t status;
|
||||
int retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -534,7 +528,7 @@ int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (offset & 0x3)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required 4-byte alignment", offset);
|
||||
LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
@@ -566,11 +560,13 @@ int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
while (words_remaining > 0)
|
||||
{
|
||||
status = pic32mx_write_word(bank, address, *(u32*)(buffer + bytes_written));
|
||||
uint32_t value;
|
||||
memcpy(&value, buffer + bytes_written, sizeof(uint32_t));
|
||||
|
||||
if( status & NVMCON_NVMERR )
|
||||
status = pic32mx_write_word(bank, address, value);
|
||||
if (status & NVMCON_NVMERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & NVMCON_LVDERR )
|
||||
if (status & NVMCON_LVDERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
bytes_written += 4;
|
||||
@@ -580,62 +576,57 @@ int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (bytes_remaining)
|
||||
{
|
||||
u8 last_word[4] = {0xff, 0xff, 0xff, 0xff};
|
||||
int i = 0;
|
||||
uint32_t value = 0xffffffff;
|
||||
memcpy(&value, buffer + bytes_written, bytes_remaining);
|
||||
|
||||
while(bytes_remaining > 0)
|
||||
{
|
||||
/* Assumes little endian */
|
||||
last_word[i++] = *(buffer + bytes_written);
|
||||
bytes_remaining--;
|
||||
bytes_written++;
|
||||
}
|
||||
|
||||
status = pic32mx_write_word(bank, address, *(u32*)last_word);
|
||||
|
||||
if( status & NVMCON_NVMERR )
|
||||
status = pic32mx_write_word(bank, address, value);
|
||||
if (status & NVMCON_NVMERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & NVMCON_LVDERR )
|
||||
if (status & NVMCON_LVDERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_probe(struct flash_bank_s *bank)
|
||||
static int pic32mx_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
mips32_common_t *mips32 = target->arch_info;
|
||||
mips_ejtag_t *ejtag_info = &mips32->ejtag_info;
|
||||
int i;
|
||||
u16 num_pages;
|
||||
u32 device_id;
|
||||
uint16_t num_pages = 0;
|
||||
uint32_t device_id;
|
||||
int page_size;
|
||||
|
||||
pic32mx_info->probed = 0;
|
||||
|
||||
device_id = ejtag_info->idcode;
|
||||
LOG_INFO( "device id = 0x%08x (manuf 0x%03x dev 0x%02x, ver 0x%03x)", device_id, (device_id>>1)&0x7ff, (device_id>>12)&0xff, (device_id>>20)&0xfff );
|
||||
LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%02x, ver 0x%03x)",
|
||||
device_id,
|
||||
(unsigned)((device_id >> 1)&0x7ff),
|
||||
(unsigned)((device_id >> 12)&0xff),
|
||||
(unsigned)((device_id >> 20)&0xfff));
|
||||
|
||||
if(((device_id>>1)&0x7ff) != PIC32MX_MANUF_ID) {
|
||||
LOG_WARNING( "Cannot identify target as a PIC32MX family." );
|
||||
if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
|
||||
LOG_WARNING("Cannot identify target as a PIC32MX family.");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
page_size = 4096;
|
||||
if(bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {
|
||||
if (bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {
|
||||
/* 0xBFC00000: Boot flash size fixed at 12k */
|
||||
num_pages = 12;
|
||||
} else {
|
||||
/* 0xBD000000: Program flash size varies with device */
|
||||
for(i=0; pic32mx_devs[i].name != NULL; i++)
|
||||
if(pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
|
||||
for (i = 0; pic32mx_devs[i].name != NULL; i++)
|
||||
if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
|
||||
num_pages = pic32mx_devs[i].pfm_size;
|
||||
break;
|
||||
}
|
||||
if(pic32mx_devs[i].name == NULL) {
|
||||
LOG_WARNING( "Cannot identify target as a PIC32MX family." );
|
||||
if (pic32mx_devs[i].name == NULL) {
|
||||
LOG_WARNING("Cannot identify target as a PIC32MX family.");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
@@ -655,13 +646,13 @@ int pic32mx_probe(struct flash_bank_s *bank)
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_INFO( "flash size = %dkbytes", num_pages );
|
||||
LOG_INFO("flash size = %dkbytes", num_pages);
|
||||
|
||||
/* calculate numbers of pages */
|
||||
num_pages /= (page_size / 1024);
|
||||
|
||||
if(bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;
|
||||
if(bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;
|
||||
if (bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;
|
||||
if (bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;
|
||||
bank->size = (num_pages * page_size);
|
||||
bank->num_sectors = num_pages;
|
||||
bank->chip_width = 4;
|
||||
@@ -681,7 +672,7 @@ int pic32mx_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_auto_probe(struct flash_bank_s *bank)
|
||||
static int pic32mx_auto_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;
|
||||
if (pic32mx_info->probed)
|
||||
@@ -689,37 +680,43 @@ int pic32mx_auto_probe(struct flash_bank_s *bank)
|
||||
return pic32mx_probe(bank);
|
||||
}
|
||||
|
||||
int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
#if 0
|
||||
static int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
mips32_common_t *mips32 = target->arch_info;
|
||||
mips_ejtag_t *ejtag_info = &mips32->ejtag_info;
|
||||
u32 device_id;
|
||||
int printed, i;
|
||||
uint32_t device_id;
|
||||
int printed = 0, i;
|
||||
|
||||
device_id = ejtag_info->idcode;
|
||||
|
||||
if(((device_id>>1)&0x7ff) != PIC32MX_MANUF_ID) {
|
||||
snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n", (device_id>>1)&0x7ff, PIC32MX_MANUF_ID);
|
||||
if (((device_id >> 1)&0x7ff) != PIC32MX_MANUF_ID) {
|
||||
snprintf(buf, buf_size,
|
||||
"Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n",
|
||||
(unsigned)((device_id >> 1)&0x7ff),
|
||||
PIC32MX_MANUF_ID);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
for(i=0; pic32mx_devs[i].name != NULL; i++)
|
||||
if(pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
|
||||
for (i = 0; pic32mx_devs[i].name != NULL; i++)
|
||||
if (pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {
|
||||
printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);
|
||||
break;
|
||||
}
|
||||
if(pic32mx_devs[i].name == NULL) {
|
||||
if (pic32mx_devs[i].name == NULL) {
|
||||
snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family\n");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
printed = snprintf(buf, buf_size, " Ver: 0x%03x", (device_id>>20)&0xfff);
|
||||
printed = snprintf(buf, buf_size, " Ver: 0x%03x",
|
||||
(unsigned)((device_id >> 20)&0xfff));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -821,10 +818,13 @@ int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
}
|
||||
#endif
|
||||
|
||||
int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
#if 0
|
||||
static int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
#if 0
|
||||
uint32_t status;
|
||||
#endif
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -841,19 +841,19 @@ int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
|
||||
/* chip erase flash memory */
|
||||
target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER);
|
||||
target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER|FLASH_STRT);
|
||||
target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER | FLASH_STRT);
|
||||
|
||||
status = pic32mx_wait_status_busy(bank, 10);
|
||||
|
||||
target_write_u32(target, PIC32MX_FLASH_CR, FLASH_LOCK);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
{
|
||||
LOG_ERROR("pic32mx device protected");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
{
|
||||
LOG_ERROR("pic32mx device programming failed");
|
||||
return ERROR_OK;
|
||||
@@ -862,13 +862,14 @@ int pic32mx_chip_erase(struct flash_bank_s *bank)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
#if 0
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
if (argc != 0)
|
||||
{
|
||||
command_print(cmd_ctx, "pic32mx chip_erase");
|
||||
@@ -901,10 +902,10 @@ int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *c
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
u32 address, value;
|
||||
uint32_t address, value;
|
||||
int status, res;
|
||||
|
||||
if (argc != 3)
|
||||
@@ -922,7 +923,7 @@ int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[2]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (address < bank->base || address >= (bank->base+bank->size))
|
||||
if (address < bank->base || address >= (bank->base + bank->size))
|
||||
{
|
||||
command_print(cmd_ctx, "flash address '%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
@@ -930,15 +931,15 @@ int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd
|
||||
|
||||
res = ERROR_OK;
|
||||
status = pic32mx_write_word(bank, address, value);
|
||||
if( status & NVMCON_NVMERR )
|
||||
if (status & NVMCON_NVMERR)
|
||||
res = ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & NVMCON_LVDERR )
|
||||
if (status & NVMCON_LVDERR)
|
||||
res = ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
if (res == ERROR_OK)
|
||||
command_print(cmd_ctx, "pic32mx pgm word complete");
|
||||
else
|
||||
command_print(cmd_ctx, "pic32mx pgm word failed (status=0x%x)", status);
|
||||
command_print(cmd_ctx, "pic32mx pgm word failed (status = 0x%x)", status);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#define PIC32MX_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct pic32mx_flash_bank_s
|
||||
{
|
||||
@@ -63,9 +62,9 @@ typedef struct pic32mx_flash_bank_s
|
||||
* Note: These macros only work for KSEG0/KSEG1 addresses.
|
||||
*/
|
||||
#define KS1Virt2Phys(vaddr) ((vaddr)-0xA0000000)
|
||||
#define Phys2KS1Virt(paddr) ((paddr)+0xA0000000)
|
||||
#define Phys2KS1Virt(paddr) ((paddr) + 0xA0000000)
|
||||
#define KS0Virt2Phys(vaddr) ((vaddr)-0x80000000)
|
||||
#define Phys2KS0Virt(paddr) ((paddr)+0x80000000)
|
||||
#define Phys2KS0Virt(paddr) ((paddr) + 0x80000000)
|
||||
|
||||
/* pic32mx configuration register locations */
|
||||
|
||||
@@ -81,11 +80,11 @@ typedef struct pic32mx_flash_bank_s
|
||||
#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_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
|
||||
@@ -106,8 +105,8 @@ typedef struct pic32mx_flash_bank_s
|
||||
#define NVMKEY2 0x556699AA
|
||||
|
||||
typedef struct pic32mx_mem_layout_s {
|
||||
u32 sector_start;
|
||||
u32 sector_size;
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
} pic32mx_mem_layout_t;
|
||||
|
||||
#endif /* PIC32MX_H */
|
||||
|
||||
@@ -28,21 +28,14 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "target.h"
|
||||
|
||||
int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int s3c2410_init(struct nand_device_s *device);
|
||||
int s3c2410_read_data(struct nand_device_s *device, void *data);
|
||||
int s3c2410_write_data(struct nand_device_s *device, u16 data);
|
||||
int s3c2410_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
static int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2410_init(struct nand_device_s *device);
|
||||
static int s3c2410_read_data(struct nand_device_s *device, void *data);
|
||||
static int s3c2410_write_data(struct nand_device_s *device, uint16_t data);
|
||||
static int s3c2410_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
nand_flash_controller_t s3c2410_nand_controller =
|
||||
{
|
||||
@@ -61,7 +54,7 @@ nand_flash_controller_t s3c2410_nand_controller =
|
||||
.nand_ready = s3c2410_nand_ready,
|
||||
};
|
||||
|
||||
int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
static int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
@@ -81,7 +74,7 @@ int s3c2410_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2410_init(struct nand_device_s *device)
|
||||
static int s3c2410_init(struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -93,7 +86,7 @@ int s3c2410_init(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2410_write_data(struct nand_device_s *device, u16 data)
|
||||
static int s3c2410_write_data(struct nand_device_s *device, uint16_t data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -107,7 +100,7 @@ int s3c2410_write_data(struct nand_device_s *device, u16 data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2410_read_data(struct nand_device_s *device, void *data)
|
||||
static int s3c2410_read_data(struct nand_device_s *device, void *data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -121,11 +114,11 @@ int s3c2410_read_data(struct nand_device_s *device, void *data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2410_nand_ready(struct nand_device_s *device, int timeout)
|
||||
static int s3c2410_nand_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
u8 status;
|
||||
uint8_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
|
||||
@@ -28,18 +28,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "target.h"
|
||||
|
||||
int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int s3c2412_init(struct nand_device_s *device);
|
||||
|
||||
static int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2412_init(struct nand_device_s *device);
|
||||
|
||||
nand_flash_controller_t s3c2412_nand_controller =
|
||||
{
|
||||
@@ -60,7 +53,7 @@ nand_flash_controller_t s3c2412_nand_controller =
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
static int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
@@ -80,7 +73,7 @@ int s3c2412_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2412_init(struct nand_device_s *device)
|
||||
static int s3c2412_init(struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
|
||||
@@ -28,19 +28,12 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "target.h"
|
||||
|
||||
int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int s3c2440_init(struct nand_device_s *device);
|
||||
int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
static int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2440_init(struct nand_device_s *device);
|
||||
//static int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
nand_flash_controller_t s3c2440_nand_controller =
|
||||
{
|
||||
@@ -61,7 +54,7 @@ nand_flash_controller_t s3c2440_nand_controller =
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
static int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
@@ -81,7 +74,7 @@ int s3c2440_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2440_init(struct nand_device_s *device)
|
||||
static int s3c2440_init(struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -101,7 +94,7 @@ int s3c2440_nand_ready(struct nand_device_s *device, int timeout)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
u8 status;
|
||||
uint8_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
@@ -123,12 +116,12 @@ int s3c2440_nand_ready(struct nand_device_s *device, int timeout)
|
||||
|
||||
/* use the fact we can read/write 4 bytes in one go via a single 32bit op */
|
||||
|
||||
int s3c2440_read_block_data(struct nand_device_s *device, u8 *data, int data_size)
|
||||
int s3c2440_read_block_data(struct nand_device_s *device, uint8_t *data, int data_size)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
u32 nfdata = s3c24xx_info->data;
|
||||
u32 tmp;
|
||||
uint32_t nfdata = s3c24xx_info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
LOG_INFO("%s: reading data: %p, %p, %d\n", __func__, device, data, data_size);
|
||||
|
||||
@@ -159,12 +152,12 @@ int s3c2440_read_block_data(struct nand_device_s *device, u8 *data, int data_siz
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2440_write_block_data(struct nand_device_s *device, u8 *data, int data_size)
|
||||
int s3c2440_write_block_data(struct nand_device_s *device, uint8_t *data, int data_size)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
u32 nfdata = s3c24xx_info->data;
|
||||
u32 tmp;
|
||||
uint32_t nfdata = s3c24xx_info->data;
|
||||
uint32_t tmp;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("target must be halted to use S3C24XX NAND flash controller");
|
||||
|
||||
@@ -28,19 +28,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "target.h"
|
||||
|
||||
int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
int s3c2443_init(struct nand_device_s *device);
|
||||
int s3c2443_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
static int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
|
||||
static int s3c2443_init(struct nand_device_s *device);
|
||||
|
||||
nand_flash_controller_t s3c2443_nand_controller =
|
||||
{
|
||||
@@ -61,7 +53,7 @@ nand_flash_controller_t s3c2443_nand_controller =
|
||||
.nand_ready = s3c2440_nand_ready,
|
||||
};
|
||||
|
||||
int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
static int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
char **args, int argc,
|
||||
struct nand_device_s *device)
|
||||
{
|
||||
@@ -81,7 +73,7 @@ int s3c2443_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c2443_init(struct nand_device_s *device)
|
||||
static int s3c2443_init(struct nand_device_s *device)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
|
||||
@@ -28,15 +28,8 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_nand.h"
|
||||
#include "target.h"
|
||||
|
||||
|
||||
s3c24xx_nand_controller_t *
|
||||
s3c24xx_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
@@ -53,9 +46,9 @@ s3c24xx_nand_device_command(struct command_context_s *cmd_ctx, char *cmd,
|
||||
|
||||
device->controller_priv = s3c24xx_info;
|
||||
|
||||
s3c24xx_info->target = get_target_by_num(strtoul(args[1], NULL, 0));
|
||||
s3c24xx_info->target = get_target(args[1]);
|
||||
if (s3c24xx_info->target == NULL) {
|
||||
LOG_ERROR("no target '%s' configured", args[1]);
|
||||
LOG_ERROR("target '%s' not defined", args[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -82,7 +75,7 @@ int s3c24xx_reset(struct nand_device_s *device)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_command(struct nand_device_s *device, u8 command)
|
||||
int s3c24xx_command(struct nand_device_s *device, uint8_t command)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -97,7 +90,7 @@ int s3c24xx_command(struct nand_device_s *device, u8 command)
|
||||
}
|
||||
|
||||
|
||||
int s3c24xx_address(struct nand_device_s *device, u8 address)
|
||||
int s3c24xx_address(struct nand_device_s *device, uint8_t address)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
@@ -111,7 +104,7 @@ int s3c24xx_address(struct nand_device_s *device, u8 address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int s3c24xx_write_data(struct nand_device_s *device, u16 data)
|
||||
int s3c24xx_write_data(struct nand_device_s *device, uint16_t data)
|
||||
{
|
||||
s3c24xx_nand_controller_t *s3c24xx_info = device->controller_priv;
|
||||
target_t *target = s3c24xx_info->target;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* Many thanks to Simtec Electronics for sponsoring this work.
|
||||
*/
|
||||
|
||||
#include "target.h"
|
||||
#include "nand.h"
|
||||
#include "s3c24xx_regs_nand.h"
|
||||
|
||||
typedef struct s3c24xx_nand_controller_s
|
||||
@@ -32,10 +32,10 @@ typedef struct s3c24xx_nand_controller_s
|
||||
struct target_s *target;
|
||||
|
||||
/* register addresses */
|
||||
u32 cmd;
|
||||
u32 addr;
|
||||
u32 data;
|
||||
u32 nfstat;
|
||||
uint32_t cmd;
|
||||
uint32_t addr;
|
||||
uint32_t data;
|
||||
uint32_t nfstat;
|
||||
} s3c24xx_nand_controller_t;
|
||||
|
||||
/* Default to using the un-translated NAND register based address */
|
||||
@@ -46,9 +46,9 @@ extern s3c24xx_nand_controller_t *s3c24xx_nand_device_command(struct command_con
|
||||
|
||||
extern int s3c24xx_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int s3c24xx_reset(struct nand_device_s *device);
|
||||
extern int s3c24xx_command(struct nand_device_s *device, u8 command);
|
||||
extern int s3c24xx_address(struct nand_device_s *device, u8 address);
|
||||
extern int s3c24xx_write_data(struct nand_device_s *device, u16 data);
|
||||
extern int s3c24xx_command(struct nand_device_s *device, uint8_t command);
|
||||
extern int s3c24xx_address(struct nand_device_s *device, uint8_t address);
|
||||
extern int s3c24xx_write_data(struct nand_device_s *device, uint16_t data);
|
||||
extern int s3c24xx_read_data(struct nand_device_s *device, void *data);
|
||||
extern int s3c24xx_controller_ready(struct nand_device_s *device, int tout);
|
||||
|
||||
@@ -59,5 +59,5 @@ extern int s3c24xx_controller_ready(struct nand_device_s *device, int tout);
|
||||
|
||||
extern int s3c2440_nand_ready(struct nand_device_s *device, int timeout);
|
||||
|
||||
extern int s3c2440_read_block_data(struct nand_device_s *, u8 *data, int data_size);
|
||||
extern int s3c2440_write_block_data(struct nand_device_s *, u8 *data, int data_size);
|
||||
extern int s3c2440_read_block_data(struct nand_device_s *, uint8_t *data, int data_size);
|
||||
extern int s3c2440_write_block_data(struct nand_device_s *, uint8_t *data, int data_size);
|
||||
|
||||
@@ -59,63 +59,63 @@
|
||||
#define S3C2412_NFMECC1 S3C2410_NFREG(0x38)
|
||||
#define S3C2412_NFSECC S3C2410_NFREG(0x3C)
|
||||
|
||||
#define S3C2410_NFCONF_EN (1<<15)
|
||||
#define S3C2410_NFCONF_512BYTE (1<<14)
|
||||
#define S3C2410_NFCONF_4STEP (1<<13)
|
||||
#define S3C2410_NFCONF_INITECC (1<<12)
|
||||
#define S3C2410_NFCONF_nFCE (1<<11)
|
||||
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
|
||||
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
|
||||
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
|
||||
#define S3C2410_NFCONF_EN (1 << 15)
|
||||
#define S3C2410_NFCONF_512BYTE (1 << 14)
|
||||
#define S3C2410_NFCONF_4STEP (1 << 13)
|
||||
#define S3C2410_NFCONF_INITECC (1 << 12)
|
||||
#define S3C2410_NFCONF_nFCE (1 << 11)
|
||||
#define S3C2410_NFCONF_TACLS(x) ((x) << 8)
|
||||
#define S3C2410_NFCONF_TWRPH0(x) ((x) << 4)
|
||||
#define S3C2410_NFCONF_TWRPH1(x) ((x) << 0)
|
||||
|
||||
#define S3C2410_NFSTAT_BUSY (1<<0)
|
||||
#define S3C2410_NFSTAT_BUSY (1 << 0)
|
||||
|
||||
#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0)
|
||||
#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0)
|
||||
#define S3C2440_NFCONF_ADVFLASH (1<<3)
|
||||
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
|
||||
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
|
||||
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
|
||||
#define S3C2440_NFCONF_BUSWIDTH_8 (0 << 0)
|
||||
#define S3C2440_NFCONF_BUSWIDTH_16 (1 << 0)
|
||||
#define S3C2440_NFCONF_ADVFLASH (1 << 3)
|
||||
#define S3C2440_NFCONF_TACLS(x) ((x) << 12)
|
||||
#define S3C2440_NFCONF_TWRPH0(x) ((x) << 8)
|
||||
#define S3C2440_NFCONF_TWRPH1(x) ((x) << 4)
|
||||
|
||||
#define S3C2440_NFCONT_LOCKTIGHT (1<<13)
|
||||
#define S3C2440_NFCONT_SOFTLOCK (1<<12)
|
||||
#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10)
|
||||
#define S3C2440_NFCONT_RNBINT_EN (1<<9)
|
||||
#define S3C2440_NFCONT_RN_FALLING (1<<8)
|
||||
#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6)
|
||||
#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5)
|
||||
#define S3C2440_NFCONT_INITECC (1<<4)
|
||||
#define S3C2440_NFCONT_nFCE (1<<1)
|
||||
#define S3C2440_NFCONT_ENABLE (1<<0)
|
||||
#define S3C2440_NFCONT_LOCKTIGHT (1 << 13)
|
||||
#define S3C2440_NFCONT_SOFTLOCK (1 << 12)
|
||||
#define S3C2440_NFCONT_ILLEGALACC_EN (1 << 10)
|
||||
#define S3C2440_NFCONT_RNBINT_EN (1 << 9)
|
||||
#define S3C2440_NFCONT_RN_FALLING (1 << 8)
|
||||
#define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6)
|
||||
#define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5)
|
||||
#define S3C2440_NFCONT_INITECC (1 << 4)
|
||||
#define S3C2440_NFCONT_nFCE (1 << 1)
|
||||
#define S3C2440_NFCONT_ENABLE (1 << 0)
|
||||
|
||||
#define S3C2440_NFSTAT_READY (1<<0)
|
||||
#define S3C2440_NFSTAT_nCE (1<<1)
|
||||
#define S3C2440_NFSTAT_RnB_CHANGE (1<<2)
|
||||
#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3)
|
||||
#define S3C2440_NFSTAT_READY (1 << 0)
|
||||
#define S3C2440_NFSTAT_nCE (1 << 1)
|
||||
#define S3C2440_NFSTAT_RnB_CHANGE (1 << 2)
|
||||
#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3)
|
||||
|
||||
#define S3C2412_NFCONF_NANDBOOT (1<<31)
|
||||
#define S3C2412_NFCONF_ECCCLKCON (1<<30)
|
||||
#define S3C2412_NFCONF_ECC_MLC (1<<24)
|
||||
#define S3C2412_NFCONF_TACLS_MASK (7<<12) /* 1 extra bit of Tacls */
|
||||
#define S3C2412_NFCONF_NANDBOOT (1 << 31)
|
||||
#define S3C2412_NFCONF_ECCCLKCON (1 << 30)
|
||||
#define S3C2412_NFCONF_ECC_MLC (1 << 24)
|
||||
#define S3C2412_NFCONF_TACLS_MASK (7 << 12) /* 1 extra bit of Tacls */
|
||||
|
||||
#define S3C2412_NFCONT_ECC4_DIRWR (1<<18)
|
||||
#define S3C2412_NFCONT_LOCKTIGHT (1<<17)
|
||||
#define S3C2412_NFCONT_SOFTLOCK (1<<16)
|
||||
#define S3C2412_NFCONT_ECC4_ENCINT (1<<13)
|
||||
#define S3C2412_NFCONT_ECC4_DECINT (1<<12)
|
||||
#define S3C2412_NFCONT_MAIN_ECC_LOCK (1<<7)
|
||||
#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5)
|
||||
#define S3C2412_NFCONT_nFCE1 (1<<2)
|
||||
#define S3C2412_NFCONT_nFCE0 (1<<1)
|
||||
#define S3C2412_NFCONT_ECC4_DIRWR (1 << 18)
|
||||
#define S3C2412_NFCONT_LOCKTIGHT (1 << 17)
|
||||
#define S3C2412_NFCONT_SOFTLOCK (1 << 16)
|
||||
#define S3C2412_NFCONT_ECC4_ENCINT (1 << 13)
|
||||
#define S3C2412_NFCONT_ECC4_DECINT (1 << 12)
|
||||
#define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7)
|
||||
#define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5)
|
||||
#define S3C2412_NFCONT_nFCE1 (1 << 2)
|
||||
#define S3C2412_NFCONT_nFCE0 (1 << 1)
|
||||
|
||||
#define S3C2412_NFSTAT_ECC_ENCDONE (1<<7)
|
||||
#define S3C2412_NFSTAT_ECC_DECDONE (1<<6)
|
||||
#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1<<5)
|
||||
#define S3C2412_NFSTAT_RnB_CHANGE (1<<4)
|
||||
#define S3C2412_NFSTAT_nFCE1 (1<<3)
|
||||
#define S3C2412_NFSTAT_nFCE0 (1<<2)
|
||||
#define S3C2412_NFSTAT_Res1 (1<<1)
|
||||
#define S3C2412_NFSTAT_READY (1<<0)
|
||||
#define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7)
|
||||
#define S3C2412_NFSTAT_ECC_DECDONE (1 << 6)
|
||||
#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5)
|
||||
#define S3C2412_NFSTAT_RnB_CHANGE (1 << 4)
|
||||
#define S3C2412_NFSTAT_nFCE1 (1 << 3)
|
||||
#define S3C2412_NFSTAT_nFCE0 (1 << 2)
|
||||
#define S3C2412_NFSTAT_Res1 (1 << 1)
|
||||
#define S3C2412_NFSTAT_READY (1 << 0)
|
||||
|
||||
#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf)
|
||||
#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7)
|
||||
|
||||
@@ -28,40 +28,29 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "stellaris.h"
|
||||
#include "cortex_m3.h"
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "armv7m.h"
|
||||
#include "binarybuffer.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DID0_VER(did0) ((did0>>28)&0x07)
|
||||
int stellaris_register_commands(struct command_context_s *cmd_ctx);
|
||||
int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int stellaris_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int stellaris_auto_probe(struct flash_bank_s *bank);
|
||||
int stellaris_probe(struct flash_bank_s *bank);
|
||||
int stellaris_protect_check(struct flash_bank_s *bank);
|
||||
int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
#define DID0_VER(did0) ((did0 >> 28)&0x07)
|
||||
static int stellaris_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int stellaris_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int stellaris_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int stellaris_auto_probe(struct flash_bank_s *bank);
|
||||
static int stellaris_probe(struct flash_bank_s *bank);
|
||||
static int stellaris_protect_check(struct flash_bank_s *bank);
|
||||
static int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
int stellaris_read_part_info(struct flash_bank_s *bank);
|
||||
u32 stellaris_get_flash_status(flash_bank_t *bank);
|
||||
void stellaris_set_flash_mode(flash_bank_t *bank,int mode);
|
||||
u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);
|
||||
static int stellaris_read_part_info(struct flash_bank_s *bank);
|
||||
static uint32_t stellaris_get_flash_status(flash_bank_t *bank);
|
||||
static void stellaris_set_flash_mode(flash_bank_t *bank,int mode);
|
||||
//static uint32_t stellaris_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
|
||||
|
||||
int stellaris_read_part_info(struct flash_bank_s *bank);
|
||||
int stellaris_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stellaris_mass_erase(struct flash_bank_s *bank);
|
||||
static int stellaris_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stellaris_mass_erase(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t stellaris_flash =
|
||||
{
|
||||
@@ -78,8 +67,8 @@ flash_driver_t stellaris_flash =
|
||||
.info = stellaris_info
|
||||
};
|
||||
|
||||
struct {
|
||||
u32 partno;
|
||||
static struct {
|
||||
uint32_t partno;
|
||||
char *partname;
|
||||
} StellarisParts[] =
|
||||
{
|
||||
@@ -234,7 +223,7 @@ struct {
|
||||
{0,"Unknown part"}
|
||||
};
|
||||
|
||||
char * StellarisClassname[5] =
|
||||
static char * StellarisClassname[5] =
|
||||
{
|
||||
"Sandstorm",
|
||||
"Fury",
|
||||
@@ -249,7 +238,7 @@ char * StellarisClassname[5] =
|
||||
|
||||
/* flash_bank stellaris <base> <size> 0 0 <target#>
|
||||
*/
|
||||
int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info;
|
||||
|
||||
@@ -268,11 +257,14 @@ int stellaris_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, c
|
||||
/* part wasn't probed for info yet */
|
||||
stellaris_info->did1 = 0;
|
||||
|
||||
/* TODO Use an optional main oscillator clock rate in kHz from arg[6] */
|
||||
/* TODO Specify the main crystal speed in kHz using an optional
|
||||
* argument; ditto, the speed of an external oscillator used
|
||||
* instead of a crystal. Avoid programming flash using IOSC.
|
||||
*/
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int stellaris_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *stm32x_cmd = register_command(cmd_ctx, NULL, "stellaris", NULL, COMMAND_ANY, "stellaris flash specific commands");
|
||||
|
||||
@@ -280,7 +272,7 @@ int stellaris_register_commands(struct command_context_s *cmd_ctx)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed, device_class;
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
@@ -297,30 +289,56 @@ int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
|
||||
if (DID0_VER(stellaris_info->did0) > 0)
|
||||
{
|
||||
device_class = (stellaris_info->did0>>16) & 0xFF;
|
||||
device_class = (stellaris_info->did0 >> 16) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
device_class = 0;
|
||||
}
|
||||
printed = snprintf(buf, buf_size, "\nLMI Stellaris information: Chip is class %i(%s) %s v%c.%i\n",
|
||||
device_class, StellarisClassname[device_class], stellaris_info->target_name,
|
||||
'A' + ((stellaris_info->did0>>8) & 0xFF), (stellaris_info->did0) & 0xFF);
|
||||
printed = snprintf(buf,
|
||||
buf_size,
|
||||
"\nTI/LMI Stellaris information: Chip is "
|
||||
"class %i (%s) %s rev %c%i\n",
|
||||
device_class,
|
||||
StellarisClassname[device_class],
|
||||
stellaris_info->target_name,
|
||||
(int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)),
|
||||
(int)((stellaris_info->did0) & 0xFF));
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size, "did1: 0x%8.8x, arch: 0x%4.4x, eproc: %s, ramsize:%ik, flashsize: %ik\n",
|
||||
stellaris_info->did1, stellaris_info->did1, "ARMV7M", (1+((stellaris_info->dc0>>16) & 0xFFFF))/4, (1+(stellaris_info->dc0 & 0xFFFF))*2);
|
||||
printed = snprintf(buf,
|
||||
buf_size,
|
||||
"did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32
|
||||
", eproc: %s, ramsize: %ik, flashsize: %ik\n",
|
||||
stellaris_info->did1,
|
||||
stellaris_info->did1,
|
||||
"ARMv7M",
|
||||
(int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4),
|
||||
(int)((1 + (stellaris_info->dc0 & 0xFFFF))*2));
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
printed = snprintf(buf, buf_size, "master clock(estimated): %ikHz, rcc is 0x%x \n", stellaris_info->mck_freq / 1000, stellaris_info->rcc);
|
||||
printed = snprintf(buf,
|
||||
buf_size,
|
||||
"master clock: %ikHz%s, "
|
||||
"rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
|
||||
(int)(stellaris_info->mck_freq / 1000),
|
||||
stellaris_info->mck_desc,
|
||||
stellaris_info->rcc,
|
||||
stellaris_info->rcc2);
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
if (stellaris_info->num_lockbits>0)
|
||||
if (stellaris_info->num_lockbits > 0)
|
||||
{
|
||||
printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", stellaris_info->pagesize, stellaris_info->num_lockbits, stellaris_info->lockbits,stellaris_info->num_pages/stellaris_info->num_lockbits);
|
||||
printed = snprintf(buf,
|
||||
buf_size,
|
||||
"pagesize: %" PRIi32 ", lockbits: %i 0x%4.4" PRIx32 ", pages in lock region: %i \n",
|
||||
stellaris_info->pagesize,
|
||||
stellaris_info->num_lockbits,
|
||||
stellaris_info->lockbits,
|
||||
(int)(stellaris_info->num_pages/stellaris_info->num_lockbits));
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
}
|
||||
@@ -331,50 +349,115 @@ int stellaris_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
* chip identification and status *
|
||||
***************************************************************************/
|
||||
|
||||
u32 stellaris_get_flash_status(flash_bank_t *bank)
|
||||
static uint32_t stellaris_get_flash_status(flash_bank_t *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 fmc;
|
||||
uint32_t fmc;
|
||||
|
||||
target_read_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, &fmc);
|
||||
target_read_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, &fmc);
|
||||
|
||||
return fmc;
|
||||
}
|
||||
|
||||
/** Read clock configuration and set stellaris_info->usec_clocks*/
|
||||
|
||||
void stellaris_read_clock_info(flash_bank_t *bank)
|
||||
static const unsigned rcc_xtal[32] = {
|
||||
[0x00] = 1000000, /* no pll */
|
||||
[0x01] = 1843200, /* no pll */
|
||||
[0x02] = 2000000, /* no pll */
|
||||
[0x03] = 2457600, /* no pll */
|
||||
|
||||
[0x04] = 3579545,
|
||||
[0x05] = 3686400,
|
||||
[0x06] = 4000000, /* usb */
|
||||
[0x07] = 4096000,
|
||||
|
||||
[0x08] = 4915200,
|
||||
[0x09] = 5000000, /* usb */
|
||||
[0x0a] = 5120000,
|
||||
[0x0b] = 6000000, /* (reset) usb */
|
||||
|
||||
[0x0c] = 6144000,
|
||||
[0x0d] = 7372800,
|
||||
[0x0e] = 8000000, /* usb */
|
||||
[0x0f] = 8192000,
|
||||
|
||||
/* parts before DustDevil use just 4 bits for xtal spec */
|
||||
|
||||
[0x10] = 10000000, /* usb */
|
||||
[0x11] = 12000000, /* usb */
|
||||
[0x12] = 12288000,
|
||||
[0x13] = 13560000,
|
||||
|
||||
[0x14] = 14318180,
|
||||
[0x15] = 16000000, /* usb */
|
||||
[0x16] = 16384000,
|
||||
};
|
||||
|
||||
static void stellaris_read_clock_info(flash_bank_t *bank)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 rcc, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
|
||||
uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc;
|
||||
unsigned xtal;
|
||||
unsigned long mainfreq;
|
||||
|
||||
target_read_u32(target, SCB_BASE|RCC, &rcc);
|
||||
LOG_DEBUG("Stellaris RCC %x", rcc);
|
||||
target_read_u32(target, SCB_BASE|PLLCFG, &pllcfg);
|
||||
LOG_DEBUG("Stellaris PLLCFG %x", pllcfg);
|
||||
stellaris_info->rcc = rcc;
|
||||
target_read_u32(target, SCB_BASE | RCC, &rcc);
|
||||
LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc);
|
||||
|
||||
target_read_u32(target, SCB_BASE | RCC2, &rcc2);
|
||||
LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc);
|
||||
|
||||
target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg);
|
||||
LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg);
|
||||
|
||||
stellaris_info->rcc = rcc;
|
||||
stellaris_info->rcc = rcc2;
|
||||
|
||||
sysdiv = (rcc >> 23) & 0xF;
|
||||
usesysdiv = (rcc >> 22) & 0x1;
|
||||
bypass = (rcc >> 11) & 0x1;
|
||||
oscsrc = (rcc >> 4) & 0x3;
|
||||
xtal = (rcc >> 6) & stellaris_info->xtal_mask;
|
||||
|
||||
/* NOTE: post-Sandstorm parts have RCC2 which may override
|
||||
* parts of RCC ... with more sysdiv options, option for
|
||||
* 32768 Hz mainfreq, PLL controls. On Sandstorm it reads
|
||||
* as zero, so the "use RCC2" flag is always clear.
|
||||
*/
|
||||
if (rcc2 & (1 << 31)) {
|
||||
sysdiv = (rcc2 >> 23) & 0x3F;
|
||||
bypass = (rcc2 >> 11) & 0x1;
|
||||
oscsrc = (rcc2 >> 4) & 0x7;
|
||||
|
||||
/* FIXME Tempest parts have an additional lsb for
|
||||
* fractional sysdiv (200 MHz / 2.5 == 80 MHz)
|
||||
*/
|
||||
}
|
||||
|
||||
stellaris_info->mck_desc = "";
|
||||
|
||||
sysdiv = (rcc>>23) & 0xF;
|
||||
usesysdiv = (rcc>>22) & 0x1;
|
||||
bypass = (rcc>>11) & 0x1;
|
||||
oscsrc = (rcc>>4) & 0x3;
|
||||
/* xtal = (rcc>>6)&0xF; */
|
||||
switch (oscsrc)
|
||||
{
|
||||
case 0:
|
||||
mainfreq = 6000000; /* Default xtal */
|
||||
case 0: /* MOSC */
|
||||
mainfreq = rcc_xtal[xtal];
|
||||
break;
|
||||
case 1:
|
||||
mainfreq = 22500000; /* Internal osc. 15 MHz +- 50% */
|
||||
case 1: /* IOSC */
|
||||
mainfreq = stellaris_info->iosc_freq;
|
||||
stellaris_info->mck_desc = stellaris_info->iosc_desc;
|
||||
break;
|
||||
case 2:
|
||||
mainfreq = 5625000; /* Internal osc. / 4 */
|
||||
case 2: /* IOSC/4 */
|
||||
mainfreq = stellaris_info->iosc_freq / 4;
|
||||
stellaris_info->mck_desc = stellaris_info->iosc_desc;
|
||||
break;
|
||||
case 3:
|
||||
LOG_WARNING("Invalid oscsrc (3) in rcc register");
|
||||
mainfreq = 6000000;
|
||||
case 3: /* lowspeed */
|
||||
/* Sandstorm doesn't have this 30K +/- 30% osc */
|
||||
mainfreq = 30000;
|
||||
stellaris_info->mck_desc = " (±30%)";
|
||||
break;
|
||||
case 8: /* hibernation osc */
|
||||
/* not all parts support hibernation */
|
||||
mainfreq = 32768;
|
||||
break;
|
||||
|
||||
default: /* NOTREACHED */
|
||||
@@ -382,11 +465,14 @@ void stellaris_read_clock_info(flash_bank_t *bank)
|
||||
break;
|
||||
}
|
||||
|
||||
/* PLL is used if it's not bypassed; its output is 200 MHz
|
||||
* even when it runs at 400 MHz (adds divide-by-two stage).
|
||||
*/
|
||||
if (!bypass)
|
||||
mainfreq = 200000000; /* PLL out frec */
|
||||
mainfreq = 200000000;
|
||||
|
||||
if (usesysdiv)
|
||||
stellaris_info->mck_freq = mainfreq/(1+sysdiv);
|
||||
stellaris_info->mck_freq = mainfreq/(1 + sysdiv);
|
||||
else
|
||||
stellaris_info->mck_freq = mainfreq;
|
||||
|
||||
@@ -395,19 +481,20 @@ void stellaris_read_clock_info(flash_bank_t *bank)
|
||||
}
|
||||
|
||||
/* Setup the timimg registers */
|
||||
void stellaris_set_flash_mode(flash_bank_t *bank,int mode)
|
||||
static void stellaris_set_flash_mode(flash_bank_t *bank,int mode)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
u32 usecrl = (stellaris_info->mck_freq/1000000ul-1);
|
||||
LOG_DEBUG("usecrl = %i",usecrl);
|
||||
target_write_u32(target, SCB_BASE|USECRL, usecrl);
|
||||
uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1);
|
||||
LOG_DEBUG("usecrl = %i",(int)(usecrl));
|
||||
target_write_u32(target, SCB_BASE | USECRL, usecrl);
|
||||
}
|
||||
|
||||
u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
|
||||
#if 0
|
||||
static uint32_t stellaris_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
/* Stellaris waits for cmdbit to clear */
|
||||
while (((status = stellaris_get_flash_status(bank)) & waitbits) && (timeout-- > 0))
|
||||
@@ -422,13 +509,13 @@ u32 stellaris_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)
|
||||
}
|
||||
|
||||
/* Send one command to the flash controller */
|
||||
int stellaris_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
|
||||
static int stellaris_flash_command(struct flash_bank_s *bank,uint8_t cmd,uint16_t pagen)
|
||||
{
|
||||
u32 fmc;
|
||||
uint32_t fmc;
|
||||
target_t *target = bank->target;
|
||||
|
||||
fmc = FMC_WRKEY | cmd;
|
||||
target_write_u32(target, FLASH_CONTROL_BASE|FLASH_FMC, fmc);
|
||||
target_write_u32(target, FLASH_CONTROL_BASE | FLASH_FMC, fmc);
|
||||
LOG_DEBUG("Flash command: 0x%x", fmc);
|
||||
|
||||
if (stellaris_wait_status_busy(bank, cmd, 100))
|
||||
@@ -438,24 +525,26 @@ int stellaris_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read device id register, main clock frequency register and fill in driver info structure */
|
||||
int stellaris_read_part_info(struct flash_bank_s *bank)
|
||||
static int stellaris_read_part_info(struct flash_bank_s *bank)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 did0, did1, ver, fam, status;
|
||||
uint32_t did0, did1, ver, fam, status;
|
||||
int i;
|
||||
|
||||
/* Read and parse chip identification register */
|
||||
target_read_u32(target, SCB_BASE|DID0, &did0);
|
||||
target_read_u32(target, SCB_BASE|DID1, &did1);
|
||||
target_read_u32(target, SCB_BASE|DC0, &stellaris_info->dc0);
|
||||
target_read_u32(target, SCB_BASE|DC1, &stellaris_info->dc1);
|
||||
LOG_DEBUG("did0 0x%x, did1 0x%x, dc0 0x%x, dc1 0x%x", did0, did1, stellaris_info->dc0, stellaris_info->dc1);
|
||||
target_read_u32(target, SCB_BASE | DID0, &did0);
|
||||
target_read_u32(target, SCB_BASE | DID1, &did1);
|
||||
target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0);
|
||||
target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1);
|
||||
LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
|
||||
did0, did1, stellaris_info->dc0, stellaris_info->dc1);
|
||||
|
||||
ver = did0 >> 28;
|
||||
if((ver != 0) && (ver != 1))
|
||||
if ((ver != 0) && (ver != 1))
|
||||
{
|
||||
LOG_WARNING("Unknown did0 version, cannot identify target");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -469,11 +558,53 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
|
||||
|
||||
ver = did1 >> 28;
|
||||
fam = (did1 >> 24) & 0xF;
|
||||
if(((ver != 0) && (ver != 1)) || (fam != 0))
|
||||
if (((ver != 0) && (ver != 1)) || (fam != 0))
|
||||
{
|
||||
LOG_WARNING("Unknown did1 version/family, cannot positively identify target as a Stellaris");
|
||||
}
|
||||
|
||||
/* For Sandstorm, Fury, DustDevil: current data sheets say IOSC
|
||||
* is 12 MHz, but some older parts have 15 MHz. A few data sheets
|
||||
* even give _both_ numbers! We'll use current numbers; IOSC is
|
||||
* always approximate.
|
||||
*
|
||||
* For Tempest: IOSC is calibrated, 16 MHz
|
||||
*/
|
||||
stellaris_info->iosc_freq = 12000000;
|
||||
stellaris_info->iosc_desc = " (±30%)";
|
||||
stellaris_info->xtal_mask = 0x0f;
|
||||
|
||||
switch ((did0 >> 28) & 0x7) {
|
||||
case 0: /* Sandstorm */
|
||||
/*
|
||||
* Current (2009-August) parts seem to be rev C2 and use 12 MHz.
|
||||
* Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz
|
||||
* (LM3S618), but some other C0 parts are 12 MHz (LM3S811).
|
||||
*/
|
||||
if (((did0 >> 8) & 0xff) < 2) {
|
||||
stellaris_info->iosc_freq = 15000000;
|
||||
stellaris_info->iosc_desc = " (±50%)";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch ((did0 >> 16) & 0xff) {
|
||||
case 1: /* Fury */
|
||||
break;
|
||||
case 4: /* Tempest */
|
||||
stellaris_info->iosc_freq = 16000000; /* +/- 1% */
|
||||
stellaris_info->iosc_desc = " (±1%)";
|
||||
/* FALL THROUGH */
|
||||
case 3: /* DustDevil */
|
||||
stellaris_info->xtal_mask = 0x1f;
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING("Unknown did0 class");
|
||||
}
|
||||
default:
|
||||
break;
|
||||
LOG_WARNING("Unknown did0 version");
|
||||
}
|
||||
|
||||
for (i = 0; StellarisParts[i].partno; i++)
|
||||
{
|
||||
if (StellarisParts[i].partno == ((did1 >> 16) & 0xFF))
|
||||
@@ -486,11 +617,11 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
|
||||
stellaris_info->did1 = did1;
|
||||
|
||||
stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
|
||||
stellaris_info->num_pages = 2 *(1+(stellaris_info->dc0 & 0xFFFF));
|
||||
stellaris_info->num_pages = 2 *(1 + (stellaris_info->dc0 & 0xFFFF));
|
||||
stellaris_info->pagesize = 1024;
|
||||
bank->size = 1024 * stellaris_info->num_pages;
|
||||
stellaris_info->pages_in_lockregion = 2;
|
||||
target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
|
||||
target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
|
||||
|
||||
/* provide this for the benefit of the higher flash driver layers */
|
||||
bank->num_sectors = stellaris_info->num_pages;
|
||||
@@ -515,9 +646,9 @@ int stellaris_read_part_info(struct flash_bank_s *bank)
|
||||
* flash operations *
|
||||
***************************************************************************/
|
||||
|
||||
int stellaris_protect_check(struct flash_bank_s *bank)
|
||||
static int stellaris_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
|
||||
@@ -534,7 +665,7 @@ int stellaris_protect_check(struct flash_bank_s *bank)
|
||||
|
||||
if (stellaris_info->did1 == 0)
|
||||
{
|
||||
LOG_WARNING("Cannot identify target as an AT91SAM");
|
||||
LOG_WARNING("Cannot identify target as Stellaris");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -544,10 +675,10 @@ int stellaris_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
int banknr;
|
||||
u32 flash_fmc, flash_cris;
|
||||
uint32_t flash_fmc, flash_cris;
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
@@ -568,12 +699,12 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if ((first < 0) || (last < first) || (last >= stellaris_info->num_pages))
|
||||
if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages))
|
||||
{
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
if ((first == 0) && (last == (stellaris_info->num_pages-1)))
|
||||
if ((first == 0) && (last == ((int)stellaris_info->num_pages-1)))
|
||||
{
|
||||
return stellaris_mass_erase(bank);
|
||||
}
|
||||
@@ -584,7 +715,7 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
|
||||
/* Clear and disable flash programming interrupts */
|
||||
target_write_u32(target, FLASH_CIM, 0);
|
||||
target_write_u32(target, FLASH_MISC, PMISC|AMISC);
|
||||
target_write_u32(target, FLASH_MISC, PMISC | AMISC);
|
||||
|
||||
for (banknr = first; banknr <= last; banknr++)
|
||||
{
|
||||
@@ -597,13 +728,13 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
target_read_u32(target, FLASH_FMC, &flash_fmc);
|
||||
}
|
||||
while(flash_fmc & FMC_ERASE);
|
||||
while (flash_fmc & FMC_ERASE);
|
||||
|
||||
/* Check acess violations */
|
||||
target_read_u32(target, FLASH_CRIS, &flash_cris);
|
||||
if(flash_cris & (AMASK))
|
||||
if (flash_cris & (AMASK))
|
||||
{
|
||||
LOG_WARNING("Error erasing flash page %i, flash_cris 0x%x", banknr, flash_cris);
|
||||
LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", banknr, flash_cris);
|
||||
target_write_u32(target, FLASH_CRIS, 0);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
@@ -614,9 +745,9 @@ int stellaris_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
u32 fmppe, flash_fmc, flash_cris;
|
||||
uint32_t fmppe, flash_fmc, flash_cris;
|
||||
int lockregion;
|
||||
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
@@ -652,17 +783,17 @@ int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
for (lockregion = first; lockregion <= last; lockregion++)
|
||||
{
|
||||
if (set)
|
||||
fmppe &= ~(1<<lockregion);
|
||||
fmppe &= ~(1 << lockregion);
|
||||
else
|
||||
fmppe |= (1<<lockregion);
|
||||
fmppe |= (1 << lockregion);
|
||||
}
|
||||
|
||||
/* Clear and disable flash programming interrupts */
|
||||
target_write_u32(target, FLASH_CIM, 0);
|
||||
target_write_u32(target, FLASH_MISC, PMISC|AMISC);
|
||||
target_write_u32(target, FLASH_MISC, PMISC | AMISC);
|
||||
|
||||
LOG_DEBUG("fmppe 0x%x",fmppe);
|
||||
target_write_u32(target, SCB_BASE|FMPPE, fmppe);
|
||||
LOG_DEBUG("fmppe 0x%" PRIx32 "",fmppe);
|
||||
target_write_u32(target, SCB_BASE | FMPPE, fmppe);
|
||||
/* Commit FMPPE */
|
||||
target_write_u32(target, FLASH_FMA, 1);
|
||||
/* Write commit command */
|
||||
@@ -674,23 +805,23 @@ int stellaris_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
target_read_u32(target, FLASH_FMC, &flash_fmc);
|
||||
}
|
||||
while(flash_fmc & FMC_COMT);
|
||||
while (flash_fmc & FMC_COMT);
|
||||
|
||||
/* Check acess violations */
|
||||
target_read_u32(target, FLASH_CRIS, &flash_cris);
|
||||
if(flash_cris & (AMASK))
|
||||
if (flash_cris & (AMASK))
|
||||
{
|
||||
LOG_WARNING("Error setting flash page protection, flash_cris 0x%x", flash_cris);
|
||||
LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
|
||||
target_write_u32(target, FLASH_CRIS, 0);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
target_read_u32(target, SCB_BASE|FMPPE, &stellaris_info->lockbits);
|
||||
target_read_u32(target, SCB_BASE | FMPPE, &stellaris_info->lockbits);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u8 stellaris_write_code[] =
|
||||
static uint8_t stellaris_write_code[] =
|
||||
{
|
||||
/*
|
||||
Call with :
|
||||
@@ -730,18 +861,18 @@ u8 stellaris_write_code[] =
|
||||
0x01,0x00,0x42,0xA4 /* .word 0xA4420001 */
|
||||
};
|
||||
|
||||
int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 wcount)
|
||||
static int stellaris_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t wcount)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 buffer_size = 8192;
|
||||
uint32_t buffer_size = 8192;
|
||||
working_area_t *source;
|
||||
working_area_t *write_algorithm;
|
||||
u32 address = bank->base + offset;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[3];
|
||||
armv7m_algorithm_t armv7m_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
LOG_DEBUG("(bank=%p buffer=%p offset=%08X wcount=%08X)",
|
||||
LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
|
||||
bank, buffer, offset, wcount);
|
||||
|
||||
/* flash write code */
|
||||
@@ -756,7 +887,7 @@ int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
/* memory buffer */
|
||||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
|
||||
{
|
||||
LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08X source=%p)",
|
||||
LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)",
|
||||
target, buffer_size, source);
|
||||
buffer_size /= 2;
|
||||
if (buffer_size <= 256)
|
||||
@@ -779,16 +910,16 @@ int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
|
||||
while (wcount > 0)
|
||||
{
|
||||
u32 thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
|
||||
uint32_t thisrun_count = (wcount > (buffer_size / 4)) ? (buffer_size / 4) : wcount;
|
||||
|
||||
target_write_buffer(target, source->address, thisrun_count * 4, buffer);
|
||||
|
||||
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, 4*thisrun_count);
|
||||
LOG_INFO("Algorithm flash write %i words to 0x%x, %i remaining", thisrun_count, address, wcount);
|
||||
LOG_DEBUG("Algorithm flash write %i words to 0x%x, %i remaining", thisrun_count, address, wcount);
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
|
||||
LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
|
||||
LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count));
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error executing stellaris flash write algorithm");
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -810,16 +941,16 @@ int stellaris_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32
|
||||
return retval;
|
||||
}
|
||||
|
||||
int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int stellaris_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 address = offset;
|
||||
u32 flash_cris, flash_fmc;
|
||||
u32 words_remaining = (count / 4);
|
||||
u32 bytes_remaining = (count & 0x00000003);
|
||||
u32 bytes_written = 0;
|
||||
u32 retval;
|
||||
uint32_t address = offset;
|
||||
uint32_t flash_cris, flash_fmc;
|
||||
uint32_t words_remaining = (count / 4);
|
||||
uint32_t bytes_remaining = (count & 0x00000003);
|
||||
uint32_t bytes_written = 0;
|
||||
int retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -827,7 +958,7 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("(bank=%p buffer=%p offset=%08X count=%08X)",
|
||||
LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
|
||||
bank, buffer, offset, count);
|
||||
|
||||
if (stellaris_info->did1 == 0)
|
||||
@@ -856,7 +987,7 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
|
||||
/* Clear and disable flash programming interrupts */
|
||||
target_write_u32(target, FLASH_CIM, 0);
|
||||
target_write_u32(target, FLASH_MISC, PMISC|AMISC);
|
||||
target_write_u32(target, FLASH_MISC, PMISC | AMISC);
|
||||
|
||||
/* multiple words to be programmed? */
|
||||
if (words_remaining > 0)
|
||||
@@ -875,7 +1006,7 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
/* if an error occured, we examine the reason, and quit */
|
||||
target_read_u32(target, FLASH_CRIS, &flash_cris);
|
||||
|
||||
LOG_ERROR("flash writing failed with CRIS: 0x%x", flash_cris);
|
||||
LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
@@ -890,7 +1021,7 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
while (words_remaining > 0)
|
||||
{
|
||||
if (!(address & 0xff))
|
||||
LOG_DEBUG("0x%x", address);
|
||||
LOG_DEBUG("0x%" PRIx32 "", address);
|
||||
|
||||
/* Program one word */
|
||||
target_write_u32(target, FLASH_FMA, address);
|
||||
@@ -910,10 +1041,10 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
|
||||
if (bytes_remaining)
|
||||
{
|
||||
u8 last_word[4] = {0xff, 0xff, 0xff, 0xff};
|
||||
uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
|
||||
int i = 0;
|
||||
|
||||
while(bytes_remaining > 0)
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
last_word[i++] = *(buffer + bytes_written);
|
||||
bytes_remaining--;
|
||||
@@ -921,7 +1052,7 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
}
|
||||
|
||||
if (!(address & 0xff))
|
||||
LOG_DEBUG("0x%x", address);
|
||||
LOG_DEBUG("0x%" PRIx32 "", address);
|
||||
|
||||
/* Program one word */
|
||||
target_write_u32(target, FLASH_FMA, address);
|
||||
@@ -939,13 +1070,13 @@ int stellaris_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count
|
||||
target_read_u32(target, FLASH_CRIS, &flash_cris);
|
||||
if (flash_cris & (AMASK))
|
||||
{
|
||||
LOG_DEBUG("flash_cris 0x%x", flash_cris);
|
||||
LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_probe(struct flash_bank_s *bank)
|
||||
static int stellaris_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we can't probe on an stellaris
|
||||
* if this is an stellaris, it has the configured flash
|
||||
@@ -961,7 +1092,7 @@ int stellaris_probe(struct flash_bank_s *bank)
|
||||
return stellaris_read_part_info(bank);
|
||||
}
|
||||
|
||||
int stellaris_auto_probe(struct flash_bank_s *bank)
|
||||
static int stellaris_auto_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
stellaris_flash_bank_t *stellaris_info = bank->driver_priv;
|
||||
if (stellaris_info->did1)
|
||||
@@ -969,11 +1100,11 @@ int stellaris_auto_probe(struct flash_bank_s *bank)
|
||||
return stellaris_probe(bank);
|
||||
}
|
||||
|
||||
int stellaris_mass_erase(struct flash_bank_s *bank)
|
||||
static int stellaris_mass_erase(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = NULL;
|
||||
stellaris_flash_bank_t *stellaris_info = NULL;
|
||||
u32 flash_fmc;
|
||||
uint32_t flash_fmc;
|
||||
|
||||
stellaris_info = bank->driver_priv;
|
||||
target = bank->target;
|
||||
@@ -1001,7 +1132,7 @@ int stellaris_mass_erase(struct flash_bank_s *bank)
|
||||
|
||||
/* Clear and disable flash programming interrupts */
|
||||
target_write_u32(target, FLASH_CIM, 0);
|
||||
target_write_u32(target, FLASH_MISC, PMISC|AMISC);
|
||||
target_write_u32(target, FLASH_MISC, PMISC | AMISC);
|
||||
|
||||
target_write_u32(target, FLASH_FMA, 0);
|
||||
target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE);
|
||||
@@ -1029,7 +1160,7 @@ int stellaris_mass_erase(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stellaris_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stellaris_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
@@ -21,34 +21,37 @@
|
||||
#define STELLARIS_FLASH_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct stellaris_flash_bank_s
|
||||
{
|
||||
/* chip id register */
|
||||
u32 did0;
|
||||
u32 did1;
|
||||
u32 dc0;
|
||||
u32 dc1;
|
||||
uint32_t did0;
|
||||
uint32_t did1;
|
||||
uint32_t dc0;
|
||||
uint32_t dc1;
|
||||
|
||||
char * target_name;
|
||||
|
||||
u32 sramsiz;
|
||||
u32 flshsz;
|
||||
uint32_t sramsiz;
|
||||
uint32_t flshsz;
|
||||
/* flash geometry */
|
||||
u32 num_pages;
|
||||
u32 pagesize;
|
||||
u32 pages_in_lockregion;
|
||||
uint32_t num_pages;
|
||||
uint32_t pagesize;
|
||||
uint32_t pages_in_lockregion;
|
||||
|
||||
/* nv memory bits */
|
||||
u16 num_lockbits;
|
||||
u32 lockbits;
|
||||
uint16_t num_lockbits;
|
||||
uint32_t lockbits;
|
||||
|
||||
/* main clock status */
|
||||
u32 rcc;
|
||||
u8 mck_valid;
|
||||
u32 mck_freq;
|
||||
|
||||
uint32_t rcc;
|
||||
uint32_t rcc2;
|
||||
uint8_t mck_valid;
|
||||
uint8_t xtal_mask;
|
||||
uint32_t iosc_freq;
|
||||
uint32_t mck_freq;
|
||||
const char *iosc_desc;
|
||||
const char *mck_desc;
|
||||
} stellaris_flash_bank_t;
|
||||
|
||||
/* STELLARIS control registers */
|
||||
@@ -64,18 +67,19 @@ typedef struct stellaris_flash_bank_s
|
||||
#define RIS 0x050
|
||||
#define RCC 0x060
|
||||
#define PLLCFG 0x064
|
||||
#define RCC2 0x070
|
||||
|
||||
#define FMPRE 0x130
|
||||
#define FMPPE 0x134
|
||||
#define USECRL 0x140
|
||||
#define USECRL 0x140
|
||||
|
||||
#define FLASH_CONTROL_BASE 0x400FD000
|
||||
#define FLASH_FMA (FLASH_CONTROL_BASE|0x000)
|
||||
#define FLASH_FMD (FLASH_CONTROL_BASE|0x004)
|
||||
#define FLASH_FMC (FLASH_CONTROL_BASE|0x008)
|
||||
#define FLASH_CRIS (FLASH_CONTROL_BASE|0x00C)
|
||||
#define FLASH_CIM (FLASH_CONTROL_BASE|0x010)
|
||||
#define FLASH_MISC (FLASH_CONTROL_BASE|0x014)
|
||||
#define FLASH_FMA (FLASH_CONTROL_BASE | 0x000)
|
||||
#define FLASH_FMD (FLASH_CONTROL_BASE | 0x004)
|
||||
#define FLASH_FMC (FLASH_CONTROL_BASE | 0x008)
|
||||
#define FLASH_CRIS (FLASH_CONTROL_BASE | 0x00C)
|
||||
#define FLASH_CIM (FLASH_CONTROL_BASE | 0x010)
|
||||
#define FLASH_MISC (FLASH_CONTROL_BASE | 0x014)
|
||||
|
||||
#define AMISC 1
|
||||
#define PMISC 2
|
||||
@@ -84,11 +88,11 @@ typedef struct stellaris_flash_bank_s
|
||||
#define PMASK 2
|
||||
|
||||
/* Flash Controller Command bits */
|
||||
#define FMC_WRKEY (0xA442<<16)
|
||||
#define FMC_COMT (1<<3)
|
||||
#define FMC_MERASE (1<<2)
|
||||
#define FMC_ERASE (1<<1)
|
||||
#define FMC_WRITE (1<<0)
|
||||
#define FMC_WRKEY (0xA442 << 16)
|
||||
#define FMC_COMT (1 << 3)
|
||||
#define FMC_MERASE (1 << 2)
|
||||
#define FMC_ERASE (1 << 1)
|
||||
#define FMC_WRITE (1 << 0)
|
||||
|
||||
/* STELLARIS constants */
|
||||
|
||||
|
||||
@@ -24,36 +24,28 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "stm32x.h"
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "armv7m.h"
|
||||
#include "algorithm.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int stm32x_register_commands(struct command_context_s *cmd_ctx);
|
||||
int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int stm32x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int stm32x_probe(struct flash_bank_s *bank);
|
||||
int stm32x_auto_probe(struct flash_bank_s *bank);
|
||||
int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_protect_check(struct flash_bank_s *bank);
|
||||
int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int stm32x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int stm32x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int stm32x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int stm32x_probe(struct flash_bank_s *bank);
|
||||
static int stm32x_auto_probe(struct flash_bank_s *bank);
|
||||
//static int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_protect_check(struct flash_bank_s *bank);
|
||||
static int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int stm32x_mass_erase(struct flash_bank_s *bank);
|
||||
static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int stm32x_mass_erase(struct flash_bank_s *bank);
|
||||
|
||||
flash_driver_t stm32x_flash =
|
||||
{
|
||||
@@ -70,7 +62,7 @@ flash_driver_t stm32x_flash =
|
||||
.info = stm32x_info
|
||||
};
|
||||
|
||||
int stm32x_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int stm32x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *stm32x_cmd = register_command(cmd_ctx, NULL, "stm32x", NULL, COMMAND_ANY, "stm32x flash specific commands");
|
||||
|
||||
@@ -89,7 +81,7 @@ int stm32x_register_commands(struct command_context_s *cmd_ctx)
|
||||
|
||||
/* flash bank stm32x <base> <size> 0 0 <target#>
|
||||
*/
|
||||
int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info;
|
||||
|
||||
@@ -108,33 +100,38 @@ int stm32x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 stm32x_get_flash_status(flash_bank_t *bank)
|
||||
static uint32_t stm32x_get_flash_status(flash_bank_t *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
target_read_u32(target, STM32_FLASH_SR, &status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
u32 stm32x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
static uint32_t stm32x_wait_status_busy(flash_bank_t *bank, int timeout)
|
||||
{
|
||||
u32 status;
|
||||
target_t *target = bank->target;
|
||||
uint32_t status;
|
||||
|
||||
/* wait for busy to clear */
|
||||
while (((status = stm32x_get_flash_status(bank)) & FLASH_BSY) && (timeout-- > 0))
|
||||
{
|
||||
LOG_DEBUG("status: 0x%x", status);
|
||||
LOG_DEBUG("status: 0x%" PRIx32 "", status);
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
/* Clear but report errors */
|
||||
if (status & (FLASH_WRPRTERR | FLASH_PGERR))
|
||||
{
|
||||
target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int stm32x_read_options(struct flash_bank_s *bank)
|
||||
static int stm32x_read_options(struct flash_bank_s *bank)
|
||||
{
|
||||
u32 optiondata;
|
||||
uint32_t optiondata;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
|
||||
@@ -143,7 +140,7 @@ int stm32x_read_options(struct flash_bank_s *bank)
|
||||
/* read current option bytes */
|
||||
target_read_u32(target, STM32_FLASH_OBR, &optiondata);
|
||||
|
||||
stm32x_info->option_bytes.user_options = (u16)0xFFF8|((optiondata >> 2) & 0x07);
|
||||
stm32x_info->option_bytes.user_options = (uint16_t)0xFFF8 | ((optiondata >> 2) & 0x07);
|
||||
stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
|
||||
|
||||
if (optiondata & (1 << OPT_READOUT))
|
||||
@@ -152,19 +149,19 @@ int stm32x_read_options(struct flash_bank_s *bank)
|
||||
/* each bit refers to a 4bank protection */
|
||||
target_read_u32(target, STM32_FLASH_WRPR, &optiondata);
|
||||
|
||||
stm32x_info->option_bytes.protection[0] = (u16)optiondata;
|
||||
stm32x_info->option_bytes.protection[1] = (u16)(optiondata >> 8);
|
||||
stm32x_info->option_bytes.protection[2] = (u16)(optiondata >> 16);
|
||||
stm32x_info->option_bytes.protection[3] = (u16)(optiondata >> 24);
|
||||
stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata;
|
||||
stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8);
|
||||
stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16);
|
||||
stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
static int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -180,14 +177,14 @@ int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
|
||||
|
||||
/* erase option bytes */
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_OPTWRE);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER|FLASH_STRT|FLASH_OPTWRE);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* clear readout protection and complementary option bytes
|
||||
@@ -197,11 +194,11 @@ int stm32x_erase_options(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_write_options(struct flash_bank_s *bank)
|
||||
static int stm32x_write_options(struct flash_bank_s *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -214,16 +211,16 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
target_write_u32(target, STM32_FLASH_OPTKEYR, KEY2);
|
||||
|
||||
/* program option bytes */
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG|FLASH_OPTWRE);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE);
|
||||
|
||||
/* write user option byte */
|
||||
target_write_u16(target, STM32_OB_USER, stm32x_info->option_bytes.user_options);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* write protection byte 1 */
|
||||
@@ -231,9 +228,9 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* write protection byte 2 */
|
||||
@@ -241,9 +238,9 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* write protection byte 3 */
|
||||
@@ -251,9 +248,9 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* write protection byte 4 */
|
||||
@@ -261,9 +258,9 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* write readout protection bit */
|
||||
@@ -271,9 +268,9 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
|
||||
@@ -281,12 +278,12 @@ int stm32x_write_options(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
static int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
|
||||
u32 protection;
|
||||
uint32_t protection;
|
||||
int i, s;
|
||||
int num_bits;
|
||||
int set;
|
||||
@@ -307,14 +304,15 @@ int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
|
||||
if (stm32x_info->ppage_size == 2)
|
||||
{
|
||||
/* high density flash */
|
||||
/* high density flash/connectivity line protection */
|
||||
|
||||
set = 1;
|
||||
|
||||
if (protection & (1 << 31))
|
||||
set = 0;
|
||||
|
||||
/* bit 31 controls sector 62 - 255 protection */
|
||||
/* bit 31 controls sector 62 - 255 protection for high density
|
||||
* bit 31 controls sector 62 - 127 protection for connectivity line */
|
||||
for (s = 62; s < bank->num_sectors; s++)
|
||||
{
|
||||
bank->sectors[s].is_protected = set;
|
||||
@@ -336,12 +334,12 @@ int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* medium density flash */
|
||||
/* low/medium density flash protection */
|
||||
for (i = 0; i < num_bits; i++)
|
||||
{
|
||||
set = 1;
|
||||
|
||||
if( protection & (1 << i))
|
||||
if (protection & (1 << i))
|
||||
set = 0;
|
||||
|
||||
for (s = 0; s < stm32x_info->ppage_size; s++)
|
||||
@@ -352,11 +350,11 @@ int stm32x_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
int i;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -377,13 +375,13 @@ int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_PER);
|
||||
target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_PER|FLASH_STRT);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_PER | FLASH_STRT);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
@@ -393,14 +391,14 @@ int stm32x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
target_t *target = bank->target;
|
||||
u16 prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
|
||||
int i, reg, bit;
|
||||
int status;
|
||||
u32 protection;
|
||||
uint32_t protection;
|
||||
|
||||
stm32x_info = bank->driver_priv;
|
||||
|
||||
@@ -412,7 +410,7 @@ int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
|
||||
if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) && (last + 1) % stm32x_info->ppage_size))
|
||||
{
|
||||
LOG_WARNING("sector start/end incorrect - stm32 has %dK sector protection", stm32x_info->ppage_size);
|
||||
LOG_WARNING("Error: start and end sectors must be on a %d sector boundary", stm32x_info->ppage_size);
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
@@ -420,10 +418,10 @@ int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
* high density - each bit refers to a 2bank protection */
|
||||
target_read_u32(target, STM32_FLASH_WRPR, &protection);
|
||||
|
||||
prot_reg[0] = (u16)protection;
|
||||
prot_reg[1] = (u16)(protection >> 8);
|
||||
prot_reg[2] = (u16)(protection >> 16);
|
||||
prot_reg[3] = (u16)(protection >> 24);
|
||||
prot_reg[0] = (uint16_t)protection;
|
||||
prot_reg[1] = (uint16_t)(protection >> 8);
|
||||
prot_reg[2] = (uint16_t)(protection >> 16);
|
||||
prot_reg[3] = (uint16_t)(protection >> 24);
|
||||
|
||||
if (stm32x_info->ppage_size == 2)
|
||||
{
|
||||
@@ -448,7 +446,7 @@ int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
reg = (i / stm32x_info->ppage_size) / 8;
|
||||
bit = (i / stm32x_info->ppage_size) - (reg * 8);
|
||||
|
||||
if( set )
|
||||
if (set)
|
||||
prot_reg[reg] &= ~(1 << bit);
|
||||
else
|
||||
prot_reg[reg] |= (1 << bit);
|
||||
@@ -462,7 +460,7 @@ int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
reg = (i / stm32x_info->ppage_size) / 8;
|
||||
bit = (i / stm32x_info->ppage_size) - (reg * 8);
|
||||
|
||||
if( set )
|
||||
if (set)
|
||||
prot_reg[reg] &= ~(1 << bit);
|
||||
else
|
||||
prot_reg[reg] |= (1 << bit);
|
||||
@@ -480,18 +478,18 @@ int stm32x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
return stm32x_write_options(bank);
|
||||
}
|
||||
|
||||
int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int stm32x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 buffer_size = 8192;
|
||||
uint32_t buffer_size = 16384;
|
||||
working_area_t *source;
|
||||
u32 address = bank->base + offset;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[4];
|
||||
armv7m_algorithm_t armv7m_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
u8 stm32x_flash_write_code[] = {
|
||||
uint8_t stm32x_flash_write_code[] = {
|
||||
/* write: */
|
||||
0xDF, 0xF8, 0x24, 0x40, /* ldr r4, STM32_FLASH_CR */
|
||||
0x09, 0x4D, /* ldr r5, STM32_FLASH_SR */
|
||||
@@ -520,7 +518,7 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
|
||||
if ((retval=target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code))!=ERROR_OK)
|
||||
if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* memory buffer */
|
||||
@@ -548,16 +546,16 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;
|
||||
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)
|
||||
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);
|
||||
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
|
||||
stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error executing stm32x flash write algorithm");
|
||||
@@ -565,8 +563,20 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)
|
||||
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, STM32_FLASH_SR, FLASH_PGERR);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
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, STM32_FLASH_SR, FLASH_WRPRTERR);
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
@@ -587,15 +597,15 @@ int stm32x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 co
|
||||
return retval;
|
||||
}
|
||||
|
||||
int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int stm32x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 words_remaining = (count / 2);
|
||||
u32 bytes_remaining = (count & 0x00000001);
|
||||
u32 address = bank->base + offset;
|
||||
u32 bytes_written = 0;
|
||||
u8 status;
|
||||
u32 retval;
|
||||
uint32_t words_remaining = (count / 2);
|
||||
uint32_t bytes_remaining = (count & 0x00000001);
|
||||
uint32_t address = bank->base + offset;
|
||||
uint32_t bytes_written = 0;
|
||||
uint8_t status;
|
||||
int retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -605,7 +615,7 @@ int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (offset & 0x1)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required 2-byte alignment", offset);
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
@@ -641,15 +651,24 @@ int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
while (words_remaining > 0)
|
||||
{
|
||||
uint16_t value;
|
||||
memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
|
||||
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
|
||||
target_write_u16(target, address, *(u16*)(buffer + bytes_written));
|
||||
target_write_u16(target, address, value);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 5);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
{
|
||||
LOG_ERROR("flash memory not erased before writing");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
}
|
||||
if (status & FLASH_PGERR)
|
||||
{
|
||||
LOG_ERROR("flash memory write protected");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
bytes_written += 2;
|
||||
words_remaining--;
|
||||
@@ -658,25 +677,24 @@ int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (bytes_remaining)
|
||||
{
|
||||
u8 last_halfword[2] = {0xff, 0xff};
|
||||
int i = 0;
|
||||
|
||||
while(bytes_remaining > 0)
|
||||
{
|
||||
last_halfword[i++] = *(buffer + bytes_written);
|
||||
bytes_remaining--;
|
||||
bytes_written++;
|
||||
}
|
||||
uint16_t value = 0xffff;
|
||||
memcpy(&value, buffer + bytes_written, bytes_remaining);
|
||||
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_PG);
|
||||
target_write_u16(target, address, *(u16*)last_halfword);
|
||||
target_write_u16(target, address, value);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 5);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
{
|
||||
LOG_ERROR("flash memory not erased before writing");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
if( status & FLASH_PGERR )
|
||||
}
|
||||
if (status & FLASH_PGERR)
|
||||
{
|
||||
LOG_ERROR("flash memory write protected");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
|
||||
@@ -684,13 +702,13 @@ int stm32x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_probe(struct flash_bank_s *bank)
|
||||
static int stm32x_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
int i;
|
||||
u16 num_pages;
|
||||
u32 device_id;
|
||||
uint16_t num_pages;
|
||||
uint32_t device_id;
|
||||
int page_size;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -703,7 +721,7 @@ int stm32x_probe(struct flash_bank_s *bank)
|
||||
|
||||
/* read stm32 device id register */
|
||||
target_read_u32(target, 0xE0042000, &device_id);
|
||||
LOG_INFO( "device id = 0x%08x", device_id );
|
||||
LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
|
||||
|
||||
/* get flash size from target */
|
||||
if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)
|
||||
@@ -723,7 +741,7 @@ int stm32x_probe(struct flash_bank_s *bank)
|
||||
if (num_pages == 0xffff)
|
||||
{
|
||||
/* number of sectors incorrect on revA */
|
||||
LOG_WARNING( "STM32 flash size failed, probe inaccurate - assuming 128k flash" );
|
||||
LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 128k flash");
|
||||
num_pages = 128;
|
||||
}
|
||||
}
|
||||
@@ -738,7 +756,7 @@ int stm32x_probe(struct flash_bank_s *bank)
|
||||
if (num_pages == 0xffff)
|
||||
{
|
||||
/* number of sectors incorrect on revA */
|
||||
LOG_WARNING( "STM32 flash size failed, probe inaccurate - assuming 32k flash" );
|
||||
LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 32k flash");
|
||||
num_pages = 32;
|
||||
}
|
||||
}
|
||||
@@ -753,17 +771,32 @@ int stm32x_probe(struct flash_bank_s *bank)
|
||||
if (num_pages == 0xffff)
|
||||
{
|
||||
/* number of sectors incorrect on revZ */
|
||||
LOG_WARNING( "STM32 flash size failed, probe inaccurate - assuming 512k flash" );
|
||||
LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 512k flash");
|
||||
num_pages = 512;
|
||||
}
|
||||
}
|
||||
else if ((device_id & 0x7ff) == 0x418)
|
||||
{
|
||||
/* connectivity line density - we have 2k pages
|
||||
* 2 pages for a protection area */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
|
||||
/* check for early silicon */
|
||||
if (num_pages == 0xffff)
|
||||
{
|
||||
/* number of sectors incorrect on revZ */
|
||||
LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 256k flash");
|
||||
num_pages = 256;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING( "Cannot identify target as a STM32 family." );
|
||||
LOG_WARNING("Cannot identify target as a STM32 family.");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
LOG_INFO( "flash size = %dkbytes", num_pages );
|
||||
LOG_INFO("flash size = %dkbytes", num_pages);
|
||||
|
||||
/* calculate numbers of pages */
|
||||
num_pages /= (page_size / 1024);
|
||||
@@ -786,7 +819,7 @@ int stm32x_probe(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_auto_probe(struct flash_bank_s *bank)
|
||||
static int stm32x_auto_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
stm32x_flash_bank_t *stm32x_info = bank->driver_priv;
|
||||
if (stm32x_info->probed)
|
||||
@@ -794,15 +827,17 @@ int stm32x_auto_probe(struct flash_bank_s *bank)
|
||||
return stm32x_probe(bank);
|
||||
}
|
||||
|
||||
int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
#if 0
|
||||
static int stm32x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 device_id;
|
||||
uint32_t device_id;
|
||||
int printed;
|
||||
|
||||
/* read stm32 device id register */
|
||||
@@ -814,7 +849,7 @@ int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
switch(device_id >> 16)
|
||||
switch (device_id >> 16)
|
||||
{
|
||||
case 0x0000:
|
||||
snprintf(buf, buf_size, "A");
|
||||
@@ -843,7 +878,7 @@ int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
switch(device_id >> 16)
|
||||
switch (device_id >> 16)
|
||||
{
|
||||
case 0x1000:
|
||||
snprintf(buf, buf_size, "A");
|
||||
@@ -860,7 +895,28 @@ int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
switch(device_id >> 16)
|
||||
switch (device_id >> 16)
|
||||
{
|
||||
case 0x1000:
|
||||
snprintf(buf, buf_size, "A");
|
||||
break;
|
||||
|
||||
case 0x1001:
|
||||
snprintf(buf, buf_size, "Z");
|
||||
break;
|
||||
|
||||
default:
|
||||
snprintf(buf, buf_size, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((device_id & 0x7ff) == 0x418)
|
||||
{
|
||||
printed = snprintf(buf, buf_size, "stm32x (Connectivity) - Rev: ");
|
||||
buf += printed;
|
||||
buf_size -= printed;
|
||||
|
||||
switch (device_id >> 16)
|
||||
{
|
||||
case 0x1000:
|
||||
snprintf(buf, buf_size, "A");
|
||||
@@ -884,7 +940,7 @@ int stm32x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
@@ -933,7 +989,7 @@ int stm32x_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, cha
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
@@ -979,10 +1035,10 @@ int stm32x_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, c
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
u32 optionbyte;
|
||||
uint32_t optionbyte;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
|
||||
@@ -1010,27 +1066,27 @@ int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *
|
||||
}
|
||||
|
||||
target_read_u32(target, STM32_FLASH_OBR, &optionbyte);
|
||||
command_print(cmd_ctx, "Option Byte: 0x%x", optionbyte);
|
||||
command_print(cmd_ctx, "Option Byte: 0x%" PRIx32 "", optionbyte);
|
||||
|
||||
if (buf_get_u32((u8*)&optionbyte, OPT_ERROR, 1))
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_ERROR, 1))
|
||||
command_print(cmd_ctx, "Option Byte Complement Error");
|
||||
|
||||
if (buf_get_u32((u8*)&optionbyte, OPT_READOUT, 1))
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_READOUT, 1))
|
||||
command_print(cmd_ctx, "Readout Protection On");
|
||||
else
|
||||
command_print(cmd_ctx, "Readout Protection Off");
|
||||
|
||||
if (buf_get_u32((u8*)&optionbyte, OPT_RDWDGSW, 1))
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDWDGSW, 1))
|
||||
command_print(cmd_ctx, "Software Watchdog");
|
||||
else
|
||||
command_print(cmd_ctx, "Hardware Watchdog");
|
||||
|
||||
if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTOP, 1))
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTOP, 1))
|
||||
command_print(cmd_ctx, "Stop: No reset generated");
|
||||
else
|
||||
command_print(cmd_ctx, "Stop: Reset generated");
|
||||
|
||||
if (buf_get_u32((u8*)&optionbyte, OPT_RDRSTSTDBY, 1))
|
||||
if (buf_get_u32((uint8_t*)&optionbyte, OPT_RDRSTSTDBY, 1))
|
||||
command_print(cmd_ctx, "Standby: No reset generated");
|
||||
else
|
||||
command_print(cmd_ctx, "Standby: Reset generated");
|
||||
@@ -1038,16 +1094,16 @@ int stm32x_handle_options_read_command(struct command_context_s *cmd_ctx, char *
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
stm32x_flash_bank_t *stm32x_info = NULL;
|
||||
u16 optionbyte = 0xF8;
|
||||
uint16_t optionbyte = 0xF8;
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
command_print(cmd_ctx, "stm32x options_write <bank> <SWWDG|HWWDG> <RSTSTNDBY|NORSTSTNDBY> <RSTSTOP|NORSTSTOP>");
|
||||
command_print(cmd_ctx, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -1070,29 +1126,29 @@ int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char
|
||||
|
||||
if (strcmp(args[1], "SWWDG") == 0)
|
||||
{
|
||||
optionbyte |= (1<<0);
|
||||
optionbyte |= (1 << 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionbyte &= ~(1<<0);
|
||||
optionbyte &= ~(1 << 0);
|
||||
}
|
||||
|
||||
if (strcmp(args[2], "NORSTSTNDBY") == 0)
|
||||
{
|
||||
optionbyte |= (1<<1);
|
||||
optionbyte |= (1 << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionbyte &= ~(1<<1);
|
||||
optionbyte &= ~(1 << 1);
|
||||
}
|
||||
|
||||
if (strcmp(args[3], "NORSTSTOP") == 0)
|
||||
{
|
||||
optionbyte |= (1<<2);
|
||||
optionbyte |= (1 << 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionbyte &= ~(1<<2);
|
||||
optionbyte &= ~(1 << 2);
|
||||
}
|
||||
|
||||
if (stm32x_erase_options(bank) != ERROR_OK)
|
||||
@@ -1114,10 +1170,10 @@ int stm32x_handle_options_write_command(struct command_context_s *cmd_ctx, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
static int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 status;
|
||||
uint32_t status;
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -1131,19 +1187,19 @@ int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
|
||||
/* mass erase flash memory */
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_MER);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_MER|FLASH_STRT);
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_MER | FLASH_STRT);
|
||||
|
||||
status = stm32x_wait_status_busy(bank, 10);
|
||||
|
||||
target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
|
||||
|
||||
if( status & FLASH_WRPRTERR )
|
||||
if (status & FLASH_WRPRTERR)
|
||||
{
|
||||
LOG_ERROR("stm32x device protected");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if( status & FLASH_PGERR )
|
||||
if (status & FLASH_PGERR)
|
||||
{
|
||||
LOG_ERROR("stm32x device programming failed");
|
||||
return ERROR_OK;
|
||||
@@ -1152,7 +1208,7 @@ int stm32x_mass_erase(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int stm32x_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
int i;
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
#define STM32X_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct stm32x_options_s
|
||||
{
|
||||
u16 RDP;
|
||||
u16 user_options;
|
||||
u16 protection[4];
|
||||
uint16_t RDP;
|
||||
uint16_t user_options;
|
||||
uint16_t protection[4];
|
||||
} stm32x_options_t;
|
||||
|
||||
typedef struct stm32x_flash_bank_s
|
||||
@@ -65,21 +64,21 @@ typedef struct stm32x_flash_bank_s
|
||||
|
||||
/* FLASH_CR register bits */
|
||||
|
||||
#define FLASH_PG (1<<0)
|
||||
#define FLASH_PER (1<<1)
|
||||
#define FLASH_MER (1<<2)
|
||||
#define FLASH_OPTPG (1<<4)
|
||||
#define FLASH_OPTER (1<<5)
|
||||
#define FLASH_STRT (1<<6)
|
||||
#define FLASH_LOCK (1<<7)
|
||||
#define FLASH_OPTWRE (1<<9)
|
||||
#define FLASH_PG (1 << 0)
|
||||
#define FLASH_PER (1 << 1)
|
||||
#define FLASH_MER (1 << 2)
|
||||
#define FLASH_OPTPG (1 << 4)
|
||||
#define FLASH_OPTER (1 << 5)
|
||||
#define FLASH_STRT (1 << 6)
|
||||
#define FLASH_LOCK (1 << 7)
|
||||
#define FLASH_OPTWRE (1 << 9)
|
||||
|
||||
/* FLASH_SR regsiter bits */
|
||||
/* FLASH_SR register bits */
|
||||
|
||||
#define FLASH_BSY (1<<0)
|
||||
#define FLASH_PGERR (1<<2)
|
||||
#define FLASH_WRPRTERR (1<<4)
|
||||
#define FLASH_EOP (1<<5)
|
||||
#define FLASH_BSY (1 << 0)
|
||||
#define FLASH_PGERR (1 << 2)
|
||||
#define FLASH_WRPRTERR (1 << 4)
|
||||
#define FLASH_EOP (1 << 5)
|
||||
|
||||
/* STM32_FLASH_OBR bit definitions (reading) */
|
||||
|
||||
@@ -95,8 +94,8 @@ typedef struct stm32x_flash_bank_s
|
||||
#define KEY2 0xCDEF89AB
|
||||
|
||||
typedef struct stm32x_mem_layout_s {
|
||||
u32 sector_start;
|
||||
u32 sector_size;
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
} stm32x_mem_layout_t;
|
||||
|
||||
#endif /* STM32X_H */
|
||||
|
||||
@@ -24,19 +24,10 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "replacements.h"
|
||||
|
||||
#include "str7x.h"
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
#include "log.h"
|
||||
#include "armv4_5.h"
|
||||
#include "algorithm.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
str7x_mem_layout_t mem_layout_str7bank0[] = {
|
||||
{0x00000000, 0x02000, 0x01},
|
||||
@@ -54,17 +45,17 @@ str7x_mem_layout_t mem_layout_str7bank1[] = {
|
||||
{0x00002000, 0x02000, 0x20000}
|
||||
};
|
||||
|
||||
int str7x_register_commands(struct command_context_s *cmd_ctx);
|
||||
int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
int str7x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
|
||||
int str7x_probe(struct flash_bank_s *bank);
|
||||
int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int str7x_protect_check(struct flash_bank_s *bank);
|
||||
int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
static int str7x_register_commands(struct command_context_s *cmd_ctx);
|
||||
static int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
|
||||
static int str7x_erase(struct flash_bank_s *bank, int first, int last);
|
||||
static int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
|
||||
static int str7x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
|
||||
static int str7x_probe(struct flash_bank_s *bank);
|
||||
//static int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int str7x_protect_check(struct flash_bank_s *bank);
|
||||
static int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
|
||||
|
||||
int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
flash_driver_t str7x_flash =
|
||||
{
|
||||
@@ -81,7 +72,7 @@ flash_driver_t str7x_flash =
|
||||
.info = str7x_info
|
||||
};
|
||||
|
||||
int str7x_register_commands(struct command_context_s *cmd_ctx)
|
||||
static int str7x_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
command_t *str7x_cmd = register_command(cmd_ctx, NULL, "str7x", NULL, COMMAND_ANY, NULL);
|
||||
|
||||
@@ -91,13 +82,13 @@ int str7x_register_commands(struct command_context_s *cmd_ctx)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
|
||||
static int str7x_get_flash_adr(struct flash_bank_s *bank, uint32_t reg)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
return (str7x_info->register_base | reg);
|
||||
}
|
||||
|
||||
int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
static int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
|
||||
@@ -128,7 +119,7 @@ int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
|
||||
bank->num_sectors = num_sectors;
|
||||
bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
|
||||
str7x_info->sector_bits = malloc(sizeof(u32) * num_sectors);
|
||||
str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors);
|
||||
|
||||
num_sectors = 0;
|
||||
|
||||
@@ -155,7 +146,7 @@ int str7x_build_block_list(struct flash_bank_s *bank)
|
||||
|
||||
/* flash bank str7x <base> <size> 0 0 <target#> <str71_variant>
|
||||
*/
|
||||
int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
static int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info;
|
||||
|
||||
@@ -169,8 +160,8 @@ int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
bank->driver_priv = str7x_info;
|
||||
|
||||
/* set default bits for str71x flash */
|
||||
str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA1|FLASH_BSYA0);
|
||||
str7x_info->disable_bit = (1<<1);
|
||||
str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0);
|
||||
str7x_info->disable_bit = (1 << 1);
|
||||
|
||||
if (strcmp(args[6], "STR71x") == 0)
|
||||
{
|
||||
@@ -179,12 +170,12 @@ int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
else if (strcmp(args[6], "STR73x") == 0)
|
||||
{
|
||||
str7x_info->register_base = 0x80100000;
|
||||
str7x_info->busy_bits = (FLASH_LOCK|FLASH_BSYA0);
|
||||
str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0);
|
||||
}
|
||||
else if (strcmp(args[6], "STR75x") == 0)
|
||||
{
|
||||
str7x_info->register_base = 0x20100000;
|
||||
str7x_info->disable_bit = (1<<0);
|
||||
str7x_info->disable_bit = (1 << 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -200,33 +191,33 @@ int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
u32 str7x_status(struct flash_bank_s *bank)
|
||||
static uint32_t str7x_status(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 retval;
|
||||
uint32_t retval;
|
||||
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
u32 str7x_result(struct flash_bank_s *bank)
|
||||
static uint32_t str7x_result(struct flash_bank_s *bank)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
u32 retval;
|
||||
uint32_t retval;
|
||||
|
||||
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int str7x_protect_check(struct flash_bank_s *bank)
|
||||
static int str7x_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
int i;
|
||||
u32 retval;
|
||||
uint32_t retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -247,15 +238,15 @@ int str7x_protect_check(struct flash_bank_s *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
static int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
|
||||
int i;
|
||||
u32 cmd;
|
||||
u32 retval;
|
||||
u32 sectors = 0;
|
||||
uint32_t cmd;
|
||||
uint32_t retval;
|
||||
uint32_t sectors = 0;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -268,7 +259,7 @@ int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
sectors |= str7x_info->sector_bits[i];
|
||||
}
|
||||
|
||||
LOG_DEBUG("sectors: 0x%x", sectors);
|
||||
LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors);
|
||||
|
||||
/* clear FLASH_ER register */
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0);
|
||||
@@ -279,10 +270,10 @@ int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
cmd = sectors;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd);
|
||||
|
||||
cmd = FLASH_SER|FLASH_WMS;
|
||||
cmd = FLASH_SER | FLASH_WMS;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
|
||||
|
||||
while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){
|
||||
while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
@@ -290,7 +281,7 @@ int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
|
||||
if (retval)
|
||||
{
|
||||
LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%x", retval);
|
||||
LOG_ERROR("error erasing flash bank, FLASH_ER: 0x%" PRIx32 "", retval);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -300,14 +291,14 @@ int str7x_erase(struct flash_bank_s *bank, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
static int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
int i;
|
||||
u32 cmd;
|
||||
u32 retval;
|
||||
u32 protect_blocks;
|
||||
uint32_t cmd;
|
||||
uint32_t retval;
|
||||
uint32_t protect_blocks;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
{
|
||||
@@ -335,16 +326,16 @@ int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
cmd = protect_blocks;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd);
|
||||
|
||||
cmd = FLASH_SPR|FLASH_WMS;
|
||||
cmd = FLASH_SPR | FLASH_WMS;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd);
|
||||
|
||||
while (((retval = str7x_status(bank)) & str7x_info->busy_bits)){
|
||||
while (((retval = str7x_status(bank)) & str7x_info->busy_bits)) {
|
||||
alive_sleep(1);
|
||||
}
|
||||
|
||||
retval = str7x_result(bank);
|
||||
|
||||
LOG_DEBUG("retval: 0x%8.8x", retval);
|
||||
LOG_DEBUG("retval: 0x%8.8" PRIx32 "", retval);
|
||||
|
||||
if (retval & FLASH_ERER)
|
||||
return ERROR_FLASH_SECTOR_NOT_ERASED;
|
||||
@@ -354,18 +345,18 @@ int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int str7x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
target_t *target = bank->target;
|
||||
u32 buffer_size = 8192;
|
||||
uint32_t buffer_size = 8192;
|
||||
working_area_t *source;
|
||||
u32 address = bank->base + offset;
|
||||
uint32_t address = bank->base + offset;
|
||||
reg_param_t reg_params[6];
|
||||
armv4_5_algorithm_t armv4_5_info;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
u32 str7x_flash_write_code[] = {
|
||||
uint32_t str7x_flash_write_code[] = {
|
||||
/* write: */
|
||||
0xe3a04201, /* mov r4, #0x10000000 */
|
||||
0xe5824000, /* str r4, [r2, #0x0] */
|
||||
@@ -398,7 +389,7 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
};
|
||||
|
||||
target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (u8*)str7x_flash_write_code);
|
||||
target_write_buffer(target, str7x_info->write_algorithm->address, 20 * 4, (uint8_t*)str7x_flash_write_code);
|
||||
|
||||
/* memory buffer */
|
||||
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
|
||||
@@ -428,7 +419,7 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
u32 thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
|
||||
uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;
|
||||
|
||||
target_write_buffer(target, source->address, thisrun_count * 8, buffer);
|
||||
|
||||
@@ -438,7 +429,7 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
|
||||
buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
|
||||
buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);
|
||||
|
||||
if ((retval = target->type->run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
|
||||
if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params, str7x_info->write_algorithm->address, str7x_info->write_algorithm->address + (19 * 4), 10000, &armv4_5_info)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error executing str7x flash write algorithm");
|
||||
retval = ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -469,17 +460,17 @@ int str7x_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 cou
|
||||
return retval;
|
||||
}
|
||||
|
||||
int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
static int str7x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
target_t *target = bank->target;
|
||||
str7x_flash_bank_t *str7x_info = bank->driver_priv;
|
||||
u32 dwords_remaining = (count / 8);
|
||||
u32 bytes_remaining = (count & 0x00000007);
|
||||
u32 address = bank->base + offset;
|
||||
u32 bytes_written = 0;
|
||||
u32 cmd;
|
||||
u32 retval;
|
||||
u32 check_address = offset;
|
||||
uint32_t dwords_remaining = (count / 8);
|
||||
uint32_t bytes_remaining = (count & 0x00000007);
|
||||
uint32_t address = bank->base + offset;
|
||||
uint32_t bytes_written = 0;
|
||||
uint32_t cmd;
|
||||
int retval;
|
||||
uint32_t check_address = offset;
|
||||
int i;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED)
|
||||
@@ -490,14 +481,14 @@ int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (offset & 0x7)
|
||||
{
|
||||
LOG_WARNING("offset 0x%x breaks required 8-byte alignment", offset);
|
||||
LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
u32 sec_start = bank->sectors[i].offset;
|
||||
u32 sec_end = sec_start + bank->sectors[i].size;
|
||||
uint32_t sec_start = bank->sectors[i].offset;
|
||||
uint32_t sec_end = sec_start + bank->sectors[i].size;
|
||||
|
||||
/* check if destination falls within the current sector */
|
||||
if ((check_address >= sec_start) && (check_address < sec_end))
|
||||
@@ -555,11 +546,11 @@ int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
|
||||
|
||||
/* data word 1 */
|
||||
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
|
||||
target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written);
|
||||
bytes_written += 4;
|
||||
|
||||
/* data word 2 */
|
||||
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
|
||||
target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written);
|
||||
bytes_written += 4;
|
||||
|
||||
/* start programming cycle */
|
||||
@@ -584,10 +575,10 @@ int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
|
||||
if (bytes_remaining)
|
||||
{
|
||||
u8 last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int i = 0;
|
||||
|
||||
while(bytes_remaining > 0)
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
last_dword[i++] = *(buffer + bytes_written);
|
||||
bytes_remaining--;
|
||||
@@ -602,11 +593,11 @@ int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address);
|
||||
|
||||
/* data word 1 */
|
||||
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
|
||||
target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword);
|
||||
bytes_written += 4;
|
||||
|
||||
/* data word 2 */
|
||||
target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
|
||||
target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4);
|
||||
bytes_written += 4;
|
||||
|
||||
/* start programming cycle */
|
||||
@@ -629,32 +620,34 @@ int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_probe(struct flash_bank_s *bank)
|
||||
static int str7x_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
#if 0
|
||||
static int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
static int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
snprintf(buf, buf_size, "str7x flash driver info" );
|
||||
snprintf(buf, buf_size, "str7x flash driver info");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
static int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
target_t *target = NULL;
|
||||
str7x_flash_bank_t *str7x_info = NULL;
|
||||
|
||||
u32 flash_cmd;
|
||||
u32 retval;
|
||||
u16 ProtectionLevel = 0;
|
||||
u16 ProtectionRegs;
|
||||
uint32_t flash_cmd;
|
||||
uint32_t retval;
|
||||
uint16_t ProtectionLevel = 0;
|
||||
uint16_t ProtectionRegs;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
@@ -710,7 +703,7 @@ int str7x_handle_disable_jtag_command(struct command_context_s *cmd_ctx, char *c
|
||||
flash_cmd = FLASH_SPR;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1<<(15+ProtectionLevel)));
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + ProtectionLevel)));
|
||||
flash_cmd = FLASH_SPR | FLASH_WMS;
|
||||
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
#define STR7X_H
|
||||
|
||||
#include "flash.h"
|
||||
#include "target.h"
|
||||
|
||||
typedef struct str7x_flash_bank_s
|
||||
{
|
||||
u32 *sector_bits;
|
||||
u32 disable_bit;
|
||||
u32 busy_bits;
|
||||
u32 register_base;
|
||||
uint32_t *sector_bits;
|
||||
uint32_t disable_bit;
|
||||
uint32_t busy_bits;
|
||||
uint32_t register_base;
|
||||
working_area_t *write_algorithm;
|
||||
} str7x_flash_bank_t;
|
||||
|
||||
@@ -60,14 +59,14 @@ enum str7x_status_codes
|
||||
#define FLASH_AR 0x00000010
|
||||
#define FLASH_ER 0x00000014
|
||||
#define FLASH_NVWPAR 0x0000DFB0
|
||||
#define FLASH_NVAPR0 0x0000DFB8
|
||||
#define FLASH_NVAPR1 0x0000DFBC
|
||||
#define FLASH_NVAPR0 0x0000DFB8
|
||||
#define FLASH_NVAPR1 0x0000DFBC
|
||||
|
||||
/* FLASH_CR0 register bits */
|
||||
|
||||
#define FLASH_WMS 0x80000000
|
||||
#define FLASH_SUSP 0x40000000
|
||||
#define FLASH_WPG 0x20000000
|
||||
#define FLASH_WPG 0x20000000
|
||||
#define FLASH_DWPG 0x10000000
|
||||
#define FLASH_SER 0x08000000
|
||||
#define FLASH_SPR 0x01000000
|
||||
@@ -77,7 +76,7 @@ enum str7x_status_codes
|
||||
#define FLASH_BSYA1 0x00000004
|
||||
#define FLASH_BSYA0 0x00000002
|
||||
|
||||
/* FLASH_CR1 regsiter bits */
|
||||
/* FLASH_CR1 register bits */
|
||||
|
||||
#define FLASH_B1S 0x02000000
|
||||
#define FLASH_B0S 0x01000000
|
||||
@@ -103,9 +102,9 @@ enum str7x_status_codes
|
||||
#define FLASH_ERR 0x00000001
|
||||
|
||||
typedef struct str7x_mem_layout_s {
|
||||
u32 sector_start;
|
||||
u32 sector_size;
|
||||
u32 sector_bit;
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_size;
|
||||
uint32_t sector_bit;
|
||||
} str7x_mem_layout_t;
|
||||
|
||||
#endif /* STR7X_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user