11# pyOCD debugger
22# Copyright (c) 2019-2020 Arm Limited
3+ # Copyright (C) 2020 Ted Tawara
34# SPDX-License-Identifier: Apache-2.0
45#
56# Licensed under the Apache License, Version 2.0 (the "License");
1718from time import sleep
1819import logging
1920
21+ from ...utility .sequencer import CallSequence
22+ from ...core import exceptions
2023from ...core .target import Target
2124from ...coresight .coresight_target import CoreSightTarget
2225from ...core .memory_map import (FlashRegion , RamRegion , RomRegion , MemoryMap )
4346FLASH_INT_STATUS = 0x00034FE0
4447FLASH_INT_CLR_STATUS = 0x00034FE8
4548FLASH_CMD_READ_SINGLE_WORD = 0x3
49+ FLASH_CMD_BLANK_CHECK = 0x5
4650
4751BOOTROM_MAGIC_ADDR = 0x50000040
4852
53+ DM_AP = 2
54+
55+ # Control and Status Word (CSW) is used to control the Debug Mailbox communication
56+ DM_CSW = 0x00
57+ # Debugger will set this bit to 1 to request a resynchronrisation
58+ DM_CSW_RESYNCH_REQ_MASK = (1 << 0 )
59+ # Write only bit. Once written will cause the chip to reset (note that the DM is not
60+ # reset by this reset as it is only resettable by a SOFT reset or a POR/BOD event)
61+ DM_CSW_CHIP_RESET_REQ_MASK = (1 << 5 )
62+
63+ # Request register is used to send data from debugger to device
64+ DM_REQUEST = 0x04
65+
66+ # Return register is used to send data from device to debugger
67+ # Note: Any read from debugger side will be stalled until new data is present.
68+ DM_RETURN = 0x08
69+
70+ ## Debugger mailbox command to start a debug session (unlock debug).
71+ DM_START_DBG_SESSION = 7
72+
4973LOG = logging .getLogger (__name__ )
5074
5175class LPC5500Family (CoreSightTarget ):
5276
5377 VENDOR = "NXP"
5478
79+ # Minimum value for the 'adi.v5.max_invalid_ap_count' option.
80+ _MIN_INVALID_APS = 3
81+
5582 def create_init_sequence (self ):
5683 seq = super (LPC5500Family , self ).create_init_sequence ()
5784
58- seq .wrap_task ('discovery' ,
59- lambda seq : seq
60- .wrap_task ('find_components' , self ._modify_ap1 ) \
61- .replace_task ('create_cores' , self .create_lpc55xx_cores ) \
62- .insert_before ('create_components' ,
63- ('enable_traceclk' , self ._enable_traceclk ),
64- )
65- )
66-
85+ seq .wrap_task ('discovery' , self .modify_discovery )
86+ return seq
87+
88+ def modify_discovery (self , seq ):
89+ seq .insert_before ('find_aps' ,
90+ ('set_max_invalid_aps' , self .set_max_invalid_aps )) \
91+ .insert_before ('find_components' ,
92+ ('check_locked_state' , lambda : self .check_locked_state (seq ))) \
93+ .wrap_task ('find_components' , self ._modify_ap1 ) \
94+ .replace_task ('create_cores' , self .create_lpc55xx_cores ) \
95+ .insert_before ('create_components' ,
96+ ('enable_traceclk' , self ._enable_traceclk ),
97+ ) \
98+ .append (('restore_max_invalid_aps' , self .restore_max_invalid_aps ))
6799 return seq
68100
101+ def set_max_invalid_aps (self ):
102+ # Save current option and make sure it is set to at least 3.
103+ self ._saved_max_invalid_aps = self .session .options .get ('adi.v5.max_invalid_ap_count' )
104+ if self ._saved_max_invalid_aps < self ._MIN_INVALID_APS :
105+ self .session .options .set ('adi.v5.max_invalid_ap_count' , self ._MIN_INVALID_APS )
106+
107+ def restore_max_invalid_aps (self ):
108+ # Only restore if we changed it.
109+ if self ._saved_max_invalid_aps < self ._MIN_INVALID_APS :
110+ self .session .options .set ('adi.v5.max_invalid_ap_count' , self ._saved_max_invalid_aps )
111+
69112 def _modify_ap1 (self , seq ):
70113 # If AP#1 exists we need to adjust it before we can read the ROM.
71114 if seq .has_task ('init_ap.1' ):
@@ -75,34 +118,64 @@ def _modify_ap1(self, seq):
75118
76119 return seq
77120
121+ def check_locked_state (self , seq ):
122+ """! @brief Attempt to unlock cores if they are locked (flash is empty etc.)"""
123+ # The device is not locked if AP#0 was found and is enabled.
124+ if (0 in self .aps ) and self .aps [0 ].is_enabled :
125+ return
126+
127+ # The debugger mailbox should always be present.
128+ if not DM_AP in self .aps :
129+ LOG .error ("cannot request debug unlock; no debugger mailbox AP was found" )
130+ return
131+
132+ # Perform the unlock procedure using the debugger mailbox.
133+ self .unlock (self .aps [DM_AP ])
134+
135+ # re-run discovery
136+ LOG .info ("re-running discovery" )
137+ new_seq = CallSequence ()
138+ for entry in seq :
139+ if entry [0 ] == 'check_locked_state' :
140+ break
141+ new_seq .append (entry )
142+ self .dp .valid_aps = None
143+ return new_seq
144+
78145 def _set_ap1_nonsec (self ):
79146 # Make AP#1 transactions non-secure so transfers will succeed.
80147 self .aps [1 ].hnonsec = 1
81148
82149 def create_lpc55xx_cores (self ):
83150 # Make sure AP#0 was detected.
84- if 0 not in self .aps :
151+ if ( 0 not in self .aps ) or ( not self . aps [ 0 ]. is_enabled ) :
85152 LOG .error ("AP#0 was not found, unable to create core 0" )
86153 return
87154
88- # Create core 0 with a custom class.
89- core0 = CortexM_LPC5500 (self .session , self .aps [0 ], self .memory_map , 0 )
90- core0 .default_reset_type = self .ResetType .SW_SYSRESETREQ
91- self .aps [0 ].core = core0
92- core0 .init ()
93- self .add_core (core0 )
155+ try :
156+ # Create core 0 with a custom class.
157+ core0 = CortexM_LPC5500 (self .session , self .aps [0 ], self .memory_map , 0 )
158+ core0 .default_reset_type = self .ResetType .SW_SYSRESETREQ
159+ self .aps [0 ].core = core0
160+ core0 .init ()
161+ self .add_core (core0 )
162+ except exceptions .Error as err :
163+ LOG .error ("Error creating core 0: %s" , err , exc_info = self .session .log_tracebacks )
94164
95165 # Create core 1 if the AP is present. It uses the standard Cortex-M core class for v8-M.
96- if 1 in self .aps :
97- core1 = CortexM_v8M (self .session , self .aps [1 ], self .memory_map , 1 )
98- core1 .default_reset_type = self .ResetType .SW_SYSRESETREQ
99- self .aps [1 ].core = core1
100- core1 .init ()
101- self .add_core (core1 )
166+ if (1 in self .aps ) and (self .aps [0 ].is_enabled ):
167+ try :
168+ core1 = CortexM_v8M (self .session , self .aps [1 ], self .memory_map , 1 )
169+ core1 .default_reset_type = self .ResetType .SW_SYSRESETREQ
170+ self .aps [1 ].core = core1
171+ core1 .init ()
172+ self .add_core (core1 )
173+ except exceptions .Error as err :
174+ LOG .error ("Error creating core 1: %s" , err , exc_info = self .session .log_tracebacks )
102175
103176 def _enable_traceclk (self ):
104177 # Don't make it worse if no APs were found.
105- if 0 not in self .aps :
178+ if ( 0 not in self .aps ) or ( not self . aps [ 0 ]. is_enabled ) :
106179 return
107180
108181 SYSCON_NS_Base_Addr = 0x40000000
@@ -132,13 +205,43 @@ def trace_start(self):
132205 # To prevent this, we explicitly (re)enable traceclk.
133206 self ._enable_traceclk ()
134207
208+ def unlock (self , dm_ap ):
209+ """! @brief Unlock Cores. See UM11126 51.6.1 """
210+ assert self .dp .probe .is_open
211+
212+ LOG .info ("attempting unlock procedure" )
213+
214+ # Set RESYNCH_REQ (0x1) and CHIP_RESET_REQ (0x20) in DM.CSW.
215+ dm_ap .write_reg (addr = DM_CSW , data = (DM_CSW_RESYNCH_REQ_MASK | DM_CSW_CHIP_RESET_REQ_MASK ))
216+ dm_ap .dp .flush ()
217+
218+ # Wait for reset to complete.
219+ sleep (0.1 )
220+
221+ # Read CSW to verify the reset happened and the register is cleared.
222+ retval = dm_ap .read_reg (addr = DM_CSW )
223+ if retval != 0 :
224+ LOG .error ("debugger mailbox failed to reset the device" )
225+ return
226+
227+ # Write debug unlock request.
228+ dm_ap .write_reg (addr = DM_REQUEST , data = DM_START_DBG_SESSION )
229+ dm_ap .dp .flush ()
230+
231+ # Read reply from boot ROM. The return status is the low half-word.
232+ retval = dm_ap .read_reg (addr = DM_RETURN ) & 0xffff
233+ if retval != 0 :
234+ LOG .error ("received error from unlock attempt (%x)" , retval )
235+ return
236+ return
237+
135238class CortexM_LPC5500 (CortexM_v8M ):
136239
137240 def reset_and_halt (self , reset_type = None ):
138241 """! @brief Perform a reset and stop the core on the reset handler. """
139-
242+ halt_only = False
140243 catch_mode = 0
141-
244+
142245 delegateResult = self .call_delegate ('set_reset_catch' , core = self , reset_type = reset_type )
143246
144247 # Save CortexM.DEMCR
@@ -158,27 +261,48 @@ def reset_and_halt(self, reset_type=None):
158261 base = PERIPHERAL_BASE_S
159262 else :
160263 base = PERIPHERAL_BASE_NS
161-
162- # Use the flash programming model to check if the first flash page is readable, since
163- # attempted accesses to erased pages result in bus faults. The start and stop address
164- # are both set to 0x0 to probe the sector containing the reset vector.
264+
265+ #
266+ # Check to see if the flash is erased
267+ #
165268 self .write32 (base + FLASH_STARTA , 0x00000000 ) # Program flash word start address to 0x0
166269 self .write32 (base + FLASH_STOPA , 0x00000000 ) # Program flash word stop address to 0x0
167- self .write_memory_block32 (base + FLASH_DATAW0 , [0x00000000 ] * 8 ) # Prepare for read
168270 self .write32 (base + FLASH_INT_CLR_STATUS , 0x0000000F ) # Clear Flash controller status
169- self .write32 (base + FLASH_CMD , FLASH_CMD_READ_SINGLE_WORD ) # Read single flash word
271+ self .write32 (base + FLASH_CMD , FLASH_CMD_BLANK_CHECK ) # Check if page is cleared
170272
171273 # Wait for flash word read to finish.
172274 with timeout .Timeout (5.0 ) as t_o :
173275 while t_o .check ():
174276 if (self .read32 (base + FLASH_INT_STATUS ) & 0x00000004 ) != 0 :
175277 break
176278 sleep (0.01 )
177-
279+
178280 # Check for error reading flash word.
179281 if (self .read32 (base + FLASH_INT_STATUS ) & 0xB ) == 0 :
180- # Read the reset vector address.
181- reset_vector = self .read32 (0x00000004 )
282+ LOG .info ("required flash area is erased" )
283+ halt_only = True
284+
285+ # Use the flash programming model to check if the first flash page is readable, since
286+ # attempted accesses to erased pages result in bus faults. The start and stop address
287+ # are both set to 0x0 to probe the sector containing the reset vector.
288+ self .write32 (base + FLASH_STARTA , 0x00000000 ) # Program flash word start address to 0x0
289+ self .write32 (base + FLASH_STOPA , 0x00000000 ) # Program flash word stop address to 0x0
290+ self .write_memory_block32 (base + FLASH_DATAW0 , [0x00000000 ] * 8 ) # Prepare for read
291+ self .write32 (base + FLASH_INT_CLR_STATUS , 0x0000000F ) # Clear Flash controller status
292+ if not halt_only :
293+ self .write32 (base + FLASH_CMD , FLASH_CMD_READ_SINGLE_WORD ) # Read single flash word
294+
295+ # Wait for flash word read to finish.
296+ with timeout .Timeout (5.0 ) as t_o :
297+ while t_o .check ():
298+ if (self .read32 (base + FLASH_INT_STATUS ) & 0x00000004 ) != 0 :
299+ break
300+ sleep (0.01 )
301+
302+ # Check for error reading flash word.
303+ if (self .read32 (base + FLASH_INT_STATUS ) & 0xB ) == 0 :
304+ # Read the reset vector address.
305+ reset_vector = self .read32 (0x00000004 )
182306
183307 # Break on user application reset vector if we have a valid breakpoint address.
184308 if reset_vector != 0xFFFFFFFF :
@@ -196,7 +320,10 @@ def reset_and_halt(self, reset_type=None):
196320 # Read DHCSR to clear potentially set DHCSR.S_RESET_ST bit
197321 self .read32 (CortexM .DHCSR )
198322
199- self .reset (reset_type )
323+ if not halt_only :
324+ self .reset (reset_type )
325+ else :
326+ self .halt ()
200327
201328 # wait until the unit resets
202329 with timeout .Timeout (2.0 ) as t_o :
0 commit comments