1# SPDX-License-Identifier: GPL-2.0 2# (C) Copyright 2023, Advanced Micro Devices, Inc. 3 4import pytest 5import random 6import string 7import test_net 8 9""" 10Note: This test relies on boardenv_* containing configuration values to define 11RPU applications information for AMD's ZynqMP SoC which contains, application 12names, processors, address where it is built, expected output and the tftp load 13addresses. This test will be automatically skipped without this. 14 15It also relies on dhcp or setup_static net test to support tftp to load 16application on DDR. All the environment parameters are stored sequentially. 17The length of all parameters values should be same. For example, if 2 app_names 18are defined in a list as a value of parameter 'app_name' then the other 19parameters value also should have a list with 2 items. 20It will run RPU cases for all the applications defined in boardenv_* 21configuration file. 22 23Example: 24env__zynqmp_rpu_apps = { 25 'app_name': ['hello_world_r5_0_ddr.elf', 'hello_world_r5_1_ddr.elf'], 26 'proc': ['rpu0', 'rpu1'], 27 'cpu_num': [4, 5], 28 'addr': [0xA00000, 0xB00000], 29 'output': ['Successfully ran Hello World application on DDR from RPU0', 30 'Successfully ran Hello World application on DDR from RPU1'], 31 'tftp_addr': [0x100000, 0x200000], 32} 33""" 34 35# Get rpu apps params from env 36def get_rpu_apps_env(u_boot_console): 37 rpu_apps = u_boot_console.config.env.get('env__zynqmp_rpu_apps', False) 38 if not rpu_apps: 39 pytest.skip('ZynqMP RPU application info not defined!') 40 41 apps = rpu_apps.get('app_name', None) 42 if not apps: 43 pytest.skip('No RPU application found!') 44 45 procs = rpu_apps.get('proc', None) 46 if not procs: 47 pytest.skip('No RPU application processor provided!') 48 49 cpu_nums = rpu_apps.get('cpu_num', None) 50 if not cpu_nums: 51 pytest.skip('No CPU number for respective processor provided!') 52 53 addrs = rpu_apps.get('addr', None) 54 if not addrs: 55 pytest.skip('No RPU application build address found!') 56 57 outputs = rpu_apps.get('output', None) 58 if not outputs: 59 pytest.skip('Expected output not found!') 60 61 tftp_addrs = rpu_apps.get('tftp_addr', None) 62 if not tftp_addrs: 63 pytest.skip('TFTP address to load application not found!') 64 65 return apps, procs, cpu_nums, addrs, outputs, tftp_addrs 66 67# Check return code 68def ret_code(u_boot_console): 69 return u_boot_console.run_command('echo $?') 70 71# Initialize tcm 72def tcminit(u_boot_console, rpu_mode): 73 output = u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode) 74 assert 'Initializing TCM overwrites TCM content' in output 75 return ret_code(u_boot_console) 76 77# Load application in DDR 78def load_app_ddr(u_boot_console, tftp_addr, app): 79 output = u_boot_console.run_command('tftpboot %x %s' % (tftp_addr, app)) 80 assert 'TIMEOUT' not in output 81 assert 'Bytes transferred = ' in output 82 83 # Load elf 84 u_boot_console.run_command('bootelf -p %x' % tftp_addr) 85 assert ret_code(u_boot_console).endswith('0') 86 87# Disable cpus 88def disable_cpus(u_boot_console, cpu_nums): 89 for num in cpu_nums: 90 u_boot_console.run_command(f'cpu {num} disable') 91 92# Load apps on RPU cores 93def rpu_apps_load(u_boot_console, rpu_mode): 94 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env( 95 u_boot_console) 96 test_net.test_net_dhcp(u_boot_console) 97 if not test_net.net_set_up: 98 test_net.test_net_setup_static(u_boot_console) 99 100 try: 101 assert tcminit(u_boot_console, rpu_mode).endswith('0') 102 103 for i in range(len(apps)): 104 if rpu_mode == 'lockstep' and procs[i] != 'rpu0': 105 continue 106 107 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i]) 108 rel_addr = int(addrs[i] + 0x3C) 109 110 # Release cpu at app load address 111 cpu_num = cpu_nums[i] 112 cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode) 113 output = u_boot_console.run_command(cmd) 114 exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}' 115 assert exp_op in output 116 assert f'R5 {rpu_mode} mode' in output 117 u_boot_console.wait_for(outputs[i]) 118 assert ret_code(u_boot_console).endswith('0') 119 finally: 120 disable_cpus(u_boot_console, cpu_nums) 121 122@pytest.mark.buildconfigspec('cmd_zynqmp') 123def test_zynqmp_rpu_app_load_split(u_boot_console): 124 rpu_apps_load(u_boot_console, 'split') 125 126@pytest.mark.buildconfigspec('cmd_zynqmp') 127def test_zynqmp_rpu_app_load_lockstep(u_boot_console): 128 rpu_apps_load(u_boot_console, 'lockstep') 129 130@pytest.mark.buildconfigspec('cmd_zynqmp') 131def test_zynqmp_rpu_app_load_negative(u_boot_console): 132 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env( 133 u_boot_console) 134 135 # Invalid commands 136 u_boot_console.run_command('zynqmp tcminit mode') 137 assert ret_code(u_boot_console).endswith('1') 138 139 rand_str = ''.join(random.choices(string.ascii_lowercase, k=4)) 140 u_boot_console.run_command('zynqmp tcminit %s' % rand_str) 141 assert ret_code(u_boot_console).endswith('1') 142 143 rand_num = random.randint(2, 100) 144 u_boot_console.run_command('zynqmp tcminit %d' % rand_num) 145 assert ret_code(u_boot_console).endswith('1') 146 147 test_net.test_net_dhcp(u_boot_console) 148 if not test_net.net_set_up: 149 test_net.test_net_setup_static(u_boot_console) 150 151 try: 152 rpu_mode = 'split' 153 assert tcminit(u_boot_console, rpu_mode).endswith('0') 154 155 for i in range(len(apps)): 156 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i]) 157 158 # Run in split mode at different load address 159 rel_addr = int(addrs[i]) + random.randint(200, 1000) 160 cpu_num = cpu_nums[i] 161 cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode) 162 output = u_boot_console.run_command(cmd) 163 exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}' 164 assert exp_op in output 165 assert f'R5 {rpu_mode} mode' in output 166 assert not outputs[i] in output 167 168 # Invalid rpu mode 169 rand_str = ''.join(random.choices(string.ascii_lowercase, k=4)) 170 cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rand_str) 171 output = u_boot_console.run_command(cmd) 172 assert exp_op in output 173 assert f'Unsupported mode' in output 174 assert not ret_code(u_boot_console).endswith('0') 175 176 # Switch to lockstep mode, without disabling CPUs 177 rpu_mode = 'lockstep' 178 u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode) 179 assert not ret_code(u_boot_console).endswith('0') 180 181 # Disable cpus 182 disable_cpus(u_boot_console, cpu_nums) 183 184 # Switch to lockstep mode, after disabling CPUs 185 output = u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode) 186 assert 'Initializing TCM overwrites TCM content' in output 187 assert ret_code(u_boot_console).endswith('0') 188 189 # Run lockstep mode for RPU1 190 for i in range(len(apps)): 191 if procs[i] == 'rpu0': 192 continue 193 194 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i]) 195 rel_addr = int(addrs[i] + 0x3C) 196 cpu_num = cpu_nums[i] 197 cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode) 198 output = u_boot_console.run_command(cmd) 199 exp_op = f'Using TCM jump trampoline for address {hex(rel_addr)}' 200 assert exp_op in output 201 assert f'R5 {rpu_mode} mode' in output 202 assert u_boot_console.p.expect([outputs[i]]) 203 finally: 204 disable_cpus(u_boot_console, cpu_nums) 205 # This forces the console object to be shutdown, so any subsequent test 206 # will reset the board back into U-Boot. 207 u_boot_console.drain_console() 208 u_boot_console.cleanup_spawn() 209