1 # SPDX-License-Identifier: GPL-2.0
2 # (C) Copyright 2023, Advanced Micro Devices, Inc.
10 Note: This test relies on boardenv_* containing configuration values to define
11 RPU applications information for AMD's ZynqMP SoC which contains, application
12 names, processors, address where it is built, expected output and the tftp load
13 addresses. This test will be automatically skipped without this.
15 It also relies on dhcp or setup_static net test to support tftp to load
16 application on DDR. All the environment parameters are stored sequentially.
17 The length of all parameters values should be same. For example, if 2 app_names
18 are defined in a list as a value of parameter 'app_name' then the other
19 parameters value also should have a list with 2 items.
20 It will run RPU cases for all the applications defined in boardenv_*
24 env__zynqmp_rpu_apps = {
25 'app_name': ['hello_world_r5_0_ddr.elf', 'hello_world_r5_1_ddr.elf'],
26 'proc': ['rpu0', 'rpu1'],
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],
35 # Get rpu apps params from env
36 def get_rpu_apps_env(u_boot_console):
37 rpu_apps = u_boot_console.config.env.get('env__zynqmp_rpu_apps', False)
39 pytest.skip('ZynqMP RPU application info not defined!')
41 apps = rpu_apps.get('app_name', None)
43 pytest.skip('No RPU application found!')
45 procs = rpu_apps.get('proc', None)
47 pytest.skip('No RPU application processor provided!')
49 cpu_nums = rpu_apps.get('cpu_num', None)
51 pytest.skip('No CPU number for respective processor provided!')
53 addrs = rpu_apps.get('addr', None)
55 pytest.skip('No RPU application build address found!')
57 outputs = rpu_apps.get('output', None)
59 pytest.skip('Expected output not found!')
61 tftp_addrs = rpu_apps.get('tftp_addr', None)
63 pytest.skip('TFTP address to load application not found!')
65 return apps, procs, cpu_nums, addrs, outputs, tftp_addrs
68 def ret_code(u_boot_console):
69 return u_boot_console.run_command('echo $?')
72 def tcminit(u_boot_console, rpu_mode):
73 output = u_boot_console.run_command(f'zynqmp tcminit {rpu_mode}')
74 assert 'Initializing TCM overwrites TCM content' in output
75 return ret_code(u_boot_console)
77 # Load application in DDR
78 def 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
84 u_boot_console.run_command('bootelf -p %x' % tftp_addr)
85 assert ret_code(u_boot_console).endswith('0')
88 def disable_cpus(u_boot_console, cpu_nums):
90 u_boot_console.run_command(f'cpu {num} disable')
92 # Get random RPU mode between string and integer
93 def get_rpu_mode(rpu_mode):
94 if rpu_mode == 0 or rpu_mode == 'lockstep':
95 return random.choice(['lockstep', 0])
96 elif rpu_mode == 1 or rpu_mode == 'split':
97 return random.choice(['split', 1])
99 # Load apps on RPU cores
100 def rpu_apps_load(u_boot_console, rpu_mode):
101 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
103 test_net.test_net_dhcp(u_boot_console)
104 if not test_net.net_set_up:
105 test_net.test_net_setup_static(u_boot_console)
108 assert tcminit(u_boot_console, get_rpu_mode(rpu_mode)).endswith('0')
110 for i in range(len(apps)):
111 if rpu_mode == 'lockstep' and procs[i] != 'rpu0':
114 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
115 rel_addr = hex(int(addrs[i] + 0x3C))
117 # Release cpu at app load address
118 cpu_num = cpu_nums[i]
119 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
120 output = u_boot_console.run_command(cmd)
121 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
122 assert exp_op in output
123 assert f'R5 {rpu_mode} mode' in output
124 u_boot_console.wait_for(outputs[i])
125 assert ret_code(u_boot_console).endswith('0')
127 disable_cpus(u_boot_console, cpu_nums)
129 @pytest.mark.buildconfigspec('cmd_zynqmp')
130 def test_zynqmp_rpu_app_load_split(u_boot_console):
131 rpu_apps_load(u_boot_console, 'split')
133 @pytest.mark.buildconfigspec('cmd_zynqmp')
134 def test_zynqmp_rpu_app_load_lockstep(u_boot_console):
135 rpu_apps_load(u_boot_console, 'lockstep')
137 @pytest.mark.buildconfigspec('cmd_zynqmp')
138 def test_zynqmp_rpu_app_load_negative(u_boot_console):
139 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
143 rand_str = ''.join(random.choices(string.ascii_lowercase, k=4))
144 rand_num = random.randint(2, 100)
145 inv_modes = ['mode', rand_str, rand_num, 'splittt', 'locksteppp', '00', 11]
147 for mode in inv_modes:
148 u_boot_console.run_command(f'zynqmp tcminit {mode}')
149 assert ret_code(u_boot_console).endswith('1')
151 test_net.test_net_dhcp(u_boot_console)
152 if not test_net.net_set_up:
153 test_net.test_net_setup_static(u_boot_console)
157 assert tcminit(u_boot_console, get_rpu_mode(rpu_mode)).endswith('0')
160 for i in range(len(apps)):
161 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
163 # Run in split mode at different load address
164 rel_addr = hex(int(addrs[i]) + random.randint(200, 1000))
165 cpu_num = cpu_nums[i]
166 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
167 output = u_boot_console.run_command(cmd)
168 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
169 assert exp_op in output
170 assert f'R5 {rpu_mode} mode' in output
171 assert not outputs[i] in output
174 for mode in inv_modes:
175 cmd = f'cpu {cpu_num} release {rel_addr} {mode}'
176 output = u_boot_console.run_command(cmd)
177 assert exp_op in output
178 assert f'Unsupported mode' in output
179 assert not ret_code(u_boot_console).endswith('0')
181 # Switch to lockstep mode, without disabling CPUs
182 rpu_mode = 'lockstep'
183 output = u_boot_console.run_command(
184 f'zynqmp tcminit {get_rpu_mode(rpu_mode)}'
186 assert 'ERROR: ' in output
189 disable_cpus(u_boot_console, cpu_nums)
191 # Switch to lockstep mode, after disabling CPUs
192 output = u_boot_console.run_command(
193 f'zynqmp tcminit {get_rpu_mode(rpu_mode)}'
195 assert 'Initializing TCM overwrites TCM content' in output
196 assert ret_code(u_boot_console).endswith('0')
198 # Run lockstep mode for RPU1/RPU0
199 for i in range(len(apps)):
200 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
201 rel_addr = hex(int(addrs[i] + 0x3C))
202 cpu_num = cpu_nums[i]
203 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
204 output = u_boot_console.run_command(cmd)
205 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
206 assert exp_op in output
208 if procs[i] == 'rpu1':
209 assert 'Lockstep mode should run on ZYNQMP_CORE_RPU0' in output
210 assert not ret_code(u_boot_console).endswith('0')
211 elif procs[i] == 'rpu0':
212 assert f'R5 {rpu_mode} mode' in output
213 u_boot_console.wait_for(outputs[i])
214 assert ret_code(u_boot_console).endswith('0')
216 assert False, 'ERROR: Invalid processor!'
218 disable_cpus(u_boot_console, cpu_nums)
219 # This forces the console object to be shutdown, so any subsequent test
220 # will reset the board back into U-Boot.
221 u_boot_console.drain_console()
222 u_boot_console.cleanup_spawn()