diff options
| author | Sandeep Gundlupet Raju <sandeep.gundlupet-raju@amd.com> | 2024-03-12 19:20:24 -0600 |
|---|---|---|
| committer | Mark Hatle <mark.hatle@amd.com> | 2024-03-15 13:08:07 -0500 |
| commit | 3a9cd6df2cda6e502c2e4556303ef77006d8387a (patch) | |
| tree | 030322e7f935e14ed1a22e64ad83ca8f81f06758 | |
| parent | d10b2f6f3c502265830583f994d31de7d5d6e48b (diff) | |
| download | meta-xilinx-3a9cd6df2cda6e502c2e4556303ef77006d8387a.tar.gz | |
boot-jtag.py: Add devtool script for jtag boot mode
This script uses devtool and creates a boot-jtag.tcl script in
${DEPLOY_DIR_IMAGE} directory. This script is executed by xsdb tool to
boot yocto generated images on HW via jtag boot mode.
Signed-off-by: Sandeep Gundlupet Raju <sandeep.gundlupet-raju@amd.com>
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
| -rw-r--r-- | meta-xilinx-core/lib/devtool/boot-jtag.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/meta-xilinx-core/lib/devtool/boot-jtag.py b/meta-xilinx-core/lib/devtool/boot-jtag.py new file mode 100644 index 00000000..53d70262 --- /dev/null +++ b/meta-xilinx-core/lib/devtool/boot-jtag.py | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | # Copyright (C) 2021-2022, Xilinx, Inc. All rights reserved. | ||
| 2 | # Copyright (C) 2022-2024, Advanced Micro Devices, Inc. All rights reserved. | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: MIT | ||
| 5 | # | ||
| 6 | # This script uses devtool and creates a boot-jtag.tcl script in | ||
| 7 | # ${DEPLOY_DIR_IMAGE} directory. This script is executed by xsdb tool to boot | ||
| 8 | # yocto generated images on HW via jtag boot mode. | ||
| 9 | |||
| 10 | import os | ||
| 11 | import logging | ||
| 12 | import argparse | ||
| 13 | from devtool import setup_tinfoil, parse_recipe, DevtoolError | ||
| 14 | import yaml | ||
| 15 | import sys | ||
| 16 | import glob | ||
| 17 | |||
| 18 | logger = logging.getLogger('devtool') | ||
| 19 | |||
| 20 | def bootjtag(args, config, basepath, workspace): | ||
| 21 | """Entry point for the devtool 'boot-jtag' subcommand""" | ||
| 22 | |||
| 23 | if not args.image: | ||
| 24 | print('\nINFO: Please specify the target image name. \n\nExample: --image core-image-minimal or petalinux-image-minimal') | ||
| 25 | return | ||
| 26 | |||
| 27 | # Get required boot variables | ||
| 28 | tinfoil = setup_tinfoil(basepath=basepath) | ||
| 29 | try: | ||
| 30 | rd = tinfoil.parse_recipe('u-boot-xlnx-scr') | ||
| 31 | deploy_dir = rd.getVar('DEPLOY_DIR_IMAGE') | ||
| 32 | machine = rd.getVar('MACHINE') | ||
| 33 | arch = rd.getVar('TARGET_ARCH') | ||
| 34 | soc = rd.getVar("SOC_FAMILY") | ||
| 35 | soc_variant = rd.getVar("SOC_VARIANT") | ||
| 36 | ddr_base_addr = rd.getVar('DDR_BASEADDR') | ||
| 37 | kernel_img_name = rd.getVar('KERNEL_IMAGE') | ||
| 38 | kernel_load_addr = rd.getVar('KERNEL_LOAD_ADDRESS') | ||
| 39 | dtb_load_addr = rd.getVar('DEVICETREE_ADDRESS') | ||
| 40 | rootfs_load_addr = rd.getVar('RAMDISK_IMAGE_ADDRESS') | ||
| 41 | machine_features = rd.getVar('MACHINE_FEATURES') | ||
| 42 | boot_mode = rd.getVar('BOOTMODE') | ||
| 43 | finally: | ||
| 44 | tinfoil.shutdown() | ||
| 45 | |||
| 46 | if not args.hw_server: | ||
| 47 | print("\nINFO: --hw_server is null so default URL description of hw_server/TCF agent and port number is set to: " + str(args.hw_server)) | ||
| 48 | |||
| 49 | print("INFO: HW_SERVER Connected to: " + str(args.hw_server)) | ||
| 50 | print("INFO: Using DISTRO IMAGE: " + str(args.image)) | ||
| 51 | |||
| 52 | # Use arch for MB and SOC Family other devices. | ||
| 53 | if arch == 'microblazeel': | ||
| 54 | print("INFO: ARCH: " + arch) | ||
| 55 | else: | ||
| 56 | print("INFO: SOC FAMILY: " + soc) | ||
| 57 | |||
| 58 | # Load Address of boot.scr in DDR(Except for QSPI/OSPI/NAND boot) | ||
| 59 | # MB = (DDR base address + DDR Size) - 0xe00000 | ||
| 60 | # Zynq 7000 = DDR base address + 0x3000000 | ||
| 61 | # ZynqMP = DDR base address + 0x20000000 | ||
| 62 | # Versal = DDR base address + 0x20000000 | ||
| 63 | if arch == 'microblazeel': | ||
| 64 | # Assuming DDR size is 2GB | ||
| 65 | bootscr_addr = hex(int(ddr_base_addr, 16) + 0x80000000 - 0xe00000) | ||
| 66 | elif soc == 'zynq': | ||
| 67 | bootscr_addr = hex(int(ddr_base_addr, 16) + 0x3000000) | ||
| 68 | else: | ||
| 69 | bootscr_addr = hex(int(ddr_base_addr, 16) + 0x20000000) | ||
| 70 | |||
| 71 | print("INFO: MACHINE: " + machine) | ||
| 72 | |||
| 73 | if arch != 'microblazeel': | ||
| 74 | if "fpga-overaly" in machine_features: | ||
| 75 | print("INFO: fpga-overlay MACHINE_FEATURES is enabled, Hence PL bitstream or PDI will not be loaded at initial boot, User can load from u-boot or linux.") | ||
| 76 | else: | ||
| 77 | print("INFO: fpga-overlay MACHINE_FEATURES is not enabled, Hence PL bitstream or PDI will be loaded at initial boot.") | ||
| 78 | |||
| 79 | #dictionary with all required artifacts | ||
| 80 | data = {} | ||
| 81 | |||
| 82 | # For MB, Zynq 7000 and ZynqMP. | ||
| 83 | if arch == 'microblazeel' or soc == 'zynq' or soc == 'zynqmp': | ||
| 84 | if not "fpga-overaly" in machine_features: | ||
| 85 | data['bit'] = glob.glob(os.path.join(deploy_dir, '*' + machine + '.bit'))[0] | ||
| 86 | data['uboot'] = os.path.join(deploy_dir, 'u-boot.elf') | ||
| 87 | data['dtb'] = os.path.join(deploy_dir, machine + '-system.dtb') | ||
| 88 | |||
| 89 | if soc == 'zynq' or soc == 'zynqmp': | ||
| 90 | data['fsbl'] = os.path.join(deploy_dir, 'fsbl-' + machine + '.elf') | ||
| 91 | |||
| 92 | if soc == 'zynqmp': | ||
| 93 | data['atf'] = os.path.join(deploy_dir, 'arm-trusted-firmware.elf') | ||
| 94 | data['pmufw'] = os.path.join(deploy_dir, 'pmu-firmware-' + machine + '.elf') | ||
| 95 | |||
| 96 | if soc == 'versal': | ||
| 97 | data['bootbin'] = os.path.join(deploy_dir, 'boot.bin') | ||
| 98 | |||
| 99 | data['bootscr'] = os.path.join(deploy_dir, 'boot.scr') | ||
| 100 | data['kernel'] = os.path.join(deploy_dir, kernel_img_name) | ||
| 101 | |||
| 102 | if not args.norootfs: | ||
| 103 | data['rfs'] = os.path.join(deploy_dir, args.image + '-' + machine + '.cpio.gz.u-boot') | ||
| 104 | |||
| 105 | # Check if all the required boot images exists | ||
| 106 | for key in data: | ||
| 107 | if not os.path.isfile(data[key]): | ||
| 108 | print('INFO:' + key + ' does not exist.') | ||
| 109 | print('INFO: Please make sure you have run: \n\'MACHINE=' + machine + ' devtool build-image ' + args.image + '\'') | ||
| 110 | return | ||
| 111 | |||
| 112 | # Enable verbose mode | ||
| 113 | if args.verbose: | ||
| 114 | print("The following artifacts are being loaded:") | ||
| 115 | for key in data: | ||
| 116 | print('INFO: ' + key + ": " + data[key]) | ||
| 117 | |||
| 118 | # Start writing xsdb script | ||
| 119 | lines = [] | ||
| 120 | lines.append('# Run \'xsdb ' + deploy_dir + '/boot-jtag.tcl\' to execute this script.') | ||
| 121 | lines.append('connect -url ' + args.hw_server) | ||
| 122 | |||
| 123 | if arch == 'microblazeel' or soc == 'zynq' or soc == 'zynqmp': | ||
| 124 | lines.append('for {set i 0} {$i < 20} {incr i} {') | ||
| 125 | lines.append(' if { [ta] != "" } break;') | ||
| 126 | lines.append(' after 50') | ||
| 127 | lines.append('}') | ||
| 128 | if not "fpga-overaly" in machine_features: | ||
| 129 | lines.append('') | ||
| 130 | lines.append('puts stderr "INFO: Configuring the PL ..."') | ||
| 131 | lines.append('puts stderr "INFO: Downloading bitstream: ' + data['bit'] + '"') | ||
| 132 | lines.append('fpga -no-revision-check \"' + data['bit'] + '\"') | ||
| 133 | |||
| 134 | if soc == 'zynqmp': | ||
| 135 | # Disable Security gates to view PMU MB target | ||
| 136 | lines.append('') | ||
| 137 | lines.append('targets -set -nocase -filter {name =~ \"*PSU*\"}') | ||
| 138 | |||
| 139 | # By default, JTAG security gates are enabled. This disables security gates for DAP, PLTAP and PMU. | ||
| 140 | lines.append('mask_write 0xFFCA0038 0x1C0 0x1C0') | ||
| 141 | lines.append('targets -set -nocase -filter {name =~ \"*MicroBlaze PMU*\"}') | ||
| 142 | lines.append('') | ||
| 143 | |||
| 144 | # Check if the target is already stopped or cannot be stopped. | ||
| 145 | lines.append('catch {stop}; after 1000') | ||
| 146 | lines.append('') | ||
| 147 | |||
| 148 | # Download the pmufw.elf and run PMUFW | ||
| 149 | lines.append('puts stderr "INFO: Downloading PMUFW ELF file: ' + data['pmufw'] + '"') | ||
| 150 | lines.append('dow \"' + data['pmufw'] + '\"') | ||
| 151 | lines.append('con') | ||
| 152 | |||
| 153 | # Select A53 Core 0 to load and run FSBL | ||
| 154 | lines.append('targets -set -nocase -filter {name =~ \"*A53*#0\"}') | ||
| 155 | |||
| 156 | # Reset A53, If the reset is being triggered after powering on the device, | ||
| 157 | # write bootloop at reset vector address (0xffff0000), or use | ||
| 158 | # -clear-registers option, to avoid unpredictable behavior. | ||
| 159 | # Further warnings will be suppressed | ||
| 160 | lines.append('rst -processor -clear-registers') | ||
| 161 | lines.append('') | ||
| 162 | elif soc == 'versal': | ||
| 163 | # Download boot.bin to versal device | ||
| 164 | lines.append('targets -set -nocase -filter {name =~ \"*PMC*\"}') | ||
| 165 | lines.append('puts stderr "INFO: Downloading BOOT bin file: ' + data['bootbin'] + '"') | ||
| 166 | lines.append('device program \"' + data['bootbin'] + '\"') | ||
| 167 | lines.append('') | ||
| 168 | |||
| 169 | if soc_variant == 'net': | ||
| 170 | lines.append('targets -set -nocase -filter {name =~ \"*A78*#0\"}') | ||
| 171 | else: | ||
| 172 | lines.append('targets -set -nocase -filter {name =~ \"*A72*#0\"}') | ||
| 173 | |||
| 174 | lines.append('stop') | ||
| 175 | lines.append('') | ||
| 176 | lines.append('targets -set -nocase -filter {name =~ \"*Versal*\"}') | ||
| 177 | elif soc == 'zynq': | ||
| 178 | lines.append('targets -set -nocase -filter {name =~ \"arm*#0\"}') | ||
| 179 | # Check if the target is already stopped or cannot be stopped. | ||
| 180 | lines.append('catch {stop}; after 1000') | ||
| 181 | lines.append('') | ||
| 182 | else: | ||
| 183 | lines.append('targets -set -nocase -filter {name =~ \"microblaze*#0\"}') | ||
| 184 | # Check if the target is already stopped or cannot be stopped. | ||
| 185 | lines.append('catch {stop}; after 1000') | ||
| 186 | lines.append('') | ||
| 187 | |||
| 188 | |||
| 189 | if soc == 'zynq' or soc == 'zynqmp': | ||
| 190 | # Download FSBL for Zynq 7000 and ZynqMP | ||
| 191 | lines.append('puts stderr "INFO: Downloading FSBL ELF file: ' + data['fsbl'] + '"') | ||
| 192 | lines.append('dow \"' + data['fsbl'] + '\"') | ||
| 193 | lines.append('con') | ||
| 194 | lines.append('after 4000; stop') | ||
| 195 | lines.append('') | ||
| 196 | |||
| 197 | # Download U-boot and DTB for MB, Zynq 7000 and ZynqMP | ||
| 198 | if arch == 'microblazeel' or soc == 'zynq' or soc == 'zynqmp': | ||
| 199 | lines.append('puts stderr "INFO: Downloading U-boot ELF file: ' + data['uboot'] + '"') | ||
| 200 | lines.append('dow \"' + data['uboot'] + '\"') | ||
| 201 | lines.append('') | ||
| 202 | # For MB and Zynq 7000 we need to connect and stop before loading | ||
| 203 | # kernel images | ||
| 204 | if soc != 'zynqmp': | ||
| 205 | lines.append('con') | ||
| 206 | lines.append('after 1000; stop') | ||
| 207 | lines.append('puts stderr "INFO: Downloading DTB file: ' + data['dtb'] + ' at ' + dtb_load_addr + '"') | ||
| 208 | lines.append('dow -data \"' + data['dtb'] + '\" ' + dtb_load_addr) | ||
| 209 | lines.append('') | ||
| 210 | |||
| 211 | # Download Trusted Firmware-A(TF-A) for ZynqMP | ||
| 212 | # Note: TF-A elf should be loaded after u-boot elf in JTAG boot mode else | ||
| 213 | # TF-A elf will not be loaded. | ||
| 214 | if soc == 'zynqmp': | ||
| 215 | lines.append('puts stderr "INFO: Downloading Trusted Firmware-A(TF-A) ELF file: ' + data['atf'] + '"') | ||
| 216 | lines.append('dow \"' + data['atf'] + '\"') | ||
| 217 | lines.append('') | ||
| 218 | |||
| 219 | # If BOOTMODE is xen then boot till u-boot only. | ||
| 220 | # Download Kernel Image for all architecture | ||
| 221 | if boot_mode != 'xen': | ||
| 222 | lines.append('puts stderr "INFO: Downloading Kernel Image file: ' + data['kernel'] + ' at ' + kernel_load_addr + '"') | ||
| 223 | lines.append('dow -data \"' + data['kernel'] + '\" ' + kernel_load_addr) | ||
| 224 | lines.append('') | ||
| 225 | |||
| 226 | # Download Rootfs | ||
| 227 | if not args.norootfs and boot_mode != 'xen': | ||
| 228 | lines.append('puts stderr "INFO: Downloading Rootfs file: ' + data['rfs'] + ' at ' + rootfs_load_addr + '"') | ||
| 229 | lines.append('dow -data \"' + data['rfs'] + '\" ' + rootfs_load_addr) | ||
| 230 | lines.append('') | ||
| 231 | |||
| 232 | lines.append('puts stderr "INFO: Downloading U-boot boot script: ' + data['bootscr'] + ' at ' + bootscr_addr + '"') | ||
| 233 | lines.append('dow -data \"' + data['bootscr'] + '\" ' + bootscr_addr) | ||
| 234 | lines.append('') | ||
| 235 | |||
| 236 | # Select A72 Core 0 to load and run Versal images | ||
| 237 | if soc == 'versal': | ||
| 238 | if soc_variant == 'net': | ||
| 239 | lines.append('targets -set -nocase -filter {name =~ \"*A78*#0\"}') | ||
| 240 | else: | ||
| 241 | lines.append('targets -set -nocase -filter {name =~ \"*A72*#0\"}') | ||
| 242 | |||
| 243 | lines.append('con') | ||
| 244 | lines.append('exit\n') | ||
| 245 | |||
| 246 | script = os.path.join(deploy_dir, "boot-jtag.tcl") | ||
| 247 | with open(script, "w") as f: | ||
| 248 | f.write('\n'.join(lines)) | ||
| 249 | |||
| 250 | print('INFO: HW JTAG boot tcl script written to '+ script + "\n" \ | ||
| 251 | + 'INFO: User can run \'xsdb ' + script + '\' to execute.') | ||
| 252 | |||
| 253 | return 0 | ||
| 254 | |||
| 255 | def register_commands(subparsers, context): | ||
| 256 | """Register devtool subcommands from this plugin""" | ||
| 257 | parser_bootjtag = subparsers.add_parser('boot-jtag', | ||
| 258 | help='Script to deploy target images on HW via JTAG boot mode.', | ||
| 259 | description='Script to deploy target images on HW via JTAG boot mode. \ | ||
| 260 | Example command: MACHINE=zcu102-zynqmp devtool boot-jtag --image ${image_name} --hw_server ${hw_server}') | ||
| 261 | required = parser_bootjtag.add_argument_group('required arguments') | ||
| 262 | required.add_argument('--image', | ||
| 263 | help='Specify target image name. Example: core-image-minimal or petalinux-image-minimal') | ||
| 264 | parser_bootjtag.add_argument('--hw_server', nargs='?', default='TCP:localhost:3121', | ||
| 265 | help='URL description of hw_server/TCF agent and port number. (default: %(default)s) \ | ||
| 266 | Example: --hw_server TCP:puffball12:3121') | ||
| 267 | |||
| 268 | parser_bootjtag.add_argument('-v', '--verbose', | ||
| 269 | help='verbose mode', action="store_true") | ||
| 270 | parser_bootjtag.add_argument('-n', '--norootfs', | ||
| 271 | help='Don\'t include rootfs', action='store_true') | ||
| 272 | parser_bootjtag.set_defaults(func=bootjtag, no_workspace=True) | ||
