tcl/target: add SPDX tag
[fw/openocd] / tcl / target / psoc4.cfg
1 # SPDX-License-Identifier: GPL-2.0-or-later
2
3 # script for Cypress PSoC 4 devices
4
5 #
6 # PSoC 4 devices support SWD transports only.
7 #
8 source [find target/swj-dp.tcl]
9
10 if { [info exists CHIPNAME] } {
11    set _CHIPNAME $CHIPNAME
12 } else {
13    set _CHIPNAME psoc4
14 }
15
16 # Work-area is a space in RAM used for flash programming
17 # By default use 4kB
18 if { [info exists WORKAREASIZE] } {
19    set _WORKAREASIZE $WORKAREASIZE
20 } else {
21    set _WORKAREASIZE 0x1000
22 }
23
24 if { [info exists CPUTAPID] } {
25    set _CPUTAPID $CPUTAPID
26 } else {
27    set _CPUTAPID 0x0bb11477
28 }
29
30 swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
31 dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
32
33 set _TARGETNAME $_CHIPNAME.cpu
34 target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
35
36 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
37
38 set _FLASHNAME $_CHIPNAME.flash
39 flash bank $_FLASHNAME psoc4 0 0 0 0 $_TARGETNAME
40
41 adapter speed 1500
42
43 # Reset, bloody PSoC 4 reset
44 #
45 # 1) XRES (nSRST) resets also SWD DP so SWD line reset and DP reinit is needed.
46 # High level adapter stops working after SRST and needs OpenOCD restart.
47 # If your hw does not use SRST for other circuits, use sysresetreq instead
48 #
49 # 2) PSoC 4 executes initialization code from system ROM after reset.
50 # This code subsequently jumps to user flash reset vector address.
51 # Unfortunately the system ROM code is protected from reading and debugging.
52 # Protection breaks vector catch VC_CORERESET used for "reset halt" by cortex_m.
53 #
54 # Cypress uses TEST_MODE flag to loop CPU in system ROM before executing code
55 # from user flash. Programming specifications states that TEST_MODE flag must be
56 # set in time frame 400 usec delayed about 1 msec from reset.
57 #
58 # OpenOCD have no standard way how to set TEST_MODE in specified time frame.
59 # As a workaround the TEST_MODE flag is set before reset instead.
60 # It worked for the oldest family PSoC4100/4200 even though it is not guaranteed
61 # by specification.
62 #
63 # Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE
64 # clear TEST_MODE flag during device reset so workaround is not possible.
65 # Use a KitProg adapter for these devices or "reset halt" will not stop
66 # before executing user code.
67 #
68 # 3) SWD cannot be connected during system initialization after reset.
69 # This might be a reason for unconnecting ST-Link v2 when deasserting reset.
70 # As a workaround arp_reset deassert is not called for hla
71
72 if {![using_hla]} {
73    # if srst is not fitted use SYSRESETREQ to
74    # perform a soft reset
75    cortex_m reset_config sysresetreq
76 }
77
78 proc psoc4_get_family_id {} {
79         set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}]
80         if { $err } {
81                 return 0
82         }
83         if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }]
84           || [expr {[lindex $romtable_pid 1] & 0xffffff00 }]
85           || [expr {[lindex $romtable_pid 2] & 0xffffff00 }] } {
86                 echo "Unexpected data in ROMTABLE"
87                 return 0
88         }
89         set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $romtable_pid 2] & 0xf ) << 4 ) }]
90         if { $designer_id != 0xb4 } {
91                 echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id]
92                 return 0
93         }
94         set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }]
95         return $family_id
96 }
97
98 proc ocd_process_reset_inner { MODE } {
99         global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND
100         global _TARGETNAME
101
102         if { 0 != [string compare $_TARGETNAME [target names]] } {
103                 return -code error "PSoC 4 reset can handle only one $_TARGETNAME target";
104         }
105         set t $_TARGETNAME
106
107         # If this target must be halted...
108         set halt -1
109         if { 0 == [string compare $MODE halt] } {
110                 set halt 1
111         }
112         if { 0 == [string compare $MODE init] } {
113                 set halt 1;
114         }
115         if { 0 == [string compare $MODE run ] } {
116                 set halt 0;
117         }
118         if { $halt < 0 } {
119                 return -code error "Invalid mode: $MODE, must be one of: halt, init, or run";
120         }
121
122         if { ! [info exists PSOC4_USE_ACQUIRE] } {
123                 if { 0 == [string compare [adapter name] kitprog ] } {
124                         set PSOC4_USE_ACQUIRE 1
125                 } else {
126                         set PSOC4_USE_ACQUIRE 0
127                 }
128         }
129         if { $PSOC4_USE_ACQUIRE } {
130                 set PSOC4_TEST_MODE_WORKAROUND 0
131         } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } {
132                 if { [psoc4_get_family_id] == 0x93 } {
133                         set PSOC4_TEST_MODE_WORKAROUND 1
134                 } else {
135                         set PSOC4_TEST_MODE_WORKAROUND 0
136                 }
137         }
138
139         #$t invoke-event reset-start
140         $t invoke-event reset-assert-pre
141
142         if { $halt && $PSOC4_USE_ACQUIRE } {
143                 catch { [adapter name] acquire_psoc }
144                 $t arp_examine
145         } else {
146                 if { $PSOC4_TEST_MODE_WORKAROUND } {
147                         set TEST_MODE 0x40030014
148                         if { $halt == 1 } {
149                                 catch { mww $TEST_MODE 0x80000000 }
150                         } else {
151                                 catch { mww $TEST_MODE 0 }
152                         }
153                 }
154
155                 $t arp_reset assert 0
156         }
157
158         $t invoke-event reset-assert-post
159         $t invoke-event reset-deassert-pre
160         if {![using_hla]} {     # workaround ST-Link v2 fails and forcing reconnect
161                 $t arp_reset deassert 0
162         }
163         $t invoke-event reset-deassert-post
164
165         # Pass 1 - Now wait for any halt (requested as part of reset
166         # assert/deassert) to happen.  Ideally it takes effect without
167         # first executing any instructions.
168         if { $halt } {
169                 # Now PSoC CPU should loop in system ROM
170                 $t arp_waitstate running 200
171                 $t arp_halt
172
173                 # Catch, but ignore any errors.
174                 catch { $t arp_waitstate halted 1000 }
175
176                 # Did we succeed?
177                 set s [$t curstate]
178
179                 if { 0 != [string compare $s "halted" ] } {
180                         return -code error [format "TARGET: %s - Not halted" $t]
181                 }
182
183                 # Check if PSoC CPU is stopped in system ROM
184                 set pc [reg pc]
185                 regsub {pc[^:]*: } $pc "" pc
186                 if { $pc < 0x10000000 || $pc > 0x1000ffff } {
187                         set hint ""
188                         set family_id [psoc4_get_family_id]
189                         if { $family_id == 0x93 } {
190                                 set hint ", use 'reset_config none'"
191                         } elseif { $family_id > 0x93 } {
192                                 set hint ", use a KitProg adapter"
193                         }
194                         return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint]
195                 }
196
197                 # Set registers to reset vector values
198                 set value [read_memory 0x0 32 2]
199                 reg pc [expr {[lindex $value 1] & 0xfffffffe}]
200                 reg msp [lindex $value 0]
201
202                 if { $PSOC4_TEST_MODE_WORKAROUND } {
203                         catch { mww $TEST_MODE 0 }
204                 }
205         }
206
207         #Pass 2 - if needed "init"
208         if { 0 == [string compare init $MODE] } {
209                 set err [catch "$t arp_waitstate halted 5000"]
210
211                 # Did it halt?
212                 if { $err == 0 } {
213                         $t invoke-event reset-init
214                 }
215         }
216
217         $t invoke-event reset-end
218 }