blackmagic-debug / blackmagic

In application debugger for ARM Cortex microcontrollers.
GNU General Public License v3.0
3.21k stars 766 forks source link

Adding support for i.MXRT6xx #1753

Open ohunter opened 7 months ago

ohunter commented 7 months ago

Hey, I was trying to use blackmagic along with an OrbTrace Mini on an NXP RT685 evk and I encountered a few issues preventing me from doing so. I know the I.MXRT series from NXP are different from most other controllers so I didnt expect it to be plug-n-play if I'm being honest but this ended up just not working.

The first issue is that of recognizing that it was supposed to use the I.MXRT interface whatsoever. In the designer_code switch statement in cortexm_probe() the NXP JEP106 code only maps to an LPC55xx controller (assuming the controller even is an M33). I am not sure what values to check for to differentiate between the LPC and the I.MXRT controller in here but they shouldn't be treated the same. Since I know my target is an I.MXRT controller I just replaced the LPC call with the I.MXRT call. After doing that the log after running with -tv1 looks like this:

Black Magic Debug App v1.10.2-dirty
 for Black Magic Probe, ST-Link v2 and v3, CMSIS-DAP, J-Link and FTDI (MPSSE)
Using 1209:3443 2F24718163008E06 Orbcode
 Orbtrace v1.3.1-0-gd096575
Using bulk transfer
Adaptor version v1.3.1-0-gd096575, CMSIS-DAP v2.1.0
Capabilities: 03 (JTAG/SWD)
Adaptor supports DAP SWD sequences
Running in Test Mode
Target voltage: (null) Volt
Speed set to 4.000MHz for SWD
Switching out of dormant state into SWD
Handling SWD multi-drop, TARGETID 0x0000002b
DP DPIDR 0x6ba02477 (v2 rev0) designer 0x43b partno 0xba
TARGETID 0x0000002b designer 0x15 partno 0x0
AP   0: IDR=84770001 CFG=00000000 BASE=e00fe003 CSW=83800040 (AHB3-AP var0 rev8)
Halt via DHCSR(00130003): success after 1ms
ROM: Table BASE=0xe00fe000 SYSMEM=0x00000001, Manufacturer 015 Partno 000
ROM: Table BASE=0xe00ff000 SYSMEM=0x00000001, Manufacturer 43b Partno 4c9
 0 0xe000e000: Debug component - Cortex-M33 (System Control Space) (PIDR = 0x00000004000bbd21 DEVTYPE = 0x00 ARCHID = 0x2a04)
 -> cortexm_probe
CPUID 0x410fd213 (M33 var 0 rev 3)

The line Target voltage: (null) Volt screams at me that something is wrong, but I have not had the time to look into it.

The second issue seems to be that the part number is incorrect as I doubt NXP would just set it to the extremely error-prone value of 0. However since I know my target I just add that to the valid part ids in imxrt_probe().

The last issue I experienced is that after the imxrt_ident_device() call which detects the system correctly the boot_mode failes with the following printout:

Access resulted in fault
dap_read_single failed (fault = 4)

All subsequent calls also print out the same error. I am not sure why this fails and the same call in imxrt_ident_device() doesn't although I suspect that it has to do with the address that is accessed.

dragonmux commented 7 months ago

There's a lot to unpack here, and particularly as support for your target has not been explicitly added and we didn't even know it was i.MXRT-like.

The big switch-case to which you refer is designed as a "try this, then this, then this" type of piece of logic w/ the target-specific probe routines doing identification to extract a positive identification because the ROM table information on which the Cortex-M architecture implementation has to make decisions is insufficient. Therefore, do not replace routine calls in that switch-case, only add to them (otherwise you are removing support for an existing part!):

     case JEP106_MANUFACTURER_NXP:
-        if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33)
+        if ((target->cpuid & CORTEX_CPUID_PARTNO_MASK) == CORTEX_M33) {
             PROBE(lpc55xx_probe);
+            PROBE(imxrt_probe);
+        }
         else
             DEBUG_WARN("Unhandled NXP device\n");
         break;

The PROBE macro checks the return value of the function named as the macro argument - if it returns true, it concludes checking and returns true from the probe routine, otherwise it clears errors and falls through to the next statement below the macro.

CMSIS-DAP does not provide a way for us to read the Vtgt voltage, which is why it's displayed as "(null)", this is normal and to be expected.

As for the TARGETID - that is the actual value read from the DP register. NXP screwed up - it's not particularly uncommon for vendors to so yes, that's the actual and real part number they shipped. Likewise they've shipped duff ROM tables - they've made the exact same mistake in the outer most AP ROM Table, and the next one in is ARM's pre-made table for the Cortex-M33 core (this is why it's got ARM's JEP-106 and sane values, they've not mucked with that table thankfully).

With regards to imxrt_ident_device(), that is written for the i.MXRT's address space layout. Likely, your target has a different address space layout and needs addresses used for it specifically. Given this, you probably actually want to write a new probe routine specifically for this part - rt6xx_probe() maybe? - and a rt6xx_ident_device() call that uses the correct addresses for your part. The existing routine uses the correct ones for the i.MXRT, so can't be modified to just use this part's.

ohunter commented 7 months ago

I suspect you may have misunderstood me which is my bad. When I say RT6xx I mean the I.MXRT6xx series. It is advertised as the I.MX RT600 by NXP.

Having stepped through imxrt_ident_device() I know that it behaves correctly. So when the subsequent call to target_mem_read32() fails I suspect it is because IMXRT_SRC_BOOT_MODE2 is (as you said) outside of the supported address space of the controller. Thus it'd need special handling. I am not partial to any way of doing this, but it seems weird to separate the I.MX RT600 from the rest of the I.MXRT series. Are the boot_mode and boot_cfg variables supposed to represent the values of the ISP pins? If so then both boot mode addresses are definitely incorrect for the I.MXRT600.

dragonmux commented 7 months ago

Ah, yeah, that i.MX prefix is not optional. specifically in this case.. i.MXRT6xx.

Yes, boot_mode is the currently selected boot mode, and boot_cfg the boot configuration - both taken, as you correctly noted, from the boot pins via the state latch that's provided.

This is not a target that has been tested against, so it's not surprising there are issues, especially when it's showing entirely broken ROM tables and part identification. It sounds like the SRC (System Reset Controller) might well be at a different address which is why the issue. This is where those two boot registers are located.

In the i.MXRT1060 reference manual, you will find them defined in §21.6, pg 1273 as SRC_SBMR1 and SRC_SBMR2.

ohunter commented 7 months ago

I am looking through UM11147 and I'm not able to see what you're referring to. Which document are you using?

dragonmux commented 7 months ago

IMXRT1060RM - note it will require you to log into the NXP website to download. All the information you need is in the reference manuals, not the user guides.

ohunter commented 7 months ago

I see. To me it looks like the I.MX RT6xx works slightly differently compared to the 1060. Here is the correct document for this controller.

dragonmux commented 7 months ago

So, taking a read of that user manual.. it looks like the i.MXRT600 is an i.MXRT in name only vs basically all the rest of the series - its entire architecture is vastly different. The only reason it has a compatible Flash controller is that it's using the Freescale Flash SPI controller (FlexSPI). Nothing else about how this device works or is laid out is otherwise the same.

SYSCON has SYSCTL0_PRODUCT_ID (0x40002000 + 0x60) which contains an identification value we can use to confirm it's actually an i.MXRT600 we're poking at, solving that device identification problem along with the JTAG ID register in the same controller at +0x68.

Determining the boot mode appears to require reading PIO1_{15,17} manually and hoping they're still in boot state. This device, unlike the rest, does not implement a boot-time latch for these 3 pins states. See §41.3, table 995, pg1090. This will include having to figure out the GPIO name to register mappings from §9.5, pg318.

ohunter commented 7 months ago

One alternative might be to read the OTP fuses of the boot config though I don't know whether that would solve every case

ohunter commented 7 months ago

Would you rather have this in a separate file or together with the rest of the imxrt implementations. Due to some discussion revolving implementing support for the I.MXRT6xx and I.MXRT5xx in probe-rs I suspect that they both behave similarly but with different address spaces ect.