blob: 22f687dd6d399d3bb7c4f877d90583e86b516c73 [file] [log] [blame]
Love Kumard899e022024-01-19 11:06:41 +05301# 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):
Love Kumar0d458242024-11-15 17:32:02 +053073 output = u_boot_console.run_command(f'zynqmp tcminit {rpu_mode}')
Love Kumard899e022024-01-19 11:06:41 +053074 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
Love Kumar0d458242024-11-15 17:32:02 +053092# Get random RPU mode between string and integer
93def 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])
98
Love Kumard899e022024-01-19 11:06:41 +053099# Load apps on RPU cores
100def rpu_apps_load(u_boot_console, rpu_mode):
101 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
102 u_boot_console)
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)
106
107 try:
Love Kumar0d458242024-11-15 17:32:02 +0530108 assert tcminit(u_boot_console, get_rpu_mode(rpu_mode)).endswith('0')
Love Kumard899e022024-01-19 11:06:41 +0530109
110 for i in range(len(apps)):
111 if rpu_mode == 'lockstep' and procs[i] != 'rpu0':
112 continue
113
114 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
Love Kumar0d458242024-11-15 17:32:02 +0530115 rel_addr = hex(int(addrs[i] + 0x3C))
Love Kumard899e022024-01-19 11:06:41 +0530116
117 # Release cpu at app load address
118 cpu_num = cpu_nums[i]
Love Kumar0d458242024-11-15 17:32:02 +0530119 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
Love Kumard899e022024-01-19 11:06:41 +0530120 output = u_boot_console.run_command(cmd)
Love Kumar0d458242024-11-15 17:32:02 +0530121 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
Love Kumard899e022024-01-19 11:06:41 +0530122 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')
126 finally:
127 disable_cpus(u_boot_console, cpu_nums)
128
129@pytest.mark.buildconfigspec('cmd_zynqmp')
130def test_zynqmp_rpu_app_load_split(u_boot_console):
131 rpu_apps_load(u_boot_console, 'split')
132
133@pytest.mark.buildconfigspec('cmd_zynqmp')
134def test_zynqmp_rpu_app_load_lockstep(u_boot_console):
135 rpu_apps_load(u_boot_console, 'lockstep')
136
137@pytest.mark.buildconfigspec('cmd_zynqmp')
138def test_zynqmp_rpu_app_load_negative(u_boot_console):
139 apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
140 u_boot_console)
141
142 # Invalid commands
Love Kumard899e022024-01-19 11:06:41 +0530143 rand_str = ''.join(random.choices(string.ascii_lowercase, k=4))
Love Kumard899e022024-01-19 11:06:41 +0530144 rand_num = random.randint(2, 100)
Love Kumar0d458242024-11-15 17:32:02 +0530145 inv_modes = ['mode', rand_str, rand_num, 'splittt', 'locksteppp', '00', 11]
146
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')
Love Kumard899e022024-01-19 11:06:41 +0530150
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)
154
155 try:
156 rpu_mode = 'split'
Love Kumar0d458242024-11-15 17:32:02 +0530157 assert tcminit(u_boot_console, get_rpu_mode(rpu_mode)).endswith('0')
Love Kumard899e022024-01-19 11:06:41 +0530158
Love Kumar0d458242024-11-15 17:32:02 +0530159 inv_modes += [0, 1]
Love Kumard899e022024-01-19 11:06:41 +0530160 for i in range(len(apps)):
161 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
162
163 # Run in split mode at different load address
Love Kumar0d458242024-11-15 17:32:02 +0530164 rel_addr = hex(int(addrs[i]) + random.randint(200, 1000))
Love Kumard899e022024-01-19 11:06:41 +0530165 cpu_num = cpu_nums[i]
Love Kumar0d458242024-11-15 17:32:02 +0530166 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
Love Kumard899e022024-01-19 11:06:41 +0530167 output = u_boot_console.run_command(cmd)
Love Kumar0d458242024-11-15 17:32:02 +0530168 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
Love Kumard899e022024-01-19 11:06:41 +0530169 assert exp_op in output
170 assert f'R5 {rpu_mode} mode' in output
171 assert not outputs[i] in output
172
173 # Invalid rpu mode
Love Kumar0d458242024-11-15 17:32:02 +0530174 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')
Love Kumard899e022024-01-19 11:06:41 +0530180
181 # Switch to lockstep mode, without disabling CPUs
182 rpu_mode = 'lockstep'
Love Kumar0d458242024-11-15 17:32:02 +0530183 output = u_boot_console.run_command(
184 f'zynqmp tcminit {get_rpu_mode(rpu_mode)}'
185 )
186 assert 'ERROR: ' in output
Love Kumard899e022024-01-19 11:06:41 +0530187
188 # Disable cpus
189 disable_cpus(u_boot_console, cpu_nums)
190
191 # Switch to lockstep mode, after disabling CPUs
Love Kumar0d458242024-11-15 17:32:02 +0530192 output = u_boot_console.run_command(
193 f'zynqmp tcminit {get_rpu_mode(rpu_mode)}'
194 )
Love Kumard899e022024-01-19 11:06:41 +0530195 assert 'Initializing TCM overwrites TCM content' in output
196 assert ret_code(u_boot_console).endswith('0')
197
Love Kumar0d458242024-11-15 17:32:02 +0530198 # Run lockstep mode for RPU1/RPU0
Love Kumard899e022024-01-19 11:06:41 +0530199 for i in range(len(apps)):
Love Kumard899e022024-01-19 11:06:41 +0530200 load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
Love Kumar0d458242024-11-15 17:32:02 +0530201 rel_addr = hex(int(addrs[i] + 0x3C))
Love Kumard899e022024-01-19 11:06:41 +0530202 cpu_num = cpu_nums[i]
Love Kumar0d458242024-11-15 17:32:02 +0530203 cmd = f'cpu {cpu_num} release {rel_addr} {rpu_mode}'
Love Kumard899e022024-01-19 11:06:41 +0530204 output = u_boot_console.run_command(cmd)
Love Kumar0d458242024-11-15 17:32:02 +0530205 exp_op = f'Using TCM jump trampoline for address {rel_addr}'
Love Kumard899e022024-01-19 11:06:41 +0530206 assert exp_op in output
Love Kumar0d458242024-11-15 17:32:02 +0530207
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')
215 else:
216 assert False, 'ERROR: Invalid processor!'
Love Kumard899e022024-01-19 11:06:41 +0530217 finally:
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()