Skip to content

Commit 0fd5e80

Browse files
ttt-t3rflit
authored andcommitted
Added code to unlock AP for lpc55s69
1 parent ec20c42 commit 0fd5e80

File tree

1 file changed

+162
-35
lines changed

1 file changed

+162
-35
lines changed

pyocd/target/family/target_lpc5500.py

Lines changed: 162 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
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");
@@ -17,6 +18,8 @@
1718
from time import sleep
1819
import logging
1920

21+
from ...utility.sequencer import CallSequence
22+
from ...core import exceptions
2023
from ...core.target import Target
2124
from ...coresight.coresight_target import CoreSightTarget
2225
from ...core.memory_map import (FlashRegion, RamRegion, RomRegion, MemoryMap)
@@ -43,29 +46,69 @@
4346
FLASH_INT_STATUS = 0x00034FE0
4447
FLASH_INT_CLR_STATUS = 0x00034FE8
4548
FLASH_CMD_READ_SINGLE_WORD = 0x3
49+
FLASH_CMD_BLANK_CHECK = 0x5
4650

4751
BOOTROM_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+
4973
LOG = logging.getLogger(__name__)
5074

5175
class 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+
135238
class 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

Comments
 (0)