[PATCH v2] test/py: spi: Set the expected error message

2024-09-02 Thread Love Kumar
If erase/write/read size is 0 then it throws the mentioned error message
when debug message ie enabled as per 899fb5aa8bec ("cmd: sf/nand: Print
and return failure when 0 length is passed"), setting it to None as
debug message is not enabled by default for testing.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Updated commit message
---
 test/py/tests/test_spi.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/py/tests/test_spi.py b/test/py/tests/test_spi.py
index c81eca5fba6e..3160d58540f2 100644
--- a/test/py/tests/test_spi.py
+++ b/test/py/tests/test_spi.py
@@ -646,7 +646,7 @@ def test_spi_negative(u_boot_console):
 
 # If erase size is 0
 esize = 0
-error_msg = 'ERROR: Invalid size 0'
+error_msg = None
 flash_ops(
 u_boot_console, 'erase', start, esize, 0, 1, error_msg, 
EXPECTED_ERASE
 )
@@ -685,7 +685,7 @@ def test_spi_negative(u_boot_console):
 # if Write/Read size is 0
 offset = random.randint(0, 2)
 size = 0
-error_msg = 'ERROR: Invalid size 0'
+error_msg = None
 flash_ops(
 u_boot_console, 'write', offset, size, addr, 1, error_msg, 
EXPECTED_WRITE
 )
-- 
2.25.1



[PATCH] test/py: spi: Set the expected error message

2024-08-29 Thread Love Kumar
If erase/write/read size is 0 then it throws the mentioned error message
when debug message ie enabled as per "899fb5aa8becc159b1eb086d8828c4e8eb28f121"
, setting it to None as debug message is not enabled by default for
testing.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_spi.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/py/tests/test_spi.py b/test/py/tests/test_spi.py
index c81eca5fba6e..3160d58540f2 100644
--- a/test/py/tests/test_spi.py
+++ b/test/py/tests/test_spi.py
@@ -646,7 +646,7 @@ def test_spi_negative(u_boot_console):
 
 # If erase size is 0
 esize = 0
-error_msg = 'ERROR: Invalid size 0'
+error_msg = None
 flash_ops(
 u_boot_console, 'erase', start, esize, 0, 1, error_msg, 
EXPECTED_ERASE
 )
@@ -685,7 +685,7 @@ def test_spi_negative(u_boot_console):
 # if Write/Read size is 0
 offset = random.randint(0, 2)
 size = 0
-error_msg = 'ERROR: Invalid size 0'
+error_msg = None
 flash_ops(
 u_boot_console, 'write', offset, size, addr, 1, error_msg, 
EXPECTED_WRITE
 )
-- 
2.25.1



Re: [PATCH] test/py/tests/test_bootstage.py: Combine stash/unstash tests

2024-08-28 Thread Love Kumar




On 29/08/24 4:26 am, Tom Rini wrote:

When running the bootstage tests currently we get a warning like:
tests/test_bootstage.py::test_bootstage_stash
...PytestReturnNotNoneWarning: Expected None, but 
tests/test_bootstage.py::test_bootstage_stash returned (37748736, 4096), which 
will be an error in a future version of pytest.  Did you mean to use `assert` 
in stead of `return`?

This is because the unstash test will run the stash test and fetch the
addr / size from that. Rework the test to be stash and unstash and then
run the unstash command at the end of the current stash test.

Signed-off-by: Tom Rini 
---
It's possible we could solve this instead by getting addr / size again
from our environment file, and then also noting that order-wise the
unstash test follows the stash test. However, this felt more clean to
me.


Agree with this approach.

Reviewed-by: Love Kumar 

Regards,
Love Kumar


[PATCH] versal2: Update the sys prompt name

2024-08-08 Thread Love Kumar
versal2 refers as "Versal Gen 2" as a generic approved name so using
the same as u-boot prompt name for all versal2 defconfig

Signed-off-by: Love Kumar 
---
 configs/amd_versal2_mini_defconfig  | 2 +-
 configs/amd_versal2_mini_emmc_defconfig | 2 +-
 configs/amd_versal2_mini_ospi_defconfig | 2 +-
 configs/amd_versal2_mini_qspi_defconfig | 2 +-
 configs/amd_versal2_virt_defconfig  | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/configs/amd_versal2_mini_defconfig 
b/configs/amd_versal2_mini_defconfig
index 0dd2305bfb2d..2af9ff4d8377 100644
--- a/configs/amd_versal2_mini_defconfig
+++ b/configs/amd_versal2_mini_defconfig
@@ -32,7 +32,7 @@ CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
 # CONFIG_SYS_LONGHELP is not set
-CONFIG_SYS_PROMPT="versal2> "
+CONFIG_SYS_PROMPT="VersalGen2> "
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_BOOTI is not set
diff --git a/configs/amd_versal2_mini_emmc_defconfig 
b/configs/amd_versal2_mini_emmc_defconfig
index 7ad44386a6da..520dabbf7c8b 100644
--- a/configs/amd_versal2_mini_emmc_defconfig
+++ b/configs/amd_versal2_mini_emmc_defconfig
@@ -24,7 +24,7 @@ CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
 # CONFIG_SYS_LONGHELP is not set
-CONFIG_SYS_PROMPT="versal2> "
+CONFIG_SYS_PROMPT="VersalGen2> "
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
diff --git a/configs/amd_versal2_mini_ospi_defconfig 
b/configs/amd_versal2_mini_ospi_defconfig
index 2242960392f5..9498f4ba46c4 100644
--- a/configs/amd_versal2_mini_ospi_defconfig
+++ b/configs/amd_versal2_mini_ospi_defconfig
@@ -30,7 +30,7 @@ CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
 # CONFIG_SYS_LONGHELP is not set
-CONFIG_SYS_PROMPT="versal2> "
+CONFIG_SYS_PROMPT="VersalGen2> "
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_BOOTI is not set
diff --git a/configs/amd_versal2_mini_qspi_defconfig 
b/configs/amd_versal2_mini_qspi_defconfig
index 3360c1546a20..6aa2223df2fe 100644
--- a/configs/amd_versal2_mini_qspi_defconfig
+++ b/configs/amd_versal2_mini_qspi_defconfig
@@ -30,7 +30,7 @@ CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
 # CONFIG_SYS_LONGHELP is not set
-CONFIG_SYS_PROMPT="versal2> "
+CONFIG_SYS_PROMPT="VersalGen2> "
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_BOOTI is not set
diff --git a/configs/amd_versal2_virt_defconfig 
b/configs/amd_versal2_virt_defconfig
index c4bf77186cd5..1ab916451b54 100644
--- a/configs/amd_versal2_virt_defconfig
+++ b/configs/amd_versal2_virt_defconfig
@@ -26,7 +26,7 @@ CONFIG_USE_PREBOOT=y
 CONFIG_SYS_PBSIZE=2073
 CONFIG_BOARD_EARLY_INIT_R=y
 CONFIG_CLOCKS=y
-CONFIG_SYS_PROMPT="versal2> "
+CONFIG_SYS_PROMPT="VersalGen2> "
 CONFIG_CMD_BOOTMENU=y
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_NVEDIT_EFI=y
-- 
2.23.0



[PATCH v3] test/py: spi: Add tests for SPI flash device

2024-07-31 Thread Love Kumar
Add test cases for sf commands to verify various SPI flash operations
such as erase, write and read. It also adds qspi lock unlock cases.
This test relies on boardenv_* configurations to run it for different
SPI flash family such as single SPI, QSPI, and OSPI.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Fix the pylint errors
 - Re-order/organize the tests
Changes in v3:
 - Spelling correction
 - Describe the boardenv params
---
 test/py/tests/test_spi.py | 696 ++
 1 file changed, 696 insertions(+)
 create mode 100644 test/py/tests/test_spi.py

diff --git a/test/py/tests/test_spi.py b/test/py/tests/test_spi.py
new file mode 100644
index ..c81eca5fba6e
--- /dev/null
+++ b/test/py/tests/test_spi.py
@@ -0,0 +1,696 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2024, Advanced Micro Devices, Inc.
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+spi minimum and maximum frequencies at which the flash part can operate on and
+these tests run at different spi frequency randomised values in the range
+multiple times based on the user defined iteration value.
+It also defines the SPI bus number containing the SPI-flash chip, SPI
+chip-select, SPI mode, SPI flash part name and timeout parameters. If minimum
+and maximum frequency is not defined, it will run on freq 0 by default.
+
+Without the boardenv_* configuration, this test will be automatically skipped.
+
+It also relies on configuration values for supported flashes for lock and
+unlock cases for SPI family flash. It will run lock-unlock cases only for the
+supported flash parts.
+
+For Example:
+
+# Details of SPI device test parameters required for SPI device testing:
+
+# bus - SPI bus number to init the flash device
+# chip_select - SPI chip select number to init the flash device
+# min_freq - Minimum frequency in hz at which the flash part can operate, set 0
+# or None for default frequency
+# max_freq - Maximum frequency in hz at which the flash part can operate, set 0
+# or None for default frequency
+# mode - SPI mode to init the flash device
+# part_name - SPI flash part name to be detected
+# timeout - Default timeout to run the sf commands
+# iteration - No of iteration to run SPI flash test
+
+env__spi_device_test = {
+'bus': 0,
+'chip_select': 0,
+'min_freq': 1000,
+'max_freq': 1,
+'mode': 0,
+'part_name': 'n25q00a',
+'timeout': 10,
+'iteration': 5,
+}
+
+# supported_flash - Flash parts name which support lock-unlock functionality
+env__spi_lock_unlock = {
+'supported_flash': 'mt25qu512a, n25q00a, n25q512ax3',
+}
+"""
+
+import random
+import re
+import pytest
+import u_boot_utils
+
+SPI_DATA = {}
+EXPECTED_ERASE = 'Erased: OK'
+EXPECTED_WRITE = 'Written: OK'
+EXPECTED_READ = 'Read: OK'
+EXPECTED_ERASE_ERRORS = [
+'Erase operation failed',
+'Attempted to modify a protected sector',
+'Erased: ERROR',
+'is protected and cannot be erased',
+'ERROR: flash area is locked',
+]
+EXPECTED_WRITE_ERRORS = [
+'ERROR: flash area is locked',
+'Program operation failed',
+'Attempted to modify a protected sector',
+'Written: ERROR',
+]
+
+def get_params_spi(u_boot_console):
+''' Get SPI device test parameters from boardenv file '''
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+bus = f.get('bus', 0)
+cs = f.get('chip_select', 0)
+mode = f.get('mode', 0)
+part_name = f.get('part_name', None)
+timeout = f.get('timeout', None)
+
+if not part_name:
+pytest.skip('No env file to read SPI family flash part name')
+
+return bus, cs, mode, part_name, timeout
+
+def spi_find_freq_range(u_boot_console):
+'''Find out minimum and maximum frequnecies that SPI device can operate'''
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+min_f = f.get('min_freq', None)
+max_f = f.get('max_freq', None)
+iterations = f.get('iteration', 1)
+
+if not min_f:
+min_f = 0
+if not max_f:
+max_f = 0
+
+max_f = max(max_f, min_f)
+
+return min_f, max_f, iterations
+
+def spi_pre_commands(u_boot_console, freq):
+''' Find out SPI family flash memory parameters '''
+bus, cs, mode, part_name, timeout = get_params_spi(u_boot_con

[PATCH v2] test/py: spi: Add tests for SPI flash device

2024-07-24 Thread Love Kumar
Add test cases for sf commands to verify various SPI flash operations
such as erase, write and read. It also adds qspi lock unlock cases.
This test relies on boardenv_* configurations to run it for different
SPI flash family such as single SPI, QSPI, and OSPI.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Fix the pylint errors
 - Re-order/organize the tests
---
 test/py/tests/test_spi.py | 680 ++
 1 file changed, 680 insertions(+)
 create mode 100644 test/py/tests/test_spi.py

diff --git a/test/py/tests/test_spi.py b/test/py/tests/test_spi.py
new file mode 100644
index ..4774b4151b4e
--- /dev/null
+++ b/test/py/tests/test_spi.py
@@ -0,0 +1,680 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2024, Advanced Micro Devices, Inc.
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+spi minimum and maximum frequnecies at which the flash part can operate on and
+these tests run at 5 different spi frequnecy randomised values in the range.
+It also defines the SPI bus number containing the SPI-flash chip, SPI
+chip-select, SPI mode, SPI flash part name and timeout parameters. If minimum
+and maximum frequency is not defined, it will run on freq 0 by default.
+
+Without the boardenv_* configuration, this test will be automatically skipped.
+
+It also relies on configuration values for supported flashes for lock and
+unlock cases for SPI family flash. It will run lock-unlock cases only for the
+supported flash parts.
+
+Example:
+env__spi_device_test = {
+'bus': 0,
+'chip_select': 0,
+'min_freq': 1000,
+'max_freq': 1,
+'mode': 0,
+'part_name': 'n25q00a',
+'timeout': 10,
+'iteration': 5,
+}
+
+env__spi_lock_unlock = {
+'supported_flash': 'mt25qu512a, n25q00a, n25q512ax3',
+}
+"""
+
+import random
+import re
+import pytest
+import u_boot_utils
+
+SPI_DATA = {}
+EXPECTED_ERASE = 'Erased: OK'
+EXPECTED_WRITE = 'Written: OK'
+EXPECTED_READ = 'Read: OK'
+EXPECTED_ERASE_ERRORS = [
+'Erase operation failed',
+'Attempted to modify a protected sector',
+'Erased: ERROR',
+'is protected and cannot be erased',
+'ERROR: flash area is locked',
+]
+EXPECTED_WRITE_ERRORS = [
+'ERROR: flash area is locked',
+'Program operation failed',
+'Attempted to modify a protected sector',
+'Written: ERROR',
+]
+
+def get_params_spi(u_boot_console):
+''' Get SPI device test parameters from boardenv file '''
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+bus = f.get('bus', 0)
+cs = f.get('chip_select', 0)
+mode = f.get('mode', 0)
+part_name = f.get('part_name', None)
+timeout = f.get('timeout', None)
+
+if not part_name:
+pytest.skip('No env file to read SPI family flash part name')
+
+return bus, cs, mode, part_name, timeout
+
+def spi_find_freq_range(u_boot_console):
+'''Find out minimum and maximum frequnecies that SPI device can operate'''
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+min_f = f.get('min_freq', None)
+max_f = f.get('max_freq', None)
+iterations = f.get('iteration', 1)
+
+if not min_f:
+min_f = 0
+if not max_f:
+max_f = 0
+
+max_f = max(max_f, min_f)
+
+return min_f, max_f, iterations
+
+def spi_pre_commands(u_boot_console, freq):
+''' Find out SPI family flash memory parameters '''
+bus, cs, mode, part_name, timeout = get_params_spi(u_boot_console)
+
+output = u_boot_console.run_command(f'sf probe {bus}:{cs} {freq} {mode}')
+if not 'SF: Detected' in output:
+pytest.fail('No SPI device available')
+
+if not part_name in output:
+pytest.fail('SPI flash part name not recognized')
+
+m = re.search('page size (.+?) Bytes', output)
+if m:
+try:
+page_size = int(m.group(1))
+except ValueError:
+pytest.fail('SPI page size not recognized')
+
+m = re.search('erase size (.+?) KiB', output)
+if m:
+try:
+erase_size = int(m.group(1))
+except ValueError:
+pytest.fail('SPI erase size not recognized')
+
+erase_size *= 1024
+
+m = re.search('to

[PATCH v7] test/py: net_boot: Add test cases for net boot

2024-06-05 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
  - Expand commit message
Changes in v3:
  - Add the config option to skip the test
  - Remove imi command to check FIT image config
  - Configure static networking only if DHCP fails
Changes in v4:
  - Use configured timeout for tftpboot
Changes in v5:
  - Add pre-req for boot test to enable error check
  - Merged boot and boot config test
Changes in v6:
  - Use common setup_networking function for tftp and pxe cases
  - Check for bootfile env variable for pxe config name
Changes in v7:
  - Set pxefile_addr_r env variable to use the same address for loading
  and running pxe config
---
 test/py/tests/test_net_boot.py | 403 +
 1 file changed, 403 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..4729ccf07feb
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,403 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+import re
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a TFTP boot test should be tested.
+# If TFTP boot testing is not possible or desired, set this variable to True.
+# For example: If FIT image is not proper to boot
+env__tftp_boot_test_skip = False
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a PXE boot test should be tested.
+# If PXE boot testing is not possible or desired, set this variable to True.
+# For example: If pxe configuration file is not proper to boot
+env__pxe_boot_test_skip = False
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+

[PATCH v6] test/py: net_boot: Add test cases for net boot

2024-06-03 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
  - Expand commit message
Changes in v3:
  - Add the config option to skip the test
  - Remove imi command to check FIT image config
  - Configure static networking only if DHCP fails
Changes in v4:
  - Use configured timeout for tftpboot
Changes in v5:
  - Add pre-req for boot test to enable error check
  - Merged boot and boot config test
Changes in v6:
  - Use common setup_networking function for tftp and pxe cases
  - Check for bootfile env variable for pxe config name
---
 test/py/tests/test_net_boot.py | 394 +
 1 file changed, 394 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..41591b192830
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,394 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+import re
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a TFTP boot test should be tested.
+# If TFTP boot testing is not possible or desired, set this variable to True.
+# For example: If FIT image is not proper to boot
+env__tftp_boot_test_skip = False
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a PXE boot test should be tested.
+# If PXE boot testing is not possible or desired, set this variable to True.
+# For example: If pxe configuration file is not proper to boot
+env__pxe_boot_test_skip = False
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlypri

Re: [PATCH v2 12/14] test/py: net: add _lwip variants of dhcp, ping and tftpboot tests

2024-05-28 Thread Love Kumar




On 24/05/24 9:50 pm, Jerome Forissier wrote:

WHen NET_LWIP is enabled, the dhcp/ping/tftpboot commands are enabled
via CMD_DHCP_LWIP, CMD_PING_LWIP and CMD_TFTPBOOT_LWIP, respectively;
therefore the config annotations in the Python test scripts need to be
cmd_dhcp_lwip, cmd_ping_lwip and cmd_tftpboot_lwip.

The console output of the tftpboot command with lwIP is slightly
different from the non-lwIP implementation. This is taken care of in
test_net_tftpboot().

Signed-off-by: Jerome Forissier 
---
  test/py/tests/test_net.py | 21 +
  1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index 038a473b239..ba30780903f 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -127,6 +127,10 @@ def test_net_dhcp(u_boot_console):
  global net_set_up
  net_set_up = True
  
+@pytest.mark.buildconfigspec('cmd_dhcp_lwip')

+def test_net_dhcp_lwip(u_boot_console):
+test_net_dhcp(u_boot_console)
+
  @pytest.mark.buildconfigspec('cmd_dhcp')
  @pytest.mark.buildconfigspec('cmd_mii')
  def test_net_dhcp_abort(u_boot_console):
@@ -230,6 +234,10 @@ def test_net_ping(u_boot_console):
  output = u_boot_console.run_command('ping $serverip')
  assert 'is alive' in output
  
+@pytest.mark.buildconfigspec('cmd_ping_lwip')

+def test_net_ping_lwip(u_boot_console):
+test_net_ping(u_boot_console)
+
  @pytest.mark.buildconfigspec('IPV6_ROUTER_DISCOVERY')
  def test_net_network_discovery(u_boot_console):
  """Test the network discovery feature of IPv6.
@@ -255,7 +263,7 @@ def test_net_network_discovery(u_boot_console):
  assert ':::::::' not in output
  
  @pytest.mark.buildconfigspec('cmd_net')

-def test_net_tftpboot(u_boot_console):
+def test_net_tftpboot(u_boot_console, lwip = False):
  """Test the tftpboot command.
  
  A file is downloaded from the TFTP server, its size and optionally its

@@ -279,10 +287,11 @@ def test_net_tftpboot(u_boot_console):
  output = u_boot_console.run_command('tftpboot %s' % (fn))
  else:
  output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
-expected_text = 'Bytes transferred = '
  sz = f.get('size', None)
-if sz:
-expected_text += '%d' % sz
+if lwip:
+expected_text = f'{sz} bytes transferred'
+else:
+expected_text = f'Bytes transferred = {sz}'
  assert expected_text in output
  
  expected_crc = f.get('crc32', None)

@@ -295,6 +304,10 @@ def test_net_tftpboot(u_boot_console):
  output = u_boot_console.run_command('crc32 $fileaddr $filesize')
  assert expected_crc in output
  
+@pytest.mark.buildconfigspec("cmd_net_lwip")

+def test_net_tftpboot_lwip(u_boot_console):
+test_net_tftpboot(u_boot_console, True)
+
  @pytest.mark.buildconfigspec('cmd_nfs')
  def test_net_nfs(u_boot_console):
  """Test the nfs command.


Reviewed-by: Love Kumar 


[PATCH v5] test/py: net_boot: Add test cases for net boot

2024-05-28 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
  - Expand commit message
Changes in v3:
  - Add the config option to skip the test
  - Remove imi command to check FIT image config
  - Configure static networking only if DHCP fails
Changes in v4:
  - Use configured timeout for tftpboot
Changes in v5:
  - Add pre-req for boot test to enable error check
  - Merged boot and boot config test
---
 test/py/tests/test_net_boot.py | 389 +
 1 file changed, 389 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..e5e8ec688df1
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,389 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+import re
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a TFTP boot test should be tested.
+# If TFTP boot testing is not possible or desired, set this variable to True.
+# For example: If FIT image is not proper to boot
+env__tftp_boot_test_skip = False
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+'check_type': 'boot_error',
+'check_pattern': 'ERROR',
+}
+
+# False or omitted if a PXE boot test should be tested.
+# If PXE boot testing is not possible or desired, set this variable to True.
+# For example: If pxe configuration file is not proper to boot
+env__pxe_boot_test_skip = False
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlyprintk
+initrd initrds/uzInitrdDebInstall
+
+label local
+menu label Local boot
+append root=/dev/sdb1
+local

[PATCH] test/py: Add support to enable check for bad pattern

2024-05-22 Thread Love Kumar
Executing a u-boot command may raise an error or extra bad pattern,
beyond the default bad patterns. Providing a way to enable the console
output error check in test.

For example, description for OS boot test:
import re
check_type = 'kernel_boot_error'
check_pattern = re.compile('ERROR -2: can't get kernel image!')
with u_boot_console.enable_check(check_type, check_pattern):
u_boot_console.run_command('')

Signed-off-by: Love Kumar 
---
 test/py/u_boot_console_base.py | 44 ++
 1 file changed, 44 insertions(+)

diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py
index 26b6de07f88f..2f882fb53fc5 100644
--- a/test/py/u_boot_console_base.py
+++ b/test/py/u_boot_console_base.py
@@ -57,6 +57,32 @@ class ConsoleDisableCheck(object):
 self.console.disable_check_count[self.check_type] -= 1
 self.console.eval_bad_patterns()
 
+class ConsoleEnableCheck(object):
+"""Context manager (for Python's with statement) that temporarily enables
+the specified console output error check. This is useful when executing a
+command that might raise an extra bad pattern, beyond the default bad
+patterns, in order to validate that the extra bad pattern is actually
+detected. This class is used internally by ConsoleBase::enable_check(); it
+is not intended for direct usage."""
+
+def __init__(self, console, check_type, check_pattern):
+self.console = console
+self.check_type = check_type
+self.check_pattern = check_pattern
+
+def __enter__(self):
+global bad_pattern_defs
+self.default_bad_patterns = bad_pattern_defs
+bad_pattern_defs += ((self.check_type, self.check_pattern),)
+self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in 
bad_pattern_defs}
+self.console.eval_bad_patterns()
+
+def __exit__(self, extype, value, traceback):
+global bad_pattern_defs
+bad_pattern_defs = self.default_bad_patterns
+self.console.disable_check_count = {pat[PAT_ID]: 0 for pat in 
bad_pattern_defs}
+self.console.eval_bad_patterns()
+
 class ConsoleSetupTimeout(object):
 """Context manager (for Python's with statement) that temporarily sets up
 timeout for specific command. This is useful when execution time is greater
@@ -499,6 +525,24 @@ class ConsoleBase(object):
 
 return ConsoleDisableCheck(self, check_type)
 
+def enable_check(self, check_type, check_pattern):
+"""Temporarily enable an error check of U-Boot's output.
+
+Create a new context manager (for use with the "with" statement) which
+temporarily enables a particular console output error check. The
+arguments form a new element of bad_pattern_defs defined above.
+
+Args:
+check_type: The type of error-check or bad pattern to enable.
+check_pattern: The regexes for text error pattern or bad pattern
+to be checked.
+
+Returns:
+A context manager object.
+"""
+
+return ConsoleEnableCheck(self, check_type, check_pattern)
+
 def temporary_timeout(self, timeout):
 """Temporarily set up different timeout for commands.
 
-- 
2.25.1



Re: [PATCH v4] test/py: net_boot: Add test cases for net boot

2024-05-06 Thread Love Kumar




On 04/05/24 1:48 am, Tom Rini wrote:

On Fri, May 03, 2024 at 05:39:46PM +0530, Love Kumar wrote:


Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 


I'm not quite sure where the problem is, next. After enabling FIT image
support in my build so I can use the image I have on hand:
U-Boot> tftpboot 20 v6.6/image.fit.nocomp
Waiting for Ethernet connection... done.
Using smsc95xx_eth device
TFTP from server 192.168.1.10; our IP address is 192.168.1.100
Filename 'v6.6/image.fit.nocomp'.
Load address: 0x20
Loading: ##  82 MiB
  3.2 MiB/s
done
Bytes transferred = 85984256 (5200400 hex)
U-Boot> U-Boot> crc32 20 $filesize
CRC32 for 0020 ... 054003ff ==> 754c839a
U-Boot> U-Boot> bootm 20
## Loading kernel from FIT Image at 0020 ...
Could not find configuration node
ERROR -2: can't get kernel image!
U-Boot>

And in u_boot_boardenv_rpi_arm64.py:
env__tftp_boot_test_skip = False

env__net_tftp_bootable_file = {
 'fn': 'v6.6/image.fit.nocomp',
 'addr': 0x0020,
 'size': 85984256,
 'crc32': '754c839a',
 'pattern': 'Linux',
 'config': 'conf-852',
}

But it's not trying to boot conf-852 but instead just passing the
address. This image lacks a default config, which your example has and I
think is why the tests work in your case.



Hi,

Yes, this case expects to have some default config in fit image as it 
uses 'bootm ' command to boot, below change in fit image should work.


configurations {
default = "conf-852";

test_net_tftpboot_boot_config - This case will boot from the given 
config: 'bootm 20#conf-852'


Regards,
Love Kumar


[PATCH v4] test/py: net_boot: Add test cases for net boot

2024-05-03 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Expand commit message
Changes in v3:
 - Add the config option to skip the test
 - Remove imi command to check FIT image config
 - Configure static networking only if DHCP fails
Changes in v4:
 - Use configured timeout for tftpboot
---
 test/py/tests/test_net_boot.py | 394 +
 1 file changed, 394 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..fb0fb7e80414
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,394 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+}
+
+# False or omitted if a TFTP boot test should be tested.
+# If TFTP boot testing is not possible or desired, set this variable to True.
+# For example: If FIT image is not proper to boot
+env__tftp_boot_test_skip = False
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+}
+
+# False or omitted if a PXE boot test should be tested.
+# If PXE boot testing is not possible or desired, set this variable to True.
+# For example: If pxe configuration file is not proper to boot
+env__pxe_boot_test_skip = False
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlyprintk
+initrd initrds/uzInitrdDebInstall
+
+label local
+menu label Local boot
+append root=/dev/sdb1
+localboot 1
+
+label boot
+menu label Empty boot
+
+3) /tftpboot/pxelinux.cfg/default
+
+label Linux
+menu label Boot kernel
+kernel Image
+fdt system.dtb
+initrd rootfs.cpio.gz.u-boot
+"""
+
+def setup_tftpboot_boot(u_boot_console):
+f = u_boot_console.config

[PATCH v3] test/py: net_boot: Add test cases for net boot

2024-04-30 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Expand commit message
Changes in v3:
 - Add the config option to skip the test
 - Remove imi command to check FIT image config
 - Configure static networking only if DHCP fails
---
 test/py/tests/test_net_boot.py | 391 +
 1 file changed, 391 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..cf7d5cca5cbd
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,391 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+}
+
+# False or omitted if a TFTP boot test should be tested.
+# If TFTP boot testing is not possible or desired, set this variable to True.
+# For example: If FIT image is not proper to boot
+env__tftp_boot_test_skip = False
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+}
+
+# False or omitted if a PXE boot test should be tested.
+# If PXE boot testing is not possible or desired, set this variable to True.
+# For example: If pxe configuration file is not proper to boot
+env__pxe_boot_test_skip = False
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlyprintk
+initrd initrds/uzInitrdDebInstall
+
+label local
+menu label Local boot
+append root=/dev/sdb1
+localboot 1
+
+label boot
+menu label Empty boot
+
+3) /tftpboot/pxelinux.cfg/default
+
+label Linux
+menu label Boot kernel
+kernel Image
+fdt system.dtb
+initrd rootfs.cpio.gz.u-boot
+"""
+
+def setup_tftpboot_boot(u_boot_console):
+f = u_boot_console.config.env.get('env__net_tftp_bootable_file'

Re: [PATCH 2/5] mmc: zynq-sdhci: refactor tapdelay settings

2024-03-13 Thread Love Kumar

Hi,

When we run in el3 for zynqmp board, we are seeing below issue with this 
patch:



Model: ZynqMP MINI EMMC0
Board: Xilinx ZynqMP
DRAM:  512 MiB
EL Level:  EL3
Secure Boot:   not authenticated, not encrypted
Multiboot: 0
Core:  10 devices, 9 uclasses, devicetree: embed
MMC:   sdhci@ff16: 0
Loading Environment from ... OK
In:dcc
Out:   dcc
Err:   dcc
ZynqMP> mmc list
sdhci@ff16: 0
ZynqMP> mmc dev 0 0
arasan_sdhci sdhci@ff16: Error setting Input Tap Delay
sdhci_set_clock: Error while setting tap delay
sdhci_send_command: Timeout for status update:  0001
ZynqMP>

Regards,
Love Kumar

On 23/02/24 7:36 pm, Steffen Dirkwinkel wrote:

From: Steffen Dirkwinkel 

Previously we were setting in tapdelay for SD1 every time even if SD0 was
requested.
The SD tapdelay settings are shifted by 16 bits between SD0 and SD1.
We can use that to make our tapdelay setup simpler. This is also how it
currently works in arm-trusted-firmware.

Signed-off-by: Steffen Dirkwinkel 
---

  drivers/mmc/zynq_sdhci.c | 65 +---
  1 file changed, 28 insertions(+), 37 deletions(-)

diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index 935540d1719..d4845245b2a 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -42,14 +42,11 @@
  #define SD_OTAP_DLY   0xFF180318
  #define SD0_DLL_RST   BIT(2)
  #define SD1_DLL_RST   BIT(18)
+#define SD1_TAP_OFFSET 16
  #define SD0_ITAPCHGWINBIT(9)
-#define SD1_ITAPCHGWIN BIT(25)
  #define SD0_ITAPDLYENABIT(8)
-#define SD1_ITAPDLYENA BIT(24)
  #define SD0_ITAPDLYSEL_MASK   GENMASK(7, 0)
-#define SD1_ITAPDLYSEL_MASKGENMASK(23, 16)
  #define SD0_OTAPDLYSEL_MASK   GENMASK(5, 0)
-#define SD1_OTAPDLYSEL_MASKGENMASK(21, 16)
  
  #define MIN_PHY_CLK_HZ			5000
  
@@ -275,44 +272,32 @@ static int arasan_sdhci_config_dll(struct sdhci_host *host, unsigned int clock,

  static inline int arasan_zynqmp_set_in_tapdelay(u32 node_id, u32 itap_delay)
  {
int ret;
+   u32 shift;
  
-	if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {

-   if (node_id == NODE_SD_0) {
-   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN,
-   SD0_ITAPCHGWIN);
-   if (ret)
-   return ret;
-
-   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA,
-   SD0_ITAPDLYENA);
-   if (ret)
-   return ret;
-
-   ret = zynqmp_mmio_write(SD_ITAP_DLY, 
SD0_ITAPDLYSEL_MASK,
-   itap_delay);
-   if (ret)
-   return ret;
+   if (node_id == NODE_SD_0)
+   shift = 0;
+   else if (node_id == NODE_SD_1)
+   shift = SD1_TAP_OFFSET;
+   else
+   return -EINVAL;
  
-			ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, 0);

-   if (ret)
-   return ret;
-   }
-   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN,
-   SD1_ITAPCHGWIN);
+   if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
+   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN << shift,
+   SD0_ITAPCHGWIN << shift);
if (ret)
return ret;
  
-		ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYENA,

-   SD1_ITAPDLYENA);
+   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYENA << shift,
+   SD0_ITAPDLYENA << shift);
if (ret)
return ret;
  
-		ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPDLYSEL_MASK,

-   (itap_delay << 16));
+   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPDLYSEL_MASK << 
shift,
+   itap_delay << shift);
if (ret)
return ret;
  
-		ret = zynqmp_mmio_write(SD_ITAP_DLY, SD1_ITAPCHGWIN, 0);

+   ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN << shift, 
0);
if (ret)
return ret;
} else {
@@ -326,14 +311,20 @@ static inline int arasan_zynqmp_set_in_tapdelay(u32 
node_id, u32 itap_delay)
  
  static inline int arasan_zynqmp_set_out_tapdelay(u32 node_id, u32 otap_delay)

  {
+   u32 shift;
+
+   if (node_id == NODE_SD_0)
+   shift = 0;
+   else if (node_id == NODE_SD_1)
+   shift = SD

[PATCH v4] test/py: reset: Add a test for reset command

2024-03-12 Thread Love Kumar
Add a test for reset commands which performs resetting of CPU, It does
COLD reset by default and WARM reset with -w option.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
Changes in v3:
 - Fix the issue with bad pattern found on console
Changes in v4:
 - Add dependency with hush parser to support variable expansion
---
 test/py/tests/test_reset.py | 63 +
 1 file changed, 63 insertions(+)
 create mode 100644 test/py/tests/test_reset.py

diff --git a/test/py/tests/test_reset.py b/test/py/tests/test_reset.py
new file mode 100644
index ..00fc31da57d1
--- /dev/null
+++ b/test/py/tests/test_reset.py
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__reset_test_skip to True if reset test is not possible or desired
+# and should be skipped.
+env__reset_test_skip = True
+
+# Setup env__reset_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__reset_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import test_000_version
+
+def setup_reset_env(u_boot_console):
+if u_boot_console.config.env.get('env__reset_test_skip', False):
+pytest.skip('reset test is not enabled')
+
+output = u_boot_console.run_command('echo $modeboot')
+if output:
+bootmode = output
+else:
+f = u_boot_console.config.env.get('env__reset_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+
+if 'jtag' in bootmode:
+pytest.skip('skipping reset test due to jtag bootmode')
+
+@pytest.mark.buildconfigspec('hush_parser')
+def test_reset(u_boot_console):
+"""Test the reset command in non-JTAG bootmode.
+It does COLD reset, which resets CPU, DDR and peripherals
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
+
+@pytest.mark.buildconfigspec('hush_parser')
+def test_reset_w(u_boot_console):
+"""Test the reset -w command in non-JTAG bootmode.
+It does WARM reset, which resets CPU but keep DDR/peripherals active.
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset -w', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
-- 
2.25.1



[PATCH v4] test/py: saveenv: Add a test for saveenv command

2024-03-12 Thread Love Kumar
Add test case for saveenv command in non-JTAG bootmode which saves the
u-boot environment variables in persistent storage.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
Changes in v3:
 - Fix the issue with bad patterns and escape sequence warning
Changes in v4:
 - Add dependency with hush parser to support variable expansion
---
 test/py/tests/test_saveenv.py | 137 ++
 1 file changed, 137 insertions(+)
 create mode 100644 test/py/tests/test_saveenv.py

diff --git a/test/py/tests/test_saveenv.py b/test/py/tests/test_saveenv.py
new file mode 100644
index ..7faa3bdf93de
--- /dev/null
+++ b/test/py/tests/test_saveenv.py
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__saveenv_test_skip to True if saveenv test is not possible or
+# desired and should be skipped.
+env__saveenv_test_skip = True
+
+# Setup env__saveenv_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__saveenv_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import random
+import ipaddress
+import string
+import uuid
+
+# Setup the env
+def setup_saveenv_env(u_boot_console):
+if u_boot_console.config.env.get('env__saveenv_test_skip', False):
+pytest.skip('saveenv test is not enabled')
+
+output = u_boot_console.run_command('echo $modeboot')
+if output:
+bootmode = output
+else:
+f = u_boot_console.config.env.get('env__saveenv_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+
+if 'jtag' in bootmode:
+pytest.skip('skipping saveenv test due to jtag bootmode')
+
+# Check return code
+def ret_code(u_boot_console):
+return u_boot_console.run_command('echo $?')
+
+# Verify env variable
+def check_env(u_boot_console, var_name, var_value):
+if var_value:
+output = u_boot_console.run_command(f'printenv {var_name}')
+var_value = str(var_value)
+if (var_value.startswith("'") and var_value.endswith("'")) or (
+var_value.startswith('"') and var_value.endswith('"')
+):
+var_value = var_value.split(var_value[-1])[1]
+assert var_value in output
+assert ret_code(u_boot_console).endswith('0')
+else:
+u_boot_console.p.send(f'printenv {var_name}\n')
+output = u_boot_console.p.expect(['not defined'])
+assert output == 0
+assert ret_code(u_boot_console).endswith('1')
+
+# Set env variable
+def set_env(u_boot_console, var_name, var_value):
+u_boot_console.run_command(f'setenv {var_name} {var_value}')
+assert ret_code(u_boot_console).endswith('0')
+check_env(u_boot_console, var_name, var_value)
+
+@pytest.mark.buildconfigspec('cmd_saveenv')
+@pytest.mark.buildconfigspec('hush_parser')
+def test_saveenv(u_boot_console):
+"""Test the saveenv command in non-JTAG bootmode.
+It saves the U-Boot environment in persistent storage.
+"""
+setup_saveenv_env(u_boot_console)
+
+# Set env for random mac address
+rand_mac = '%02x:%02x:%02x:%02x:%02x:%02x' % (
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+)
+set_env(u_boot_console, 'mac_addr', rand_mac)
+
+# Set env for random IPv4 address
+rand_ipv4 = ipaddress.IPv4Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv4Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv4_addr', rand_ipv4)
+
+# Set env for random IPv6 address
+rand_ipv6 = ipaddress.IPv6Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv6Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv6_addr', rand_ipv6)
+
+# Set env for random number
+rand_num = random.randrange(1, 10**9)
+set_env(u_boot_console, 'num_var', rand_num)
+
+# Set env for uuid
+uuid_str = uuid.uuid4().hex.lower()
+set_env(u_boot_console, 'uuid_var', uuid_str)
+
+# Set env for random string including special characters
+sc = 

Re: [PATCH v3] test/py: reset: Add a test for reset command

2024-03-11 Thread Love Kumar

Hi,

On 11/03/24 2:11 pm, Angelo Dureghello wrote:

Hi,

jfyi,

reset support added in qemu
merged as commit d3c79c3974.

Regards,
angelo


The other issue was with echo commands:
=> echo $modeboot
$modeboot

=> echo $?
$?

Does HUSH shell is enabled by default for this?

Regards,
Love Kumar


On 07/03/24 1:55 PM, Tom Rini wrote:

On Thu, Mar 07, 2024 at 09:26:42AM +0100, Michal Simek wrote:



On 3/7/24 08:56, Angelo Dureghello wrote:

Hi Tom,

On 07/03/24 1:10 AM, Tom Rini wrote:

On Thu, Mar 07, 2024 at 12:36:42AM +0100, Angelo Dureghello wrote:

Hi,

On 05/03/24 1:34 PM, Michal Simek wrote:



On 3/3/24 22:58, Angelo Dureghello wrote:

Hi Tom,

On Tue, Feb 20, 2024 at 01:11:38PM +0530, Love Kumar wrote:

Add a test for reset commands which performs resetting of
CPU, It does COLD reset by default and WARM reset with -w
option. Signed-off-by: Love Kumar 
Reviewed-by: Tom Rini  --- Changes in
v2: - Set bootmode through boardenv if modeboot is not
defined Changes in v3: - Fix the issue with bad pattern
found on console --- test/py/tests/test_reset.py | 61
+ 1 file changed, 61
insertions(+) create mode 100644 test/py/tests/test_reset.py

I had hoped this was all sorted out now, but both this and the
saveenv test cause qemu_m68k to fail now. See:
https://source.denx.de/u-boot/u-boot/-/jobs/791635

looking into this.


Is reset implemented in qemu? It should be skipped if it is not.


yes, seems not implemented

=> reset
=> reset -w
=>
=>

Not finding any trace in the qemu code related to

out_8(&rcm->rcr, RCM_RCR_SOFTRST);


Does reset work on the real HW, or can you not test? What I'm 
wondering

is if we have a missing feature on the board/arch code (and should
disable the reset command) or a problem with QEMU.


I don't have the exact hardware (m5208evb) but:

1) i checked by tracing that on qemu the reset function is properly 
called


=> reset
resetting, RCR fc0a

2) reset register address is correct. I checked also that writing
directly to it by mw.b does now produce the reset,

=> reset
resetting, RCR fc0a

=> mw.b 0xfc0a 80
=>

So looks not implemented in qemu.


ok. That means that we shouldn't run reset test inside CI loop for 
this platform.


Agreed.  The TEST_PY_TEST_SPEC variable in both of the pipelines can be
used to say "not reset" for this platform in the next rev. It would also
be nice to file a bug report with QEMU too I think. Thanks for digging
in to this everyone.



[PATCH v3] test/py: saveenv: Add a test for saveenv command

2024-02-19 Thread Love Kumar
Add test case for saveenv command in non-JTAG bootmode which saves the
u-boot environment variables in persistent storage.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
Changes in v3:
 - Fix the issue with bad patterns and escape sequence warning
---
 test/py/tests/test_saveenv.py | 136 ++
 1 file changed, 136 insertions(+)
 create mode 100644 test/py/tests/test_saveenv.py

diff --git a/test/py/tests/test_saveenv.py b/test/py/tests/test_saveenv.py
new file mode 100644
index ..fa0863f6d314
--- /dev/null
+++ b/test/py/tests/test_saveenv.py
@@ -0,0 +1,136 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__saveenv_test_skip to True if saveenv test is not possible or
+# desired and should be skipped.
+env__saveenv_test_skip = True
+
+# Setup env__saveenv_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__saveenv_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import random
+import ipaddress
+import string
+import uuid
+
+# Setup the env
+def setup_saveenv_env(u_boot_console):
+if u_boot_console.config.env.get('env__saveenv_test_skip', False):
+pytest.skip('saveenv test is not enabled')
+
+output = u_boot_console.run_command('echo $modeboot')
+if output:
+bootmode = output
+else:
+f = u_boot_console.config.env.get('env__saveenv_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+
+if 'jtag' in bootmode:
+pytest.skip('skipping saveenv test due to jtag bootmode')
+
+# Check return code
+def ret_code(u_boot_console):
+return u_boot_console.run_command('echo $?')
+
+# Verify env variable
+def check_env(u_boot_console, var_name, var_value):
+if var_value:
+output = u_boot_console.run_command(f'printenv {var_name}')
+var_value = str(var_value)
+if (var_value.startswith("'") and var_value.endswith("'")) or (
+var_value.startswith('"') and var_value.endswith('"')
+):
+var_value = var_value.split(var_value[-1])[1]
+assert var_value in output
+assert ret_code(u_boot_console).endswith('0')
+else:
+u_boot_console.p.send(f'printenv {var_name}\n')
+output = u_boot_console.p.expect(['not defined'])
+assert output == 0
+assert ret_code(u_boot_console).endswith('1')
+
+# Set env variable
+def set_env(u_boot_console, var_name, var_value):
+u_boot_console.run_command(f'setenv {var_name} {var_value}')
+assert ret_code(u_boot_console).endswith('0')
+check_env(u_boot_console, var_name, var_value)
+
+@pytest.mark.buildconfigspec('cmd_saveenv')
+def test_saveenv(u_boot_console):
+"""Test the saveenv command in non-JTAG bootmode.
+It saves the U-Boot environment in persistent storage.
+"""
+setup_saveenv_env(u_boot_console)
+
+# Set env for random mac address
+rand_mac = '%02x:%02x:%02x:%02x:%02x:%02x' % (
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+)
+set_env(u_boot_console, 'mac_addr', rand_mac)
+
+# Set env for random IPv4 address
+rand_ipv4 = ipaddress.IPv4Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv4Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv4_addr', rand_ipv4)
+
+# Set env for random IPv6 address
+rand_ipv6 = ipaddress.IPv6Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv6Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv6_addr', rand_ipv6)
+
+# Set env for random number
+rand_num = random.randrange(1, 10**9)
+set_env(u_boot_console, 'num_var', rand_num)
+
+# Set env for uuid
+uuid_str = uuid.uuid4().hex.lower()
+set_env(u_boot_console, 'uuid_var', uuid_str)
+
+# Set env for random string including special characters
+sc = "!#%&()*+,-./:;<=>?@[\\]^_`{|}~"
+rand_str = ''.join(
+random.choices(' ' + str

[PATCH v3] test/py: reset: Add a test for reset command

2024-02-19 Thread Love Kumar
Add a test for reset commands which performs resetting of CPU, It does
COLD reset by default and WARM reset with -w option.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
Changes in v3:
 - Fix the issue with bad pattern found on console
---
 test/py/tests/test_reset.py | 61 +
 1 file changed, 61 insertions(+)
 create mode 100644 test/py/tests/test_reset.py

diff --git a/test/py/tests/test_reset.py b/test/py/tests/test_reset.py
new file mode 100644
index ..0178b1dc40a3
--- /dev/null
+++ b/test/py/tests/test_reset.py
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__reset_test_skip to True if reset test is not possible or desired
+# and should be skipped.
+env__reset_test_skip = True
+
+# Setup env__reset_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__reset_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import test_000_version
+
+def setup_reset_env(u_boot_console):
+if u_boot_console.config.env.get('env__reset_test_skip', False):
+pytest.skip('reset test is not enabled')
+
+output = u_boot_console.run_command('echo $modeboot')
+if output:
+bootmode = output
+else:
+f = u_boot_console.config.env.get('env__reset_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+
+if 'jtag' in bootmode:
+pytest.skip('skipping reset test due to jtag bootmode')
+
+def test_reset(u_boot_console):
+"""Test the reset command in non-JTAG bootmode.
+It does COLD reset, which resets CPU, DDR and peripherals
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
+
+def test_reset_w(u_boot_console):
+"""Test the reset -w command in non-JTAG bootmode.
+It does WARM reset, which resets CPU but keep DDR/peripherals active.
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset -w', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
-- 
2.25.1



[PATCH v2] test/py: reset: Add a test for reset command

2024-02-13 Thread Love Kumar
Add a test for reset commands which performs resetting of CPU, It does
COLD reset by default and WARM reset with -w option.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
---
 test/py/tests/test_reset.py | 63 +
 1 file changed, 63 insertions(+)
 create mode 100644 test/py/tests/test_reset.py

diff --git a/test/py/tests/test_reset.py b/test/py/tests/test_reset.py
new file mode 100644
index ..6153a6d3e4d2
--- /dev/null
+++ b/test/py/tests/test_reset.py
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__reset_test_skip to True if reset test is not possible or desired
+# and should be skipped.
+env__reset_test_skip = True
+
+# Setup env__reset_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__reset_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import re
+import test_000_version
+
+def setup_reset_env(u_boot_console):
+if u_boot_console.config.env.get('env__reset_test_skip', False):
+pytest.skip('reset test is not enabled')
+
+output = u_boot_console.run_command('print modeboot')
+if 'not defined' in output:
+f = u_boot_console.config.env.get('env__reset_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+else:
+m = re.search('modeboot=(.+)', output)
+bootmode = m.group(1)
+
+if 'jtag' in bootmode:
+pytest.skip('skipping reset test due to jtag bootmode')
+
+def test_reset(u_boot_console):
+"""Test the reset command in non-JTAG bootmode.
+It does COLD reset, which resets CPU, DDR and peripherals
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
+
+def test_reset_w(u_boot_console):
+"""Test the reset -w command in non-JTAG bootmode.
+It does WARM reset, which resets CPU but keep DDR/peripherals active.
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset -w', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
-- 
2.25.1



[PATCH v2] test/py: saveenv: Add a test for saveenv command

2024-02-13 Thread Love Kumar
Add test case for saveenv command in non-JTAG bootmode which saves the
u-boot environment variables in persistent storage.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Set bootmode through boardenv if modeboot is not defined
---
 test/py/tests/test_saveenv.py | 138 ++
 1 file changed, 138 insertions(+)
 create mode 100644 test/py/tests/test_saveenv.py

diff --git a/test/py/tests/test_saveenv.py b/test/py/tests/test_saveenv.py
new file mode 100644
index ..cac854d82bab
--- /dev/null
+++ b/test/py/tests/test_saveenv.py
@@ -0,0 +1,138 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__saveenv_test_skip to True if saveenv test is not possible or
+# desired and should be skipped.
+env__saveenv_test_skip = True
+
+# Setup env__saveenv_test to set the bootmode if 'modeboot' u-boot environment
+# variable is not set. Test will be skipped if bootmode is not set in both
+# places i.e, boardenv and modeboot u-boot environment variable
+env__saveenv_test = {
+'bootmode': 'qspiboot',
+}
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import re
+import random
+import ipaddress
+import string
+import uuid
+
+# Setup the env
+def setup_saveenv_env(u_boot_console):
+if u_boot_console.config.env.get('env__saveenv_test_skip', False):
+pytest.skip('saveenv test is not enabled')
+
+output = u_boot_console.run_command('print modeboot')
+if 'not defined' in output:
+f = u_boot_console.config.env.get('env__saveenv_test', None)
+if not f:
+pytest.skip('bootmode cannot be determined')
+bootmode = f.get('bootmode', 'jtagboot')
+else:
+m = re.search('modeboot=(.+)', output)
+bootmode = m.group(1)
+
+if 'jtag' in bootmode:
+pytest.skip('skipping saveenv test due to jtag bootmode')
+
+# Check return code
+def ret_code(u_boot_console):
+return u_boot_console.run_command('echo $?')
+
+# Verify env variable
+def check_env(u_boot_console, var_name, var_value):
+if var_value:
+output = u_boot_console.run_command(f'printenv {var_name}')
+var_value = str(var_value)
+if (var_value.startswith("'") and var_value.endswith("'")) or (
+var_value.startswith('"') and var_value.endswith('"')
+):
+var_value = var_value.split(var_value[-1])[1]
+assert var_value in output
+assert ret_code(u_boot_console).endswith('0')
+else:
+u_boot_console.p.send(f'printenv {var_name}\n')
+output = u_boot_console.p.expect(['not defined'])
+assert output == 0
+assert ret_code(u_boot_console).endswith('1')
+
+# Set env variable
+def set_env(u_boot_console, var_name, var_value):
+u_boot_console.run_command(f'setenv {var_name} {var_value}')
+assert ret_code(u_boot_console).endswith('0')
+check_env(u_boot_console, var_name, var_value)
+
+@pytest.mark.buildconfigspec('cmd_saveenv')
+def test_saveenv(u_boot_console):
+"""Test the saveenv command in non-JTAG bootmode.
+It saves the U-Boot environment in persistent storage.
+"""
+setup_saveenv_env(u_boot_console)
+
+# Set env for random mac address
+rand_mac = '%02x:%02x:%02x:%02x:%02x:%02x' % (
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+)
+set_env(u_boot_console, 'mac_addr', rand_mac)
+
+# Set env for random IPv4 address
+rand_ipv4 = ipaddress.IPv4Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv4Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv4_addr', rand_ipv4)
+
+# Set env for random IPv6 address
+rand_ipv6 = ipaddress.IPv6Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv6Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv6_addr', rand_ipv6)
+
+# Set env for random number
+rand_num = random.randrange(1, 10**9)
+set_env(u_boot_console, 'num_var', rand_num)
+
+# Set env for uuid
+uuid_str = uuid.uuid4().hex.lower()
+set_env(u_boot_console, 'uuid_var', uuid_str)
+
+# Set env for random string including special characters
+sc = "!#%&\()*+,-./:;<=>?@[\\]^_`{|}~"
+rand_str = ''.join(
+random.choices

[PATCH v5] test/py: net: Add dhcp abort test

2024-01-30 Thread Love Kumar
Abort the dhcp request in the middle by pressing ctrl + c on u-boot
prompt and validate the abort status.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Mark CMD_MII command dependency

Changes in v3:
 - Skip the test if PHY device not present

Changes in v4:
 - Setup the network configuration by running dhcp test at the end of
 test
 - Add option to skip the test if it is not desired or possible

Changes in v5:
 - Disable this test case by default
 - Use single quote to maintain consistency
 - Setup the network configuration before exiting the test
---
 test/py/tests/test_net.py | 58 +++
 1 file changed, 58 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index 4ff3dafd6293..038a473b2394 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -8,6 +8,7 @@ import pytest
 import u_boot_utils
 import uuid
 import datetime
+import re
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -31,6 +32,12 @@ env__net_uses_pci = True
 # set to False.
 env__net_dhcp_server = True
 
+# False or omitted if a DHCP server is attached to the network, and dhcp abort
+# case should be tested.
+# If DHCP abort testing is not possible or desired, set this variable to True.
+# For example: On some setup, dhcp is too fast and this case may not work.
+env__dhcp_abort_test_skip = True
+
 # True if a DHCPv6 server is attached to the network, and should be tested.
 # If DHCPv6 testing is not possible or desired, this variable may be omitted or
 # set to False.
@@ -120,6 +127,57 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec('cmd_dhcp')
+@pytest.mark.buildconfigspec('cmd_mii')
+def test_net_dhcp_abort(u_boot_console):
+"""Test the dhcp command by pressing ctrl+c in the middle of dhcp request
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False)
+if not test_dhcp:
+pytest.skip('No DHCP server available')
+
+if u_boot_console.config.env.get('env__dhcp_abort_test_skip', True):
+pytest.skip('DHCP abort test is not enabled!')
+
+u_boot_console.run_command('setenv autoload no')
+
+# Phy reset before running dhcp command
+output = u_boot_console.run_command('mii device')
+if not re.search(r"Current device: '(.+?)'", output):
+pytest.skip('PHY device does not exist!')
+eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f'mii device {eth_num}')
+output = u_boot_console.run_command('mii info')
+eth_addr = hex(int(re.search(r'PHY (.+?):', output).groups()[0], 16))
+u_boot_console.run_command(f'mii modify {eth_addr} 0 0x8000 0x8000')
+
+u_boot_console.run_command('dhcp', wait_for_prompt=False)
+try:
+u_boot_console.wait_for('Waiting for PHY auto negotiation to complete')
+except:
+pytest.skip('Timeout waiting for PHY auto negotiation to complete')
+
+u_boot_console.wait_for('done')
+
+try:
+# Sending Ctrl-C
+output = u_boot_console.run_command(
+chr(3), wait_for_echo=False, send_nl=False
+)
+assert 'TIMEOUT' not in output
+assert 'DHCP client bound to address ' not in output
+assert 'Abort' in output
+finally:
+# Provide a time to recover from Abort - if it is not performed
+# There is message like: ethernet@ff0e: No link.
+u_boot_console.run_command('sleep 1')
+# Run the dhcp test to setup the network configuration
+test_net_dhcp(u_boot_console)
+
 @pytest.mark.buildconfigspec('cmd_dhcp6')
 def test_net_dhcp6(u_boot_console):
 """Test the dhcp6 command.
-- 
2.25.1



[PATCH] test/py: scsi: Add test for scsi commands

2024-01-19 Thread Love Kumar
Add a following test cases for scsi commands:
scsi_reset - To reset SCSI controller
scsi_info - To show available SCSI devices
scsi_scan - To (re-)scan SCSI bus
scsi_device - To show or set surrent device
scsi_part - To print partition table of selected SCSI device

Signed-off-by: Love Kumar 
---
 test/py/tests/test_scsi.py | 92 ++
 1 file changed, 92 insertions(+)
 create mode 100644 test/py/tests/test_scsi.py

diff --git a/test/py/tests/test_scsi.py b/test/py/tests/test_scsi.py
new file mode 100644
index ..be2e283e7d25
--- /dev/null
+++ b/test/py/tests/test_scsi.py
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the SCSI device number, type and capacity. This test will be automatically
+skipped without this.
+
+For example:
+
+# Setup env__scsi_device_test to set the SCSI device number/slot, the type of
+device, and the device capacity in MB.
+env__scsi_device_test = {
+'dev_num': 0,
+'device_type': 'Hard Disk',
+'device_capacity': '476940.0 MB',
+}
+"""
+
+def scsi_setup(u_boot_console):
+f = u_boot_console.config.env.get('env__scsi_device_test', None)
+if not f:
+pytest.skip('No SCSI device to test')
+
+dev_num = f.get('dev_num', None)
+if not isinstance(dev_num, int):
+pytest.skip('No device number specified in env file to read')
+
+dev_type = f.get('device_type')
+if not dev_type:
+pytest.skip('No device type specified in env file to read')
+
+dev_size = f.get('device_capacity')
+if not dev_size:
+pytest.skip('No device capacity specified in env file to read')
+
+return dev_num, dev_type, dev_size
+
+@pytest.mark.buildconfigspec('cmd_scsi')
+def test_scsi_reset(u_boot_console):
+dev_num, dev_type, dev_size = scsi_setup(u_boot_console)
+output = u_boot_console.run_command('scsi reset')
+assert f'Device {dev_num}:' in output
+assert f'Type: {dev_type}' in output
+assert f'Capacity: {dev_size}' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_scsi')
+def test_scsi_info(u_boot_console):
+dev_num, dev_type, dev_size = scsi_setup(u_boot_console)
+output = u_boot_console.run_command('scsi info')
+assert f'Device {dev_num}:' in output
+assert f'Type: {dev_type}' in output
+assert f'Capacity: {dev_size}' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_scsi')
+def test_scsi_scan(u_boot_console):
+dev_num, dev_type, dev_size = scsi_setup(u_boot_console)
+output = u_boot_console.run_command('scsi scan')
+assert f'Device {dev_num}:' in output
+assert f'Type: {dev_type}' in output
+assert f'Capacity: {dev_size}' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_scsi')
+def test_scsi_dev(u_boot_console):
+dev_num, dev_type, dev_size = scsi_setup(u_boot_console)
+output = u_boot_console.run_command('scsi device')
+assert 'no scsi devices available' not in output
+assert f'device {dev_num}:' in output
+assert f'Type: {dev_type}' in output
+assert f'Capacity: {dev_size}' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+output = u_boot_console.run_command('scsi device %d' % dev_num)
+assert 'is now current device' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_scsi')
+def test_scsi_part(u_boot_console):
+test_scsi_dev(u_boot_console)
+output = u_boot_console.run_command('scsi part')
+assert 'Partition Map for SCSI device' in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
-- 
2.25.1



[PATCH] test/py: spi: Add tests for SPI flash device

2024-01-19 Thread Love Kumar
Add test cases for sf commands to verify various SPI flash operations
such as erase, write and read. It also adds qspi lock unlock cases.
This test relies on boardenv_* configurations to run it for different
SPI flash family such as single SPI, QSPI, and OSPI.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_spi.py | 626 ++
 1 file changed, 626 insertions(+)
 create mode 100644 test/py/tests/test_spi.py

diff --git a/test/py/tests/test_spi.py b/test/py/tests/test_spi.py
new file mode 100644
index ..a0b5c075b6ce
--- /dev/null
+++ b/test/py/tests/test_spi.py
@@ -0,0 +1,626 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+import u_boot_utils
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+spi minimum and maximum frequnecies at which the flash part can operate on and
+these tests run at 5 different spi frequnecy randomised values in the range.
+It also defines the SPI bus number containing the SPI-flash chip, SPI
+chip-select, SPI mode, SPI flash part name and timeout parameters. If minimum
+and maximum frequency is not defined, it will run on freq 0 by default.
+
+Without the boardenv_* configuration, this test will be automatically skipped.
+
+It also relies on configuration values for supported flashes for qspi lock and
+unlock cases. It will run qspi lock-unlock cases only for the supported flash
+parts.
+
+Example:
+env__spi_device_test = {
+'bus': 0,
+'chip_select': 0,
+'min_freq': 1000,
+'max_freq': 1,
+'mode': 0,
+'part_name': 'n25q00a',
+'timeout': 10,
+}
+
+env__qspi_lock_unlock = {
+'supported_flash': 'mt25qu512a, n25q00a, n25q512ax3',
+}
+"""
+
+def setup_spi(u_boot_console):
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+bus = f.get('bus', 0)
+cs = f.get('chip_select', 0)
+mode = f.get('mode', 0)
+part_name = f.get('part_name', None)
+timeout = f.get('timeout', None)
+
+if not part_name:
+pytest.skip('No env file to read SPI family flash part name')
+
+return bus, cs, mode, part_name, timeout
+
+# Find out minimum and maximum frequnecies that SPI device can operate
+def spi_find_freq_range(u_boot_console):
+f = u_boot_console.config.env.get('env__spi_device_test', None)
+if not f:
+pytest.skip('No env file to read for SPI family device test')
+
+min_f = f.get('min_freq', None)
+max_f = f.get('max_freq', None)
+
+if not min_f:
+min_f = 0
+if not max_f:
+max_f = 0
+if max_f < min_f:
+max_f = min_f
+
+if min_f == 0 and max_f == 0:
+iterations = 1
+else:
+iterations = 5
+
+return min_f, max_f, iterations
+
+# Find out SPI family flash memory parameters
+def spi_pre_commands(u_boot_console, freq):
+bus, cs, mode, part_name, timeout = setup_spi(u_boot_console)
+
+output = u_boot_console.run_command(f'sf probe {bus}:{cs} {freq} {mode}')
+if not 'SF: Detected' in output:
+pytest.skip('No SPI device available')
+
+if not part_name in output:
+pytest.fail('SPI flash part name not recognized')
+
+m = re.search('page size (.+?) Bytes', output)
+if m:
+try:
+page_size = int(m.group(1))
+except ValueError:
+pytest.fail('SPI page size not recognized')
+
+m = re.search('erase size (.+?) KiB', output)
+if m:
+try:
+erase_size = int(m.group(1))
+except ValueError:
+pytest.fail('SPI erase size not recognized')
+
+erase_size *= 1024
+
+m = re.search('total (.+?) MiB', output)
+if m:
+try:
+global total_size
+total_size = int(m.group(1))
+except ValueError:
+pytest.fail('SPI total size not recognized')
+
+total_size *= 1024 * 1024
+
+m = re.search('Detected (.+?) with', output)
+if m:
+try:
+flash_part = m.group(1)
+assert flash_part == part_name
+except:
+pytest.fail('SPI flash part not recognized')
+
+return page_size, erase_size, total_size, flash_part, timeout
+
+# Read the whole SPI flash twice, random_size till full flash size, random
+# till page size
+def spi_read_twice(u_boot_console, page_size, total_size, timeout):
+expected_read = 'Read: OK'
+
+for size in random.randint(4, page_size), random.randint(4, t

[PATCH] test/py: nand: Add tests for NAND flash device

2024-01-19 Thread Love Kumar
Add tests for nand commands to test various NAND flash operations such
as erase, write and read.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_nand.py | 201 +
 1 file changed, 201 insertions(+)
 create mode 100644 test/py/tests/test_nand.py

diff --git a/test/py/tests/test_nand.py b/test/py/tests/test_nand.py
new file mode 100644
index ..f5fd5d065cfe
--- /dev/null
+++ b/test/py/tests/test_nand.py
@@ -0,0 +1,201 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+import u_boot_utils
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the nand device total size and timeout available for testing. Without this, the
+test will be automatically skipped. This test will be also skipped if the NAND
+flash device is not detected.
+
+For example:
+
+# Setup env__nand_device_test to set the NAND flash total size and timeout.
+env__nand_device_test = {
+   'size': '8192 MB',
+   'timeout': 10,
+}
+"""
+
+# Find out nand memory parameters
+def nand_pre_commands(u_boot_console):
+f = u_boot_console.config.env.get('env__nand_device_test', None)
+if not f:
+pytest.skip('No env file to read for NAND device test')
+
+total_size = f.get('size', None)
+timeout = f.get('timeout')
+
+if not total_size:
+pytest.skip('NAND device size not recognized')
+
+output = u_boot_console.run_command('nand info')
+if not 'Device 0: nand0' in output:
+pytest.skip('No NAND device available')
+
+m = re.search('Page size (.+?) b', output)
+if m:
+try:
+page_size = int(m.group(1))
+except ValueError:
+pytest.fail('NAND page size not recognized')
+
+m = re.search('sector size (.+?) KiB', output)
+if m:
+try:
+erase_size = int(m.group(1))
+sector_size = erase_size
+except ValueError:
+pytest.fail('NAND erase size not recognized')
+
+erase_size *= 1024
+
+output = u_boot_console.run_command('nand bad')
+if not 'bad blocks:' in output:
+pytest.skip('No NAND device available')
+
+count = 0
+m = re.search('bad blocks:([\n\s\s\d\w]*)', output)
+if m:
+print(m.group(1))
+var = m.group(1).split()
+count = len(var)
+print('bad blocks count= ' + str(count))
+
+m = re.search('(.+?) MB', total_size)
+if m:
+try:
+total_size = int(m.group(1))
+total_size *= 1024 * 1024
+print('Total size is: ' + str(total_size) + ' B')
+total_size -= count * sector_size * 1024
+print('New Total size is: ' + str(total_size) + ' B')
+except ValueError:
+pytest.fail('NAND size not recognized')
+
+return page_size, erase_size, total_size, sector_size, timeout
+
+@pytest.mark.buildconfigspec('cmd_nand')
+@pytest.mark.buildconfigspec('cmd_bdi')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_nand_read_twice(u_boot_console):
+"""This test reads the whole NAND flash twice, random_size till full flash
+size, random till page size.
+"""
+
+page_size, erase_size, total_size, sector_size, timeout = 
nand_pre_commands(
+u_boot_console)
+expected_read = 'read: OK'
+
+for size in random.randint(4, page_size), random.randint(4, total_size), 
total_size:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+output = u_boot_console.run_command(
+'nand read %x 0 %x' % (addr + total_size, size)
+)
+assert expected_read in output
+
+output = u_boot_console.run_command('crc32 %x %x' % (addr + 
total_size, size))
+m = re.search('==> (.+?)', output)
+if not m:
+pytest.fail('CRC32 failed')
+expected_crc32 = m.group(1)
+
+output = u_boot_console.run_command(
+'nand read %x 0 %x' % (addr + total_size + 10, size)
+)
+assert expected_read in output
+
+output = u_boot_console.run_command(
+'crc32 %x %x' % (addr + total_size + 10, size)
+)
+assert expected_crc32 in output
+
+@pytest.mark.buildconfigspec('cmd_nand')
+@pytest.mark.buildconfigspec('cmd_bdi')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_nand_write_twice(u_boot_console):
+"""This test does the random writes till page size, size and full size"""
+
+page

[PATCH] test/py: usb: Add tests for USB device

2024-01-19 Thread Love Kumar
Add the test cases for usb commands to test its various functionality
such as start, stop, reset, info, tree, storage, dev, part, ls, load,
and save. It also adds different file systems cases such as fat32, ext2
and ext4.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_usb.py | 626 ++
 1 file changed, 626 insertions(+)
 create mode 100644 test/py/tests/test_usb.py

diff --git a/test/py/tests/test_usb.py b/test/py/tests/test_usb.py
new file mode 100644
index ..fb3d20f0826b
--- /dev/null
+++ b/test/py/tests/test_usb.py
@@ -0,0 +1,626 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+import u_boot_utils
+
+"""
+Note: This test doesn't rely on boardenv_* configuration values but it can
+change the test behavior. To test USB file system cases (fat32, ext2, ext4),
+USB device should be formatted and valid partitions should be created for
+different file system, otherwise it may leads to failure. This test will be
+skipped if the USB device is not detected.
+
+For example:
+
+# Setup env__usb_device_test_skip to not skipping the test. By default, its
+# value is set to True. Set it to False to run all tests for USB device.
+env__usb_device_test_skip = False
+"""
+
+def setup_usb(u_boot_console):
+if u_boot_console.config.env.get('env__usb_device_test_skip', True):
+pytest.skip('USB device test is not enabled')
+
+@pytest.mark.buildconfigspec('cmd_usb')
+def test_usb_start(u_boot_console):
+setup_usb(u_boot_console)
+output = u_boot_console.run_command('usb start')
+
+# if output is empty, usb start may already run as part of preboot command
+# re-start the usb, in that case
+if not output:
+u_boot_console.run_command('usb stop')
+output = u_boot_console.run_command('usb start')
+
+if 'No USB device found' in output:
+pytest.skip('No USB controller available')
+
+if 'Card did not respond to voltage select' in output:
+pytest.skip('No USB device present')
+
+controllers = 0
+storage_device = 0
+obj = re.search(r'\d USB Device\(s\) found', output)
+controllers = int(obj.group()[0])
+
+if not controllers:
+pytest.skip('No USB device present')
+
+obj = re.search(r'\d Storage Device\(s\) found', output)
+storage_device = int(obj.group()[0])
+
+if not storage_device:
+pytest.skip('No USB storage device present')
+
+assert 'USB init failed' not in output
+assert 'starting USB...' in output
+
+if 'Starting the controller' in output:
+assert 'USB XHCI' in output
+
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+return controllers, storage_device
+
+@pytest.mark.buildconfigspec('cmd_usb')
+def test_usb_stop(u_boot_console):
+setup_usb(u_boot_console)
+output = u_boot_console.run_command('usb stop')
+assert 'stopping USB..' in output
+
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+output = u_boot_console.run_command('usb dev')
+assert "USB is stopped. Please issue 'usb start' first." in output
+
+@pytest.mark.buildconfigspec('cmd_usb')
+def test_usb_reset(u_boot_console):
+setup_usb(u_boot_console)
+output = u_boot_console.run_command('usb reset')
+
+if 'No USB device found' in output:
+pytest.skip('No USB controller available')
+
+if 'Card did not respond to voltage select' in output:
+pytest.skip('No USB device present')
+
+obj = re.search(r'\d USB Device\(s\) found', output)
+usb_dev_num = int(obj.group()[0])
+
+if not usb_dev_num:
+pytest.skip('No USB device present')
+
+obj = re.search(r'\d Storage Device\(s\) found', output)
+usb_stor_num = int(obj.group()[0])
+
+if not usb_stor_num:
+pytest.skip('No USB storage device present')
+
+assert 'BUG' not in output
+assert 'USB init failed' not in output
+assert 'resetting USB...' in output
+
+if 'Starting the controller' in output:
+assert 'USB XHCI' in output
+
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_usb')
+def test_usb_info(u_boot_console):
+controllers, storage_device = test_usb_start(u_boot_console)
+output = u_boot_console.run_command('usb info')
+
+num_controller = len(re.findall(': Hub,', output))
+   

[PATCH] test/py: mmc: Add tests for MMC device

2024-01-19 Thread Love Kumar
Add the test cases for mmc commands to test its various functionality
such as mmc list, dev, info, rescan, part, ls, load, and save. It also
adds different file systems cases such as fat32, ext2 and ext4.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_mmc.py | 671 ++
 1 file changed, 671 insertions(+)
 create mode 100644 test/py/tests/test_mmc.py

diff --git a/test/py/tests/test_mmc.py b/test/py/tests/test_mmc.py
new file mode 100644
index ..a96c4e8fd890
--- /dev/null
+++ b/test/py/tests/test_mmc.py
@@ -0,0 +1,671 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+import u_boot_utils
+
+"""
+Note: This test doesn't rely on boardenv_* configuration values but it can
+change the test behavior. To test MMC file system cases (fat32, ext2, ext4),
+MMC device should be formatted and valid partitions should be created for
+different file system, otherwise it may leads to failure. This test will be
+skipped if the MMC device is not detected.
+
+For example:
+
+# Setup env__mmc_device_test_skip to not skipping the test. By default, its
+# value is set to True. Set it to False to run all tests for MMC device.
+env__mmc_device_test_skip = False
+"""
+
+mmc_set_up = False
+controllers = 0
+devices = {}
+
+def setup_mmc(u_boot_console):
+if u_boot_console.config.env.get('env__mmc_device_test_skip', True):
+pytest.skip('MMC device test is not enabled')
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_list(u_boot_console):
+setup_mmc(u_boot_console)
+output = u_boot_console.run_command('mmc list')
+if 'No MMC device available' in output:
+pytest.skip('No SD/MMC/eMMC controller available')
+
+if 'Card did not respond to voltage select' in output:
+pytest.skip('No SD/MMC card present')
+
+array = output.split()
+global devices
+global controllers
+controllers = int(len(array) / 2)
+for x in range(0, controllers):
+y = x * 2
+devices[x] = {}
+devices[x]['name'] = array[y]
+
+global mmc_set_up
+mmc_set_up = True
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_dev(u_boot_console):
+if not mmc_set_up:
+pytest.skip('No SD/MMC/eMMC controller available')
+
+fail = 0
+for x in range(0, controllers):
+devices[x]['detected'] = 'yes'
+output = u_boot_console.run_command('mmc dev %d' % x)
+
+# Some sort of switch here
+if 'Card did not respond to voltage select' in output:
+fail = 1
+devices[x]['detected'] = 'no'
+
+if 'no mmc device at slot' in output:
+devices[x]['detected'] = 'no'
+
+if 'MMC: no card present' in output:
+devices[x]['detected'] = 'no'
+
+if fail:
+pytest.fail('Card not present')
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmcinfo(u_boot_console):
+if not mmc_set_up:
+pytest.skip('No SD/MMC/eMMC controller available')
+
+for x in range(0, controllers):
+if devices[x]['detected'] == 'yes':
+u_boot_console.run_command('mmc dev %d' % x)
+output = u_boot_console.run_command('mmcinfo')
+if 'busy timeout' in output:
+pytest.skip('No SD/MMC/eMMC device present')
+
+obj = re.search(r'Capacity: (\d+|\d+[\.]?\d)', output)
+try:
+capacity = float(obj.groups()[0])
+print(capacity)
+devices[x]['capacity'] = capacity
+print('Capacity of dev %d is: %g GiB' % (x, capacity))
+except ValueError:
+pytest.fail('MMC capacity not recognized')
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_info(u_boot_console):
+if not mmc_set_up:
+pytest.skip('No SD/MMC/eMMC controller available')
+
+for x in range(0, controllers):
+if devices[x]['detected'] == 'yes':
+u_boot_console.run_command('mmc dev %d' % x)
+
+output = u_boot_console.run_command('mmc info')
+
+obj = re.search(r'Capacity: (\d+|\d+[\.]?\d)', output)
+try:
+capacity = float(obj.groups()[0])
+print(capacity)
+if devices[x]['capacity'] != capacity:
+pytest.fail("MMC capacity doesn't match mmcinfo")
+
+except ValueError:
+pytest.fail('MMC capacity not recogni

[PATCH] test/py: secure: Add secure tests for Zynq & ZynqMP

2024-01-19 Thread Love Kumar
Add test cases to verify the different type of secure boot images loaded
at DDR location for AMD's ZynqMP SoC. It also adds tests authentication
and decryption functionality using AES and RSA features for Zynq.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_zynq_secure.py   | 190 
 test/py/tests/test_zynqmp_secure.py | 104 +++
 2 files changed, 294 insertions(+)
 create mode 100644 test/py/tests/test_zynq_secure.py
 create mode 100644 test/py/tests/test_zynqmp_secure.py

diff --git a/test/py/tests/test_zynq_secure.py 
b/test/py/tests/test_zynq_secure.py
new file mode 100644
index ..0ee5aebc484a
--- /dev/null
+++ b/test/py/tests/test_zynq_secure.py
@@ -0,0 +1,190 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import re
+import u_boot_utils
+import test_net
+
+"""
+This test verifies different type of secure boot images to authentication and
+decryption using AES and RSA features for AMD's Zynq SoC.
+
+Note: This test relies on boardenv_* containing configuration values to define
+the network available and files to be used for testing. Without this, this test
+will be automatically skipped. It also relies on dhcp or setup_static net test
+to support tftp to load files from a TFTP server.
+
+For example:
+
+# Details regarding the files that may be read from a TFTP server and addresses
+# and size for aes and rsa cases respectively. This variable may be omitted or
+# set to None if zynqmp secure testing is not possible or desired.
+env__zynq_aes_readable_file = {
+'fn': 'zynq_aes_image.bin',
+'fnbit': 'zynq_aes_bit.bin',
+'fnpbit': 'zynq_aes_par_bit.bin',
+'srcaddr': 0x100,
+'dstaddr': 0x200,
+'dstlen': 0x100,
+}
+
+env__zynq_rsa_readable_file = {
+'fn': 'zynq_rsa_image.bin',
+'fninvalid': 'zynq_rsa_image_invalid.bin',
+'srcaddr': 0x100,
+}
+"""
+
+def zynq_secure_pre_commands(u_boot_console):
+output = u_boot_console.run_command('print modeboot')
+if not 'modeboot=' in output:
+pytest.skip('bootmode cannnot be determined')
+m = re.search('modeboot=(.+?)boot', output)
+if not m:
+pytest.skip('bootmode cannnot be determined')
+bootmode = m.group(1)
+if bootmode == 'jtag':
+pytest.skip('skipping due to jtag bootmode')
+
+@pytest.mark.buildconfigspec('cmd_zynq_aes')
+def test_zynq_aes_image(u_boot_console):
+f = u_boot_console.config.env.get('env__zynq_aes_readable_file', None)
+if not f:
+pytest.skip('No TFTP readable file for zynq secure aes case to read')
+
+dstaddr = f.get('dstaddr', None)
+if not dstaddr:
+pytest.skip('No dstaddr specified in env file to read')
+
+dstsize = f.get('dstlen', None)
+if not dstsize:
+pytest.skip('No dstlen specified in env file to read')
+
+zynq_secure_pre_commands(u_boot_console)
+test_net.test_net_dhcp(u_boot_console)
+if not test_net.net_set_up:
+test_net.test_net_setup_static(u_boot_console)
+
+srcaddr = f.get('srcaddr', None)
+if not srcaddr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+expected_tftp = 'Bytes transferred = '
+fn = f['fn']
+output = u_boot_console.run_command('tftpboot %x %s' % (srcaddr, fn))
+assert expected_tftp in output
+
+expected_op = 'zynq aes [operation type] '
+output = u_boot_console.run_command(
+'zynq aes %x $filesize %x %x' % (srcaddr, dstaddr, dstsize)
+)
+assert expected_op not in output
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+@pytest.mark.buildconfigspec('cmd_zynq_aes')
+def test_zynq_aes_bitstream(u_boot_console):
+f = u_boot_console.config.env.get('env__zynq_aes_readable_file', None)
+if not f:
+pytest.skip('No TFTP readable file for zynq secure aes case to read')
+
+zynq_secure_pre_commands(u_boot_console)
+test_net.test_net_dhcp(u_boot_console)
+if not test_net.net_set_up:
+test_net.test_net_setup_static(u_boot_console)
+
+srcaddr = f.get('srcaddr', None)
+if not srcaddr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+expected_tftp = 'Bytes transferred = '
+fn = f['fnbit']
+output = u_boot_console.run_command('tftpboot %x %s' % (srcaddr, fn))
+assert expected_tftp in output
+
+expected_op = 'zynq aes [operation type] '
+output = u_boot_console.run_command(
+'zyn

[PATCH] test/py: gpio: Add gpio pins generic test

2024-01-18 Thread Love Kumar
Add gpio pins generic test for the set of gpio pin list to test various
gpio related functionality, such as the input, set, clear, and toggle,
it also tests the input and output functionality for shorted gpio pins.
This test depends on boardenv* configuration to define gpio pins names.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_gpio.py | 90 ++
 1 file changed, 90 insertions(+)

diff --git a/test/py/tests/test_gpio.py b/test/py/tests/test_gpio.py
index 0af186f23602..3e16e6365743 100644
--- a/test/py/tests/test_gpio.py
+++ b/test/py/tests/test_gpio.py
@@ -85,6 +85,13 @@ env__gpio_dev_config = {
 'gpio_ip_pin_clear':'66',
 'gpio_clear_value': 'value is 0',
 'gpio_set_value': 'value is 1',
+# GPIO pin list to test gpio functionality for each pins, pin should be
+# pin names (str)
+'gpio_pin_list': ['gpio@131', 'gpio@132', 'gpio@2033'],
+# GPIO input output list for shorted gpio pins to test gpio
+# functionality for each of pairs, where the first element is
+# configured as input and second as output
+'gpio_ip_op_list': [['gpio0', 'gpio1'], ['gpio2', 'gpio3']],
 }
 """
 
@@ -223,3 +230,86 @@ def test_gpio_input_generic(u_boot_console):
 response = u_boot_console.run_command(cmd)
 good_response = gpio_set_value
 assert good_response in response
+
+@pytest.mark.buildconfigspec('cmd_gpio')
+def test_gpio_pins_generic(u_boot_console):
+"""Test various gpio related functionality, such as the input, set, clear,
+   and toggle for the set of gpio pin list.
+
+   Specific set of gpio pins (by mentioning gpio pin name) configured as
+   input (mentioned as 'gpio_pin_list') to be tested for multiple gpio
+   commands.
+"""
+
+f = u_boot_console.config.env.get('env__gpio_dev_config', False)
+if not f:
+pytest.skip('gpio not configured')
+
+gpio_pins = f.get('gpio_pin_list', None)
+if not gpio_pins:
+pytest.skip('gpio pin list are not configured')
+
+for gpin in gpio_pins:
+# gpio input
+u_boot_console.run_command(f'gpio input {gpin}')
+expected_response = f'{gpin}: input:'
+response = u_boot_console.run_command(f'gpio status -a {gpin}')
+assert expected_response in response
+
+# gpio set
+u_boot_console.run_command(f'gpio set {gpin}')
+expected_response = f'{gpin}: output: 1'
+response = u_boot_console.run_command(f'gpio status -a {gpin}')
+assert expected_response in response
+
+# gpio clear
+u_boot_console.run_command(f'gpio clear {gpin}')
+expected_response = f'{gpin}: output: 0'
+response = u_boot_console.run_command(f'gpio status -a {gpin}')
+assert expected_response in response
+
+# gpio toggle
+u_boot_console.run_command(f'gpio toggle {gpin}')
+expected_response = f'{gpin}: output: 1'
+response = u_boot_console.run_command(f'gpio status -a {gpin}')
+assert expected_response in response
+
+@pytest.mark.buildconfigspec('cmd_gpio')
+def test_gpio_pins_input_output_generic(u_boot_console):
+"""Test gpio related functionality such as input and output for the list of
+   shorted gpio pins provided as a pair of input and output pins. This test
+   will fail, if the gpio pins are not shorted properly.
+
+   Specific set of shorted gpio pins (by mentioning gpio pin name)
+   configured as input and output (mentioned as 'gpio_ip_op_list') as a
+   pair to be tested for gpio input output case.
+"""
+
+f = u_boot_console.config.env.get('env__gpio_dev_config', False)
+if not f:
+pytest.skip('gpio not configured')
+
+gpio_pins = f.get('gpio_ip_op_list', None)
+if not gpio_pins:
+pytest.skip('gpio pin list for input and output are not configured')
+
+for gpins in gpio_pins:
+u_boot_console.run_command(f'gpio input {gpins[0]}')
+expected_response = f'{gpins[0]}: input:'
+response = u_boot_console.run_command(f'gpio status -a {gpins[0]}')
+assert expected_response in response
+
+u_boot_console.run_command(f'gpio set {gpins[1]}')
+expected_response = f'{gpins[1]}: output:'
+response = u_boot_console.run_command(f'gpio status -a {gpins[1]}')
+assert expected_response in response
+
+u_boot_console.run_command(f'gpio clear {gpins[1]}')
+expected_response = f'{gpins[0]}: input: 0'
+response = u_boot_console.run_command(f'gpio status -a {gpins[0]}')
+assert expected_response in response
+
+u_boot_console.run_command(f'gpio set {gpins[1]}')
+expected_response = f'{gpins[0]}: input: 1'
+response = u_boot_console.run_command(f'gpio status -a {gpins[0]}')
+assert expected_response in response
-- 
2.25.1



[PATCH] test/py: zynqmp_rpu: Add test for loading RPU apps

2024-01-18 Thread Love Kumar
Add testcases for loading RPU applications in split and lockstep mode
including the negative one for AMD's ZynqMP SoC.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_zynqmp_rpu.py | 208 +++
 1 file changed, 208 insertions(+)
 create mode 100644 test/py/tests/test_zynqmp_rpu.py

diff --git a/test/py/tests/test_zynqmp_rpu.py b/test/py/tests/test_zynqmp_rpu.py
new file mode 100644
index ..479a612b4ec2
--- /dev/null
+++ b/test/py/tests/test_zynqmp_rpu.py
@@ -0,0 +1,208 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import string
+import test_net
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+RPU applications information for AMD's ZynqMP SoC which contains, application
+names, processors, address where it is built, expected output and the tftp load
+addresses. This test will be automatically skipped without this.
+
+It also relies on dhcp or setup_static net test to support tftp to load
+application on DDR. All the environment parameters are stored sequentially.
+The length of all parameters values should be same. For example, if 2 app_names
+are defined in a list as a value of parameter 'app_name' then the other
+parameters value also should have a list with 2 items.
+It will run RPU cases for all the applications defined in boardenv_*
+configuration file.
+
+Example:
+env__zynqmp_rpu_apps = {
+'app_name': ['hello_world_r5_0_ddr.elf', 'hello_world_r5_1_ddr.elf'],
+'proc': ['rpu0', 'rpu1'],
+'cpu_num': [4, 5],
+'addr': [0xA0, 0xB0],
+'output': ['Successfully ran Hello World application on DDR from RPU0',
+   'Successfully ran Hello World application on DDR from RPU1'],
+'tftp_addr': [0x10, 0x20],
+}
+"""
+
+# Get rpu apps params from env
+def get_rpu_apps_env(u_boot_console):
+rpu_apps = u_boot_console.config.env.get('env__zynqmp_rpu_apps', False)
+if not rpu_apps:
+pytest.skip('ZynqMP RPU application info not defined!')
+
+apps = rpu_apps.get('app_name', None)
+if not apps:
+pytest.skip('No RPU application found!')
+
+procs = rpu_apps.get('proc', None)
+if not procs:
+pytest.skip('No RPU application processor provided!')
+
+cpu_nums = rpu_apps.get('cpu_num', None)
+if not cpu_nums:
+pytest.skip('No CPU number for respective processor provided!')
+
+addrs = rpu_apps.get('addr', None)
+if not addrs:
+pytest.skip('No RPU application build address found!')
+
+outputs = rpu_apps.get('output', None)
+if not outputs:
+pytest.skip('Expected output not found!')
+
+tftp_addrs = rpu_apps.get('tftp_addr', None)
+if not tftp_addrs:
+pytest.skip('TFTP address to load application not found!')
+
+return apps, procs, cpu_nums, addrs, outputs, tftp_addrs
+
+# Check return code
+def ret_code(u_boot_console):
+return u_boot_console.run_command('echo $?')
+
+# Initialize tcm
+def tcminit(u_boot_console, rpu_mode):
+output = u_boot_console.run_command('zynqmp tcminit %s' % rpu_mode)
+assert 'Initializing TCM overwrites TCM content' in output
+return ret_code(u_boot_console)
+
+# Load application in DDR
+def load_app_ddr(u_boot_console, tftp_addr, app):
+output = u_boot_console.run_command('tftpboot %x %s' % (tftp_addr, app))
+assert 'TIMEOUT' not in output
+assert 'Bytes transferred = ' in output
+
+# Load elf
+u_boot_console.run_command('bootelf -p %x' % tftp_addr)
+assert ret_code(u_boot_console).endswith('0')
+
+# Disable cpus
+def disable_cpus(u_boot_console, cpu_nums):
+for num in cpu_nums:
+u_boot_console.run_command(f'cpu {num} disable')
+
+# Load apps on RPU cores
+def rpu_apps_load(u_boot_console, rpu_mode):
+apps, procs, cpu_nums, addrs, outputs, tftp_addrs = get_rpu_apps_env(
+u_boot_console)
+test_net.test_net_dhcp(u_boot_console)
+if not test_net.net_set_up:
+test_net.test_net_setup_static(u_boot_console)
+
+try:
+assert tcminit(u_boot_console, rpu_mode).endswith('0')
+
+for i in range(len(apps)):
+if rpu_mode == 'lockstep' and procs[i] != 'rpu0':
+continue
+
+load_app_ddr(u_boot_console, tftp_addrs[i], apps[i])
+rel_addr = int(addrs[i] + 0x3C)
+
+# Release cpu at app load address
+cpu_num = cpu_nums[i]
+cmd = 'cpu %d release %x %s' % (cpu_num, rel_addr, rpu_mode)
+ 

[PATCH v2] test/py: net_boot: Add test cases for net boot

2024-01-12 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.
This test relies on boardenv_* containing configuration values including
the parameter 'pattern'. tftpboot/pxe boot cases boots the Linux till the
boot log pattern value is matched. For example, if the parameter
'pattern' is defined as 'login:', it will boot till login prompt.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Expand commit message
---
 test/py/tests/test_net_boot.py | 371 +
 1 file changed, 371 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..a1faf0db281b
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,371 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+}
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+}
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlyprintk
+initrd initrds/uzInitrdDebInstall
+
+label local
+menu label Local boot
+append root=/dev/sdb1
+localboot 1
+
+label boot
+menu label Empty boot
+
+3) /tftpboot/pxelinux.cfg/default
+
+label Linux
+menu label Boot kernel
+kernel Image
+fdt system.dtb
+initrd rootfs.cpio.gz.u-boot
+"""
+
+def setup_tftpboot_boot(u_boot_console):
+f = u_boot_console.config.env.get('env__net_tftp_bootable_file', None)
+if not f:
+pytest.skip('No TFTP bootable file to read')
+
+test_net.test_net_dhcp(u_boot_console)
+test_net.test_net_setup_static(u_boot_console)
+
+addr = f.get('addr', None)
+if not addr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+fn = f['fn']
+output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
+expected_text = 'Bytes transferred = '
+sz = f.get('size', None)
+if sz:
+expected_text += '%d' % sz
+assert expected_text in output
+
+expected_crc = 

[PATCH] test/py: saveenv: Add a test for saveenv command

2024-01-11 Thread Love Kumar
Add test case for saveenv command in non-JTAG bootmode which saves the
u-boot environment variables in persistent storage.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_saveenv.py | 125 ++
 1 file changed, 125 insertions(+)
 create mode 100644 test/py/tests/test_saveenv.py

diff --git a/test/py/tests/test_saveenv.py b/test/py/tests/test_saveenv.py
new file mode 100644
index ..30d8148f8f3e
--- /dev/null
+++ b/test/py/tests/test_saveenv.py
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+# Setup env__saveenv_test_skip to True if saveenv test is not possible or
+# desired and should be skipped.
+env__saveenv_test_skip = True
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import re
+import random
+import ipaddress
+import string
+import uuid
+
+# Setup the env
+def setup_saveenv_env(u_boot_console):
+if u_boot_console.config.env.get('env__saveenv_test_skip', False):
+pytest.skip('saveenv test is not enabled')
+
+output = u_boot_console.run_command('print modeboot')
+m = re.search('modeboot=(.+?)boot', output)
+if not m:
+pytest.skip('bootmode cannnot be determined')
+
+bootmode = m.group(1)
+if bootmode == 'jtag':
+pytest.skip('skipping saveenv test due to jtag bootmode')
+
+# Check return code
+def ret_code(u_boot_console):
+return u_boot_console.run_command('echo $?')
+
+# Verify env variable
+def check_env(u_boot_console, var_name, var_value):
+if var_value:
+output = u_boot_console.run_command(f'printenv {var_name}')
+var_value = str(var_value)
+if (var_value.startswith("'") and var_value.endswith("'")) or (
+var_value.startswith('"') and var_value.endswith('"')
+):
+var_value = var_value.split(var_value[-1])[1]
+assert var_value in output
+assert ret_code(u_boot_console).endswith('0')
+else:
+u_boot_console.p.send(f'printenv {var_name}\n')
+output = u_boot_console.p.expect(['not defined'])
+assert output == 0
+assert ret_code(u_boot_console).endswith('1')
+
+# Set env variable
+def set_env(u_boot_console, var_name, var_value):
+u_boot_console.run_command(f'setenv {var_name} {var_value}')
+assert ret_code(u_boot_console).endswith('0')
+check_env(u_boot_console, var_name, var_value)
+
+@pytest.mark.buildconfigspec('cmd_saveenv')
+def test_saveenv(u_boot_console):
+"""Test the saveenv command in non-JTAG bootmode.
+It saves the U-Boot environment in persistent storage.
+"""
+setup_saveenv_env(u_boot_console)
+
+# Set env for random mac address
+rand_mac = '%02x:%02x:%02x:%02x:%02x:%02x' % (
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+random.randint(0, 255),
+)
+set_env(u_boot_console, 'mac_addr', rand_mac)
+
+# Set env for random IPv4 address
+rand_ipv4 = ipaddress.IPv4Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv4Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv4_addr', rand_ipv4)
+
+# Set env for random IPv6 address
+rand_ipv6 = ipaddress.IPv6Address._string_from_ip_int(
+random.randint(0, ipaddress.IPv6Address._ALL_ONES)
+)
+set_env(u_boot_console, 'ipv6_addr', rand_ipv6)
+
+# Set env for random number
+rand_num = random.randrange(1, 10**9)
+set_env(u_boot_console, 'num_var', rand_num)
+
+# Set env for uuid
+uuid_str = uuid.uuid4().hex.lower()
+set_env(u_boot_console, 'uuid_var', uuid_str)
+
+# Set env for random string including special characters
+sc = "!#%&\()*+,-./:;<=>?@[\\]^_`{|}~"
+rand_str = ''.join(
+random.choices(' ' + string.ascii_letters + sc + string.digits, k=300)
+)
+set_env(u_boot_console, 'str_var', f'"{rand_str}"')
+
+# Set env for empty string
+set_env(u_boot_console, 'empty_var', '')
+
+# Save the env variables
+u_boot_console.run_command('saveenv')
+assert ret_code(u_boot_console).endswith('0')
+
+# Reboot
+u_boot_console.run_command('reset', wait_for_reboot=True)
+
+# Verify the saved env variables
+check_env(u_boot_console, 'mac_addr', rand_mac)
+check_env(u_boot_console, 'ipv4_addr', rand_ipv4)
+check_env(u_boot_console, 'ipv6_addr', rand_ipv6)
+check_env(u_boot_console, 'num_var', rand_num)
+check_env(u_boot_console, 'uuid_var', uuid_str)
+check_env(u_boot_console, 'str_var', rand_str)
+check_env(u_boot_console, 'empty_var', '')
-- 
2.25.1



[PATCH] test/py: reset: Add a test for reset command

2024-01-10 Thread Love Kumar
Add a test for reset commands which performs resetting of CPU, It does
COLD reset by default and WARM reset with -w option.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_reset.py | 50 +
 1 file changed, 50 insertions(+)
 create mode 100644 test/py/tests/test_reset.py

diff --git a/test/py/tests/test_reset.py b/test/py/tests/test_reset.py
new file mode 100644
index ..896918cd8baf
--- /dev/null
+++ b/test/py/tests/test_reset.py
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+# Setup env__reset_test_skip to True if reset test is not possible or desired
+# and should be skipped.
+env__reset_test_skip = True
+
+# This test will be also skipped if the bootmode is detected to JTAG.
+"""
+
+import pytest
+import re
+import test_000_version
+
+def setup_reset_env(u_boot_console):
+if u_boot_console.config.env.get('env__reset_test_skip', False):
+pytest.skip('reset test is not enabled')
+
+output = u_boot_console.run_command('print modeboot')
+m = re.search('modeboot=(.+?)boot', output)
+if not m:
+pytest.skip('bootmode cannnot be determined')
+
+bootmode = m.group(1)
+if bootmode == 'jtag':
+pytest.skip('skipping reset test due to jtag bootmode')
+
+def test_reset(u_boot_console):
+"""Test the reset command in non-JTAG bootmode.
+It does COLD reset, which resets CPU, DDR and peripherals
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
+
+def test_reset_w(u_boot_console):
+"""Test the reset -w command in non-JTAG bootmode.
+It does WARM reset, which resets CPU but keep DDR/peripherals active.
+"""
+setup_reset_env(u_boot_console)
+u_boot_console.run_command('reset -w', wait_for_reboot=True)
+
+# Checks the u-boot command prompt's functionality after reset
+test_000_version.test_version(u_boot_console)
-- 
2.25.1



[PATCH] test/py: bootstage: Add test for bootstage command

2024-01-09 Thread Love Kumar
Add test cases for bootstage command to print the bootstage report, to
stash the data into memory and to unstash the data from memory.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_bootstage.py | 67 +
 1 file changed, 67 insertions(+)
 create mode 100644 test/py/tests/test_bootstage.py

diff --git a/test/py/tests/test_bootstage.py b/test/py/tests/test_bootstage.py
new file mode 100644
index ..a9eb9f0b4a11
--- /dev/null
+++ b/test/py/tests/test_bootstage.py
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+
+"""
+Test the bootstage command.
+
+It is used for checking the boot progress and timing by printing the bootstage
+report, stashes the data into memory and unstashes the data from memory.
+
+Note: This test relies on boardenv_* containing configuration values to define
+the data size, memory address, and bootstage magic address (defined in
+common/bootstage.c). Without this, bootstage stash and unstash tests will be
+automatically skipped.
+
+For example:
+env__bootstage_cmd_file = {
+'addr': 0x20,
+'size': 0x1000,
+'bootstage_magic_addr': 0xb00757a3,
+}
+"""
+
+@pytest.mark.buildconfigspec('bootstage')
+@pytest.mark.buildconfigspec('cmd_bootstage')
+def test_bootstage_report(u_boot_console):
+output = u_boot_console.run_command('bootstage report')
+assert 'Timer summary in microseconds' in output
+assert 'Accumulated time:' in output
+assert 'dm_r' in output
+
+@pytest.mark.buildconfigspec('bootstage')
+@pytest.mark.buildconfigspec('cmd_bootstage')
+@pytest.mark.buildconfigspec('bootstage_stash')
+def test_bootstage_stash(u_boot_console):
+f = u_boot_console.config.env.get('env__bootstage_cmd_file', None)
+if not f:
+pytest.skip('No bootstage environment file is defined')
+
+addr = f.get('addr')
+size = f.get('size')
+bootstage_magic = f.get('bootstage_magic_addr')
+expected_text = 'dm_r'
+
+u_boot_console.run_command('bootstage stash %x %x' % (addr, size))
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
+
+output = u_boot_console.run_command('md %x 100' % addr)
+
+# Check BOOTSTAGE_MAGIC address at 4th byte address
+assert '0x' + output.split('\n')[0].split()[4] == hex(bootstage_magic)
+
+# Check expected string in last column of output
+output_last_col = ''.join([i.split()[-1] for i in output.split('\n')])
+assert expected_text in output_last_col
+return addr, size
+
+@pytest.mark.buildconfigspec('bootstage')
+@pytest.mark.buildconfigspec('cmd_bootstage')
+@pytest.mark.buildconfigspec('bootstage_stash')
+def test_bootstage_unstash(u_boot_console):
+addr, size = test_bootstage_stash(u_boot_console)
+u_boot_console.run_command('bootstage unstash %x %x' % (addr, size))
+output = u_boot_console.run_command('echo $?')
+assert output.endswith('0')
-- 
2.25.1



[PATCH] test/py: net_boot: Add test cases for net boot

2024-01-08 Thread Love Kumar
Add tests for booting image using tftpboot/pxe boot commands, tftpboot
boot case loads the FIT image into DDR and boots using bootm command
whereas pxe boot cases downloads the pxe configuration file from the
TFTP server and interprets it to boot the images mentioned in the pxe
configurations file.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_net_boot.py | 371 +
 1 file changed, 371 insertions(+)
 create mode 100644 test/py/tests/test_net_boot.py

diff --git a/test/py/tests/test_net_boot.py b/test/py/tests/test_net_boot.py
new file mode 100644
index ..a1faf0db281b
--- /dev/null
+++ b/test/py/tests/test_net_boot.py
@@ -0,0 +1,371 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import u_boot_utils
+import test_net
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which the network environment available for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# Details regarding a boot image file that may be read from a TFTP server. This
+# variable may be omitted or set to None if TFTP boot testing is not possible
+# or desired.
+env__net_tftp_bootable_file = {
+'fn': 'image.ub',
+'addr': 0x1000,
+'size': 5058624,
+'crc32': 'c2244b26',
+'pattern': 'Linux',
+'config': 'config@2',
+'timeout': 5,
+}
+
+# Here is the example of FIT image configurations:
+configurations {
+default = "config@1";
+config@1 {
+description = "Boot Linux kernel with config@1";
+kernel = "kernel@0";
+fdt = "fdt@0";
+ramdisk = "ramdisk@0";
+hash@1 {
+algo = "sha1";
+};
+};
+config@2 {
+description = "Boot Linux kernel with config@2";
+kernel = "kernel@1";
+fdt = "fdt@1";
+ramdisk = "ramdisk@1";
+hash@1 {
+algo = "sha1";
+};
+};
+};
+
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_bootable_file = {
+'fn': 'default',
+'addr': 0x1000,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+'valid_label': '1',
+'invalid_label': '2',
+'exp_str_invalid': 'Skipping install for failure retrieving',
+'local_label': '3',
+'exp_str_local': 'missing environment variable: localcmd',
+'empty_label': '4',
+'exp_str_empty': 'No kernel given, skipping boot',
+}
+
+# Here is the example of pxe configuration file ordered based on the execution
+# flow:
+1) /tftpboot/pxelinux.cfg/default-arm-zynqmp
+
+menu include pxelinux.cfg/default-arm
+timeout 50
+
+default Linux
+
+2) /tftpboot/pxelinux.cfg/default-arm
+
+menu title Linux boot selections
+menu include pxelinux.cfg/default
+
+label install
+menu label Invalid boot
+kernel kernels/install.bin
+append console=ttyAMA0,38400 debug earlyprintk
+initrd initrds/uzInitrdDebInstall
+
+label local
+menu label Local boot
+append root=/dev/sdb1
+localboot 1
+
+label boot
+menu label Empty boot
+
+3) /tftpboot/pxelinux.cfg/default
+
+label Linux
+menu label Boot kernel
+kernel Image
+fdt system.dtb
+initrd rootfs.cpio.gz.u-boot
+"""
+
+def setup_tftpboot_boot(u_boot_console):
+f = u_boot_console.config.env.get('env__net_tftp_bootable_file', None)
+if not f:
+pytest.skip('No TFTP bootable file to read')
+
+test_net.test_net_dhcp(u_boot_console)
+test_net.test_net_setup_static(u_boot_console)
+
+addr = f.get('addr', None)
+if not addr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+fn = f['fn']
+output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
+expected_text = 'Bytes transferred = '
+sz = f.get('size', None)
+if sz:
+expected_text += '%d' % sz
+assert expected_text in output
+
+expected_crc = f.get('crc32', None)
+output = u_boot_console.run_command('crc32 %x $filesize' % addr)
+if expected_crc:
+assert expected_crc in output
+
+pattern = f.get('pattern')
+config = f.get('config', None)
+timeout = f.get('timeout', 5)
+
+return addr, pattern, ti

[PATCH] test/py: memtest: Add tests for mtest command

2024-01-03 Thread Love Kumar
Add the following memory tests:
memtest_negative - To test mtest command by providing incorrect inputs
memtest_ddr - To test memory write-read-comparision for DDR memory

Signed-off-by: Love Kumar 
---
 test/py/tests/test_memtest.py | 68 +++
 1 file changed, 68 insertions(+)
 create mode 100644 test/py/tests/test_memtest.py

diff --git a/test/py/tests/test_memtest.py b/test/py/tests/test_memtest.py
new file mode 100644
index ..0618d96f1bed
--- /dev/null
+++ b/test/py/tests/test_memtest.py
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the memory test parameters such as start address, memory size, pattern,
+iterations and timeout. This test will be automatically skipped without this.
+
+For example:
+
+# Setup env__memtest to set the start address of the memory range, size of the
+# memory range to test from starting address, pattern to be written to memory,
+# number of test iterations, and expected time to complete the test of mtest
+# command. start address, size, and pattern parameters value should be in hex
+# and rest of the params value should be integer.
+env__memtest = {
+'start_addr': 0x0,
+'size': 0x1000,
+'pattern': 0x0,
+'iteration': 16,
+'timeout': 5,
+}
+"""
+
+def get_memtest_env(u_boot_console):
+f = u_boot_console.config.env.get("env__memtest", None)
+if not f:
+pytest.skip("memtest is not enabled!")
+else:
+start = f.get("start_addr", 0x0)
+size = f.get("size", 0x1000)
+pattern = f.get("pattern", 0x0)
+iteration = f.get("iteration", 2)
+timeout = f.get("timeout", 5)
+end = hex(int(start) + int(size))
+return start, end, pattern, iteration, timeout
+
+@pytest.mark.buildconfigspec("cmd_memtest")
+def test_memtest_negative(u_boot_console):
+"""Negative testcase where end address is smaller than starting address and
+pattern is invalid."""
+start, end, pattern, iteration, timeout = get_memtest_env(u_boot_console)
+expected_response = "Refusing to do empty test"
+response = u_boot_console.run_command(
+f"mtest 2000 1000 {pattern} {hex(iteration)}"
+)
+assert expected_response in response
+output = u_boot_console.run_command("echo $?")
+assert not output.endswith("0")
+u_boot_console.run_command(f"mtest {start} {end} 'xyz' {hex(iteration)}")
+output = u_boot_console.run_command("echo $?")
+assert not output.endswith("0")
+
+@pytest.mark.buildconfigspec("cmd_memtest")
+def test_memtest_ddr(u_boot_console):
+"""Test that md reads memory as expected, and that memory can be modified
+using the mw command."""
+start, end, pattern, iteration, timeout = get_memtest_env(u_boot_console)
+expected_response = f"Tested {str(iteration)} iteration(s) with 0 errors."
+with u_boot_console.temporary_timeout(timeout):
+response = u_boot_console.run_command(
+f"mtest {start} {end} {pattern} {hex(iteration)}"
+)
+assert expected_response in response
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
-- 
2.25.1



[PATCH v3] test/py: i2c: Add tests for i2c command

2024-01-01 Thread Love Kumar
Add below test cases for i2c commands:
i2c_bus - To show i2c bus info,
i2c_dev - To set or show the current bus,
i2c_probe - To probe the i2c device,
i2c_eeprom - To test i2c eeprom device,
i2c_probe_all_buses - To list down all the buses and probes it

Signed-off-by: Love Kumar 
---
Changes in v2:
- Take the configured eeprom value from env to read back and compare
Changes in v3:
- Add test env dependency to run it for provided i2c bus list
---
 test/py/tests/test_i2c.py | 116 ++
 1 file changed, 116 insertions(+)
 create mode 100644 test/py/tests/test_i2c.py

diff --git a/test/py/tests/test_i2c.py b/test/py/tests/test_i2c.py
new file mode 100644
index ..825d0c2e6eb7
--- /dev/null
+++ b/test/py/tests/test_i2c.py
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the i2c device info including the bus list and eeprom address/value. This test
+will be automatically skipped without this.
+
+For example:
+
+# Setup env__i2c_device_test to set the i2c bus list and probe_all boolean
+# parameter. For i2c_probe_all_buses case, if probe_all parameter is set to
+# False then it probes all the buses listed in bus_list instead of probing all
+# the buses available.
+env__i2c_device_test = {
+'bus_list': [0, 2, 5, 12, 16, 18],
+'probe_all': False,
+}
+
+# Setup env__i2c_eeprom_device_test to set the i2c bus number, eeprom address
+# and configured value for i2c_eeprom test case. Test will be skipped if
+# env__i2c_eeprom_device_test is not set
+env__i2c_eeprom_device_test = {
+'bus': 3,
+'eeprom_addr': 0x54,
+'eeprom_val': '30 31',
+}
+"""
+
+def get_i2c_test_env(u_boot_console):
+f = u_boot_console.config.env.get("env__i2c_device_test", None)
+if not f:
+pytest.skip("No I2C device to test!")
+else:
+bus_list = f.get("bus_list", None)
+if not bus_list:
+pytest.skip("I2C bus list is not provided!")
+probe_all = f.get("probe_all", False)
+return bus_list, probe_all
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_bus(u_boot_console):
+bus_list, probe = get_i2c_test_env(u_boot_console)
+bus = random.choice(bus_list)
+expected_response = f"Bus {bus}:"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_dev(u_boot_console):
+bus_list, probe = get_i2c_test_env(u_boot_console)
+expected_response = "Current bus is"
+response = u_boot_console.run_command("i2c dev")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe(u_boot_console):
+bus_list, probe = get_i2c_test_env(u_boot_console)
+bus = random.choice(bus_list)
+expected_response = f"Setting bus to {bus}"
+response = u_boot_console.run_command(f"i2c dev {bus}")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_eeprom(u_boot_console):
+f = u_boot_console.config.env.get("env__i2c_eeprom_device_test", None)
+if not f:
+pytest.skip("No I2C eeprom to test!")
+
+bus = f.get("bus", 0)
+if bus < 0:
+pytest.fail("No bus specified via env__i2c_eeprom_device_test!")
+
+addr = f.get("eeprom_addr", -1)
+if addr < 0:
+pytest.fail("No eeprom address specified via 
env__i2c_eeprom_device_test!")
+
+value = f.get("eeprom_val")
+if not value:
+pytest.fail(
+"No eeprom configured value provided via 
env__i2c_eeprom_device_test!"
+)
+
+# Enable i2c mux bridge
+u_boot_console.run_command("i2c dev %x" % bus)
+u_boot_console.run_command("i2c probe")
+output = u_boot_console.run_command("i2c md %x 0 5" % addr)
+assert value in output
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe_all_buses(u_boot_console):
+bus_list, probe = get_i2c_test_env(u_boot_console)
+bus = random.choice(bus_list)
+expected_response = f"Bus {bus}:"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+# Get all the bus list
+if probe:
+buses = re.findall("Bus (.+?):", response)
+bus_list = [int(x) for x in buses]
+
+for dev in bus_list:
+expected_response = f"Setting bus to {dev}"
+response = u_boot_console.run_command(f"i2c dev {dev}")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
-- 
2.25.1



[PATCH v3] test/py: mii: Add tests for mii command

2024-01-01 Thread Love Kumar
Add below test cases for mii commands:
mii_info -To display MII PHY info
mii_list - To list MII devices
mii_set_device - To set MII device
mii_read - To reads register from MII PHY address
mii_dump - To display data from MII PHY address

Signed-off-by: Love Kumar 
---
Changes in v2:
- Get MII device list from env instead of auto-detecting it
- Set the MII device to its current device after testing so that it
won't impact next cases
Changes in v3:
 - Use single quote in env to maintain consistency
---
 test/py/tests/test_mii.py | 92 +++
 1 file changed, 92 insertions(+)
 create mode 100644 test/py/tests/test_mii.py

diff --git a/test/py/tests/test_mii.py b/test/py/tests/test_mii.py
new file mode 100644
index ..7b6816d1089e
--- /dev/null
+++ b/test/py/tests/test_mii.py
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import re
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__mii_deive_test_skip to True if tests with ethernet PHY devices
+# should be skipped. For example: Missing PHY device
+env__mii_device_test_skip = True
+
+# Setup env__mii_device_test to set the MII device names. Test will be skipped
+# if env_mii_device_test is not set
+env__mii_device_test = {
+'device_list': ['eth0', 'eth1'],
+}
+"""
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_info(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+expected_output = "PHY"
+output = u_boot_console.run_command("mii info")
+if not re.search(r"PHY (.+?):", output):
+pytest.skip("PHY device does not exist!")
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_list(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+
+f = u_boot_console.config.env.get("env__mii_device_test", None)
+if not f:
+pytest.skip("No MII device to test!")
+
+dev_list = f.get("device_list")
+if not dev_list:
+pytest.fail("No MII device list provided via env__mii_device_test!")
+
+expected_output = "Current device"
+output = u_boot_console.run_command("mii device")
+mii_devices = (
+re.search(r"MII devices: '(.+)'", output).groups()[0].replace("'", 
"").split()
+)
+
+assert len([x for x in dev_list if x in mii_devices]) == len(dev_list)
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_set_device(u_boot_console):
+test_mii_list(u_boot_console)
+f = u_boot_console.config.env.get("env__mii_device_test", None)
+dev_list = f.get("device_list")
+output = u_boot_console.run_command("mii device")
+current_dev = re.search(r"Current device: '(.+?)'", output).groups()[0]
+
+for dev in dev_list:
+u_boot_console.run_command(f"mii device {dev}")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+u_boot_console.run_command(f"mii device {current_dev}")
+output = u_boot_console.run_command("mii device")
+dev = re.search(r"Current device: '(.+?)'", output).groups()[0]
+assert current_dev == dev
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_read(u_boot_console):
+test_mii_list(u_boot_console)
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii read {eth_addr} 0")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_dump(u_boot_console):
+test_mii_list(u_boot_console)
+expected_response = "PHY control register"
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+response = u_boot_console.run_command(f"mii dump {eth_addr} 0")
+assert expected_response in response
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
-- 
2.25.1



[PATCH] test/py: mdio: Add tests for mdio command

2023-12-19 Thread Love Kumar
Add below test cases for mdio commands:
mdio_list - To list MDIO buses
mdio_read - To read PHY's register at .
mdio_write - To write PHY's register at .

Signed-off-by: Love Kumar 
---
 test/py/tests/test_mdio.py | 79 ++
 1 file changed, 79 insertions(+)
 create mode 100644 test/py/tests/test_mdio.py

diff --git a/test/py/tests/test_mdio.py b/test/py/tests/test_mdio.py
new file mode 100644
index ..89711e70b559
--- /dev/null
+++ b/test/py/tests/test_mdio.py
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import re
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the PHY device info including the device name, address, register address/value
+and write data value. This test will be automatically skipped without this.
+
+For example:
+
+# Setup env__mdio_util_test to set the PHY address, device names, register
+# address, register address value, and write data value to test mdio commands.
+# Test will be skipped if env_mdio_util_test is not set
+env__mdio_util_test = {
+"eth0": {"phy_addr": 0xc, "device_name": "TI DP83867", "reg": 0,
+ "reg_val": 0x1000, "write_val": 0x100},
+"eth1": {"phy_addr": 0xa0, "device_name": "TI DP83867", "reg": 1,
+ "reg_val": 0x2000, "write_val": 0x100},
+}
+"""
+
+def get_mdio_test_env(u_boot_console):
+f = u_boot_console.config.env.get("env__mdio_util_test", None)
+if not f or len(f) == 0:
+pytest.skip("No PHY device to test!")
+else:
+return f
+
+@pytest.mark.buildconfigspec("cmd_mii")
+@pytest.mark.buildconfigspec("phylib")
+def test_mdio_list(u_boot_console):
+f = get_mdio_test_env(u_boot_console)
+output = u_boot_console.run_command("mdio list")
+for dev, val in f.items():
+phy_addr = val.get("phy_addr")
+dev_name = val.get("device_name")
+
+assert f"{phy_addr:x} -" in output
+assert dev_name in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+@pytest.mark.buildconfigspec("phylib")
+def test_mdio_read(u_boot_console):
+f = get_mdio_test_env(u_boot_console)
+output = u_boot_console.run_command("mdio list")
+for dev, val in f.items():
+phy_addr = hex(val.get("phy_addr"))
+dev_name = val.get("device_name")
+reg = hex(val.get("reg"))
+reg_val = hex(val.get("reg_val"))
+
+output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}")
+assert f"PHY at address {int(phy_addr, 16):x}:" in output
+assert f"{int(reg, 16):x} - {reg_val}" in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+@pytest.mark.buildconfigspec("phylib")
+def test_mdio_write(u_boot_console):
+f = get_mdio_test_env(u_boot_console)
+output = u_boot_console.run_command("mdio list")
+for dev, val in f.items():
+phy_addr = hex(val.get("phy_addr"))
+dev_name = val.get("device_name")
+reg = hex(val.get("reg"))
+reg_val = hex(val.get("reg_val"))
+wr_val = hex(val.get("write_val"))
+
+u_boot_console.run_command(f"mdio write {phy_addr} {reg} {wr_val}")
+output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}")
+assert f"PHY at address {int(phy_addr, 16):x}:" in output
+assert f"{int(reg, 16):x} - {wr_val}" in output
+
+u_boot_console.run_command(f"mdio write {phy_addr} {reg} {reg_val}")
+output = u_boot_console.run_command(f"mdio read {phy_addr} {reg}")
+assert f"PHY at address {int(phy_addr, 16):x}:" in output
+assert f"{int(reg, 16):x} - {reg_val}" in output
-- 
2.25.1



[PATCH v2] test/py: mii: Add tests for mii command

2023-12-05 Thread Love Kumar
Add below test cases for mii commands:
mii_info -To display MII PHY info
mii_list - To list MII devices
mii_set_device - To set MII device
mii_read - To reads register from MII PHY address
mii_dump - To display data from MII PHY address

Signed-off-by: Love Kumar 
---
Changes in v2:
  - Get MII device list from env instead of auto-detecting it
  - Set the MII device to its current device after testing so that it
  won't impact next cases
---
 test/py/tests/test_mii.py | 92 +++
 1 file changed, 92 insertions(+)
 create mode 100644 test/py/tests/test_mii.py

diff --git a/test/py/tests/test_mii.py b/test/py/tests/test_mii.py
new file mode 100644
index ..e9bdbadffc8e
--- /dev/null
+++ b/test/py/tests/test_mii.py
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import re
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__mii_deive_test_skip to True if tests with ethernet PHY devices
+# should be skipped. For example: Missing PHY device
+env__mii_device_test_skip = True
+
+# Setup env__mii_device_test to set the MII device names. Test will be skipped
+# if env_mii_device_test is not set
+env__mii_device_test = {
+"device_list": ["eth0", "eth1"],
+}
+"""
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_info(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+expected_output = "PHY"
+output = u_boot_console.run_command("mii info")
+if not re.search(r"PHY (.+?):", output):
+pytest.skip("PHY device does not exist!")
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_list(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+
+f = u_boot_console.config.env.get("env__mii_device_test", None)
+if not f:
+pytest.skip("No MII device to test!")
+
+dev_list = f.get("device_list")
+if len(dev_list) == 0:
+pytest.fail("No MII device list provided via env__mii_device_test!")
+
+expected_output = "Current device"
+output = u_boot_console.run_command("mii device")
+mii_devices = (
+re.search(r"MII devices: '(.+)'", output).groups()[0].replace("'", 
"").split()
+)
+
+assert len([x for x in dev_list if x in mii_devices]) == len(dev_list)
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_set_device(u_boot_console):
+test_mii_list(u_boot_console)
+f = u_boot_console.config.env.get("env__mii_device_test", None)
+dev_list = f.get("device_list")
+output = u_boot_console.run_command("mii device")
+current_dev = re.search(r"Current device: '(.+?)'", output).groups()[0]
+
+for dev in dev_list:
+u_boot_console.run_command(f"mii device {dev}")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+u_boot_console.run_command(f"mii device {current_dev}")
+output = u_boot_console.run_command("mii device")
+dev = re.search(r"Current device: '(.+?)'", output).groups()[0]
+assert current_dev == dev
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_read(u_boot_console):
+test_mii_list(u_boot_console)
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii read {eth_addr} 0")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_dump(u_boot_console):
+test_mii_list(u_boot_console)
+expected_response = "PHY control register"
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+response = u_boot_console.run_command(f"mii dump {eth_addr} 0")
+assert expected_response in response
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
-- 
2.25.1



[UBOOT PATCH v4] test/py: net: Add dhcp abort test

2023-11-21 Thread Love Kumar
Abort the dhcp request in the middle by pressing ctrl + c on u-boot
prompt and validate the abort status.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Mark CMD_MII command dependency

Changes in v3:
 - Skip the test if PHY device not present

Changes in v4:
 - Setup the network configuration by running dhcp test at the end of
 test
 - Add option to skip the test if it is not desired or possible
---
 test/py/tests/test_net.py | 57 +++
 1 file changed, 57 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index b2241ae6a482..e0749125fd53 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -7,6 +7,7 @@
 import pytest
 import u_boot_utils
 import uuid
+import re
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -30,6 +31,11 @@ env__net_uses_pci = True
 # set to False.
 env__net_dhcp_server = True
 
+# False or omitted if a DHCP server is attached to the network, and dhcp abort
+# case should be tested.
+# If DHCP abort testing is not possible or desired, set this variable to True.
+env__dhcp_abort_test_skip = True
+
 # True if a DHCPv6 server is attached to the network, and should be tested.
 # If DHCPv6 testing is not possible or desired, this variable may be omitted or
 # set to False.
@@ -115,6 +121,57 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec("cmd_dhcp")
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_net_dhcp_abort(u_boot_console):
+"""Test the dhcp command by pressing ctrl+c in the middle of dhcp request
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp = u_boot_console.config.env.get("env__net_dhcp_server", False)
+if not test_dhcp:
+pytest.skip("No DHCP server available")
+
+if u_boot_console.config.env.get("env__dhcp_abort_test_skip", False):
+pytest.skip("DHCP abort test is not enabled!")
+
+u_boot_console.run_command("setenv autoload no")
+
+# Phy reset before running dhcp command
+output = u_boot_console.run_command("mii device")
+if not re.search(r"Current device: '(.+?)'", output):
+pytest.skip("PHY device does not exist!")
+eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f"mii device {eth_num}")
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii modify {eth_addr} 0 0x8000 0x8000")
+
+u_boot_console.run_command("dhcp", wait_for_prompt=False)
+try:
+u_boot_console.wait_for("Waiting for PHY auto negotiation to complete")
+except:
+pytest.skip("Timeout waiting for PHY auto negotiation to complete")
+
+u_boot_console.wait_for("done")
+
+# Sending Ctrl-C
+output = u_boot_console.run_command(
+chr(3), wait_for_echo=False, send_nl=False
+)
+
+assert "TIMEOUT" not in output
+assert "DHCP client bound to address " not in output
+assert "Abort" in output
+
+# Provide a time to recover from Abort - if it is not performed
+# There is message like: ethernet@ff0e: No link.
+u_boot_console.run_command("sleep 1")
+# Run the dhcp test to setup the network configuration
+test_net_dhcp(u_boot_console)
+
 @pytest.mark.buildconfigspec('cmd_dhcp6')
 def test_net_dhcp6(u_boot_console):
 """Test the dhcp6 command.
-- 
2.25.1



[PATCH v2] test/py: i2c: Add tests for i2c command

2023-11-21 Thread Love Kumar
Add below test cases for i2c commands:
i2c_bus - To show i2c bus info,
i2c_dev - To set or show the current bus,
i2c_probe - To probe the i2c device,
i2c_eeprom - To test i2c eeprom device,
i2c_probe_all_buses - To list down all the buses and probes it

Signed-off-by: Love Kumar 
---
Changes in v2:
- Take the configured eeprom value from env to read back and compare
---
 test/py/tests/test_i2c.py | 108 ++
 1 file changed, 108 insertions(+)
 create mode 100644 test/py/tests/test_i2c.py

diff --git a/test/py/tests/test_i2c.py b/test/py/tests/test_i2c.py
new file mode 100644
index ..75321ee2fc20
--- /dev/null
+++ b/test/py/tests/test_i2c.py
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__i2c_device_test_skip to True if tests with i2c devices should be
+# skipped. For example: Missing QEMU model or broken i2c device
+env__i2c_device_test_skip = True
+
+# Setup env__i2c_eeprom_device_test to set the i2c bus number, eeprom address
+# and configured value for i2c_eeprom test case. Test will be skipped if
+# env__i2c_eeprom_device_test is not set
+env__i2c_eeprom_device_test = {
+"bus": 3,
+"eeprom_addr": 0x54,
+"eeprom_val": "30 31",
+}
+
+# Setup env__i2c_device_test to provide the i2c bus list to test against it
+# for i2c_probe_all_buses case instead of probing all the buses available. If
+# it is not set, it list down all the buses and probes it
+env__i2c_device_test = {
+"bus_list": [0, 2, 5, 12, 16, 18]
+}
+"""
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_bus(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Bus"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_dev(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Current bus"
+response = u_boot_console.run_command("i2c dev")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Setting bus to 0"
+response = u_boot_console.run_command("i2c dev 0")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_eeprom(u_boot_console):
+f = u_boot_console.config.env.get("env__i2c_eeprom_device_test", None)
+if not f:
+pytest.skip("No I2C eeprom to test!")
+
+bus = f.get("bus", 0)
+if bus < 0:
+pytest.fail("No bus specified via env__i2c_eeprom_device_test!")
+
+addr = f.get("eeprom_addr", -1)
+if addr < 0:
+pytest.fail("No eeprom address specified via 
env__i2c_eeprom_device_test!")
+
+value = f.get("eeprom_val")
+if not value:
+pytest.fail("No eeprom configured value provided via 
env__i2c_eeprom_device_test!")
+
+# Enable i2c mux bridge
+u_boot_console.run_command("i2c dev %x" % bus)
+u_boot_console.run_command("i2c probe")
+output = u_boot_console.run_command("i2c md %x 0 5" % addr)
+assert value in output
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe_all_buses(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Bus"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+# Get all the bus list
+f = u_boot_console.config.env.get("env__i2c_device_test", None)
+if f:
+bus_list = f.get("bus_list")
+else:
+buses = re.findall("Bus (.+?):", response)
+bus_list = [int(x) for x in buses]
+
+for dev in bus_list:
+expected_response = f"Setting bus to {dev}"
+response = u_boot_console.run_command(f"i2c dev {dev}")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
-- 
2.25.1



[PATCH] test/py: mii: Add tests for mii command

2023-11-21 Thread Love Kumar
Add below test cases for mii commands:
mii_info -To display MII PHY info
mii_list - To list MII devices
mii_set_device - To set MII device
mii_read - To reads register from MII PHY address
mii_dump - To display data from MII PHY address

Signed-off-by: Love Kumar 
---
 test/py/tests/test_mii.py | 68 +++
 1 file changed, 68 insertions(+)
 create mode 100644 test/py/tests/test_mii.py

diff --git a/test/py/tests/test_mii.py b/test/py/tests/test_mii.py
new file mode 100644
index ..b213df3e3f2e
--- /dev/null
+++ b/test/py/tests/test_mii.py
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import re
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__mii_deive_test_skip to True if tests with ethernet PHY devices
+# should be skipped. For example: Missing PHY device
+env__mii_device_test_skip = True
+
+It also checks for MII PHY device exist or not, it skips the test if PHY device
+does not exist.
+"""
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_info(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+expected_output = "PHY"
+output = u_boot_console.run_command("mii info")
+if not re.search(r"PHY (.+?):", output):
+pytest.skip("PHY device does not exist!")
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_list(u_boot_console):
+if u_boot_console.config.env.get("env__mii_device_test_skip", False):
+pytest.skip("MII device test is not enabled!")
+expected_output = "Current device"
+output = u_boot_console.run_command("mii device")
+if not re.search(r"Current device: '(.+?)'", output):
+pytest.skip("PHY device does not exist!")
+assert expected_output in output
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_set_device(u_boot_console):
+test_mii_list(u_boot_console)
+output = u_boot_console.run_command("mii device")
+eth_num = re.search(r"MII devices: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f"mii device {eth_num}")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_read(u_boot_console):
+test_mii_list(u_boot_console)
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii read {eth_addr} 0")
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
+
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_mii_dump(u_boot_console):
+test_mii_list(u_boot_console)
+expected_response = "PHY control register"
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+response = u_boot_console.run_command(f"mii dump {eth_addr} 0")
+assert expected_response in response
+output = u_boot_console.run_command("echo $?")
+assert output.endswith("0")
-- 
2.25.1



[PATCH] test/py: i2c: Add tests for i2c command

2023-11-14 Thread Love Kumar
Add below test cases for i2c commands:
i2c_bus - To show i2c bus info,
i2c_dev - To set or show the current bus,
i2c_probe - To probe the i2c device,
i2c_eeprom - To test i2c eeprom device,
i2c_probe_all_buses - To list down all the buses and probes it

Signed-off-by: Love Kumar 
---
 test/py/tests/test_i2c.py | 107 ++
 1 file changed, 107 insertions(+)
 create mode 100644 test/py/tests/test_i2c.py

diff --git a/test/py/tests/test_i2c.py b/test/py/tests/test_i2c.py
new file mode 100644
index ..d4f533a3ba5e
--- /dev/null
+++ b/test/py/tests/test_i2c.py
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0
+# (C) Copyright 2023, Advanced Micro Devices, Inc.
+
+import pytest
+import random
+import re
+
+"""
+Note: This test doesn't rely on boardenv_* configuration value but they can
+change test behavior.
+
+For example:
+
+# Setup env__i2c_device_test_skip to True if tests with i2c devices should be
+# skipped. For example: Missing QEMU model or broken i2c device
+env__i2c_device_test_skip = True
+
+# Setup env__i2c_eeprom_device_test to set the i2c bus number and eeprom
+# address for i2c_eeprom test case. Test will be skipped if
+# env__i2c_eeprom_device_test is not set
+env__i2c_eeprom_device_test = {
+"bus": 3,
+"eeprom_addr": 0x54,
+}
+
+# Setup env__i2c_device_test to provide the i2c bus list to test against it
+# for i2c_probe_all_buses case instead of probing all the buses available. If
+# it is not set, it list down all the buses and probes it
+env__i2c_device_test = {
+"bus_list": [0, 2, 5, 12, 16, 18]
+}
+"""
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_bus(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Bus"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_dev(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Current bus"
+response = u_boot_console.run_command("i2c dev")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Setting bus to 0"
+response = u_boot_console.run_command("i2c dev 0")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_eeprom(u_boot_console):
+f = u_boot_console.config.env.get("env__i2c_eeprom_device_test", None)
+if not f:
+pytest.skip("No I2C eeprom to test!")
+
+bus = f.get("bus", 0)
+if bus < 0:
+pytest.fail("No bus specified via env__i2c_eeprom_device_test!")
+
+addr = f.get("eeprom_addr", -1)
+if addr < 0:
+pytest.fail("No eeprom address specified via 
env__i2c_eeprom_device_test!")
+
+# Enable i2c mux bridge
+u_boot_console.run_command("i2c dev %x" % bus)
+u_boot_console.run_command("i2c probe")
+val_int = random.randint(0, 255)
+value = format(val_int, "02x")
+u_boot_console.run_command("i2c mw %x 0 %x 5" % (addr, val_int))
+expected_response = f": {value} {value} {value} {value} {value} "
+response = u_boot_console.run_command("i2c md %x 0 5" % addr)
+assert expected_response in response
+
+@pytest.mark.buildconfigspec("cmd_i2c")
+def test_i2c_probe_all_buses(u_boot_console):
+if u_boot_console.config.env.get("env__i2c_device_test_skip", False):
+pytest.skip("I2C device test is not enabled!")
+expected_response = "Bus"
+response = u_boot_console.run_command("i2c bus")
+assert expected_response in response
+
+# Get all the bus list
+f = u_boot_console.config.env.get("env__i2c_device_test", None)
+if f:
+bus_list = f.get("bus_list")
+else:
+buses = re.findall("Bus (.+?):", response)
+bus_list = [int(x) for x in buses]
+
+for dev in bus_list:
+expected_response = f"Setting bus to {dev}"
+response = u_boot_console.run_command(f"i2c dev {dev}")
+assert expected_response in response
+expected_response = "Valid chip addresses:"
+response = u_boot_console.run_command("i2c probe")
+assert expected_response in response
-- 
2.25.1



[UBOOT PATCH v3] test/py: net: Add dhcp abort test

2023-11-14 Thread Love Kumar
Abort the dhcp request in the middle by pressing ctrl + c on u-boot
prompt and validate the abort status.

Signed-off-by: Love Kumar 
---
Changes in v2:
 - Mark CMD_MII command dependency

Changes in v3:
 - Skip the test if PHY device not present
---
 test/py/tests/test_net.py | 47 +++
 1 file changed, 47 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index b2241ae6a482..76647f274006 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -7,6 +7,7 @@
 import pytest
 import u_boot_utils
 import uuid
+import re
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -115,6 +116,52 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec("cmd_dhcp")
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_net_dhcp_abort(u_boot_console):
+"""Test the dhcp command by pressing ctrl+c in the middle of dhcp request
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp = u_boot_console.config.env.get("env__net_dhcp_server", False)
+if not test_dhcp:
+pytest.skip("No DHCP server available")
+
+u_boot_console.run_command("setenv autoload no")
+
+# Phy reset before running dhcp command
+output = u_boot_console.run_command("mii device")
+if not re.search(r"Current device: '(.+?)'", output):
+pytest.skip("PHY device does not exist!")
+eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f"mii device {eth_num}")
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii modify {eth_addr} 0 0x8000 0x8000")
+
+u_boot_console.run_command("dhcp", wait_for_prompt=False)
+try:
+u_boot_console.wait_for("Waiting for PHY auto negotiation to complete")
+except:
+pytest.skip("Timeout waiting for PHY auto negotiation to complete")
+
+u_boot_console.wait_for("done")
+
+# Sending Ctrl-C
+output = u_boot_console.run_command(
+chr(3), wait_for_echo=False, send_nl=False
+)
+
+assert "TIMEOUT" not in output
+assert "DHCP client bound to address " not in output
+assert "Abort" in output
+
+# Provide a time to recover from Abort - if it is not performed
+# There is message like: ethernet@ff0e: No link.
+u_boot_console.run_command("sleep 1")
+
 @pytest.mark.buildconfigspec('cmd_dhcp6')
 def test_net_dhcp6(u_boot_console):
 """Test the dhcp6 command.
-- 
2.25.1



[UBOOT PATCH v3] test/py: net: Add a TFTP put test

2023-11-07 Thread Love Kumar
Execute tftpput command for uploading files to a server and validate its
size & CRC32.

Signed-off-by: Love Kumar 
---
Changes in v2:
- Add marking for cmd_tftpput config

Chnages in v3:
- Add filename to upload as part of env file
---
 test/py/tests/test_net.py | 71 +++
 1 file changed, 71 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index b2241ae6a482..2495608786de 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -7,6 +7,7 @@
 import pytest
 import u_boot_utils
 import uuid
+import datetime
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -51,6 +52,8 @@ env__net_tftp_readable_file = {
 'addr': 0x1000,
 'size': 5058624,
 'crc32': 'c2244b26',
+'timeout': 5,
+'fnu': 'ubtest-upload.bin',
 }
 
 # Details regarding a file that may be read from a NFS server. This variable
@@ -326,3 +329,71 @@ def test_net_pxe_get(u_boot_console):
 
 assert expected_text_default in output
 assert "Config file 'default.boot' found" in output
+
+@pytest.mark.buildconfigspec("cmd_crc32")
+@pytest.mark.buildconfigspec("cmd_net")
+@pytest.mark.buildconfigspec("cmd_tftpput")
+def test_net_tftpput(u_boot_console):
+"""Test the tftpput command.
+
+A file is downloaded from the TFTP server and then uploaded to the TFTP
+server, its size and its CRC32 are validated.
+
+The details of the file to download are provided by the boardenv_* file;
+see the comment at the beginning of this file.
+"""
+
+if not net_set_up:
+pytest.skip("Network not initialized")
+
+f = u_boot_console.config.env.get("env__net_tftp_readable_file", None)
+if not f:
+pytest.skip("No TFTP readable file to read")
+
+addr = f.get("addr", None)
+if not addr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+sz = f.get("size", None)
+timeout = f.get("timeout", u_boot_console.p.timeout)
+fn = f["fn"]
+fnu = f.get("fnu", 
"_".join([datetime.datetime.now().strftime("%y%m%d%H%M%S"), fn]))
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fn))
+
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+expected_tftpb_crc = f.get("crc32", None)
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpb_crc in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command(
+"tftpput $fileaddr $filesize $serverip:%s" % (fnu)
+)
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+addr = addr + sz
+assert "TIMEOUT" not in output
+assert "Access violation" not in output
+assert expected_text in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fnu))
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpb_crc in output
-- 
2.25.1



[UBOOT PATCH v2] test/py: net: Add dhcp abort test

2023-10-31 Thread Love Kumar
Abort the dhcp request in the middle by pressing ctrl + c on u-boot
prompt and validate the abort status.

Signed-off-by: Love Kumar 
---
Changes in v2:
- Mark CMD_MII command dependency
---
 test/py/tests/test_net.py | 45 +++
 1 file changed, 45 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index b2241ae6a482..6d32ad2db687 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -7,6 +7,7 @@
 import pytest
 import u_boot_utils
 import uuid
+import re
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -115,6 +116,50 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec("cmd_dhcp")
+@pytest.mark.buildconfigspec("cmd_mii")
+def test_net_dhcp_abort(u_boot_console):
+"""Test the dhcp command by pressing ctrl+c in the middle of dhcp request
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp = u_boot_console.config.env.get("env__net_dhcp_server", False)
+if not test_dhcp:
+pytest.skip("No DHCP server available")
+
+u_boot_console.run_command("setenv autoload no")
+
+# Phy reset before running dhcp command
+output = u_boot_console.run_command("mii device")
+eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f"mii device {eth_num}")
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii modify {eth_addr} 0 0x8000 0x8000")
+
+u_boot_console.run_command("dhcp", wait_for_prompt=False)
+try:
+u_boot_console.wait_for("Waiting for PHY auto negotiation to complete")
+except:
+pytest.skip("Timeout waiting for PHY auto negotiation to complete")
+
+u_boot_console.wait_for("done")
+
+# Sending Ctrl-C
+output = u_boot_console.run_command(
+chr(3), wait_for_echo=False, send_nl=False
+)
+
+assert "TIMEOUT" not in output
+assert "DHCP client bound to address " not in output
+assert "Abort" in output
+
+# Provide a time to recover from Abort - if it is not performed
+# There is message like: ethernet@ff0e: No link.
+u_boot_console.run_command("sleep 1")
+
 @pytest.mark.buildconfigspec('cmd_dhcp6')
 def test_net_dhcp6(u_boot_console):
 """Test the dhcp6 command.
-- 
2.25.1



[UBOOT PATCH v2] test/py: net: Add a TFTP put test

2023-10-31 Thread Love Kumar
Execute tftpput command for uploading files to a server and validate its
size & CRC32.

Signed-off-by: Love Kumar 
---
Changes in v2:
- Add marking for cmd_tftpput config
---
 test/py/tests/test_net.py | 72 +++
 1 file changed, 72 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index b2241ae6a482..fbb11b640ae8 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -7,6 +7,7 @@
 import pytest
 import u_boot_utils
 import uuid
+import datetime
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -51,6 +52,7 @@ env__net_tftp_readable_file = {
 'addr': 0x1000,
 'size': 5058624,
 'crc32': 'c2244b26',
+'timeout': 5,
 }
 
 # Details regarding a file that may be read from a NFS server. This variable
@@ -326,3 +328,73 @@ def test_net_pxe_get(u_boot_console):
 
 assert expected_text_default in output
 assert "Config file 'default.boot' found" in output
+
+@pytest.mark.buildconfigspec("cmd_crc32")
+@pytest.mark.buildconfigspec("cmd_net")
+@pytest.mark.buildconfigspec("cmd_tftpput")
+def test_net_tftpput(u_boot_console):
+"""Test the tftpput command.
+
+A file is downloaded from the TFTP server and then uploaded to the TFTP
+server, its size and its CRC32 are validated.
+
+The details of the file to download are provided by the boardenv_* file;
+see the comment at the beginning of this file.
+"""
+
+if not net_set_up:
+pytest.skip("Network not initialized")
+
+f = u_boot_console.config.env.get("env__net_tftp_readable_file", None)
+if not f:
+pytest.skip("No TFTP readable file to read")
+
+addr = f.get("addr", None)
+if not addr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+sz = f.get("size", None)
+timeout = f.get("timeout", u_boot_console.p.timeout)
+fn = f["fn"]
+fnu = "_".join([datetime.datetime.now().strftime("%y%m%d%H%M%S"), fn])
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fn))
+
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+expected_tftpb_crc = f.get("crc32", None)
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpb_crc in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command(
+"tftpput $fileaddr $filesize $serverip:%s" % (fnu)
+)
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+addr = addr + sz
+assert "TIMEOUT" not in output
+assert "Access violation" not in output
+assert expected_text in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fnu))
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+expected_tftpp_crc = expected_tftpb_crc
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpp_crc in output
-- 
2.25.1



[PATCH] test/py: net: Add a test for 'pxe get' command

2023-10-03 Thread Love Kumar
Execute the 'pxe get' command to download a pxe configuration file from
the TFTP server and validate its interpretation.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_net.py | 66 +++
 1 file changed, 66 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index cd4b4dc53cbc..b2241ae6a482 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -6,6 +6,7 @@
 
 import pytest
 import u_boot_utils
+import uuid
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -61,6 +62,16 @@ env__net_nfs_readable_file = {
 'crc32': 'c2244b26',
 }
 
+# Details regarding a file that may be read from a TFTP server. This variable
+# may be omitted or set to None if PXE testing is not possible or desired.
+env__net_pxe_readable_file = {
+'fn': 'default',
+'addr': 0x200,
+'size': 74,
+'timeout': 5,
+'pattern': 'Linux',
+}
+
 # True if a router advertisement service is connected to the network, and 
should
 # be tested. If router advertisement testing is not possible or desired, this
 variable may be omitted or set to False.
@@ -260,3 +271,58 @@ def test_net_nfs(u_boot_console):
 
 output = u_boot_console.run_command('crc32 %x $filesize' % addr)
 assert expected_crc in output
+
+@pytest.mark.buildconfigspec("cmd_net")
+@pytest.mark.buildconfigspec("cmd_pxe")
+def test_net_pxe_get(u_boot_console):
+"""Test the pxe get command.
+
+A pxe configuration file is downloaded from the TFTP server and interpreted
+to boot the images mentioned in pxe configuration file.
+
+The details of the file to download are provided by the boardenv_* file;
+see the comment at the beginning of this file.
+"""
+
+if not net_set_up:
+pytest.skip("Network not initialized")
+
+test_net_setup_static(u_boot_console)
+
+f = u_boot_console.config.env.get("env__net_pxe_readable_file", None)
+if not f:
+pytest.skip("No PXE readable file to read")
+
+addr = f.get("addr", None)
+timeout = f.get("timeout", u_boot_console.p.timeout)
+
+pxeuuid = uuid.uuid1()
+u_boot_console.run_command(f"setenv pxeuuid {pxeuuid}")
+expected_text_uuid = f"Retrieving file: pxelinux.cfg/{pxeuuid}"
+
+ethaddr = u_boot_console.run_command("echo $ethaddr")
+ethaddr = ethaddr.replace(':', '-')
+expected_text_ethaddr = f"Retrieving file: pxelinux.cfg/01-{ethaddr}"
+
+ip = u_boot_console.run_command("echo $ipaddr")
+ip = ip.split('.')
+ipaddr_file = "".join(['%02x' % int(x) for x in ip]).upper()
+expected_text_ipaddr = f"Retrieving file: pxelinux.cfg/{ipaddr_file}"
+expected_text_default = f"Retrieving file: pxelinux.cfg/default"
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("pxe get")
+
+assert "TIMEOUT" not in output
+assert expected_text_uuid in output
+assert expected_text_ethaddr in output
+assert expected_text_ipaddr in output
+
+i = 1
+for i in range(0, len(ipaddr_file) - 1):
+expected_text_ip = f"Retrieving file: pxelinux.cfg/{ipaddr_file[:-i]}"
+assert expected_text_ip in output
+i += 1
+
+assert expected_text_default in output
+assert "Config file 'default.boot' found" in output
-- 
2.25.1



[PATCH] test/py: net: Add dhcp abort test

2023-10-03 Thread Love Kumar
Abort the dhcp request in the middle by pressing ctrl + c on u-boot
prompt and validate the abort status.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_net.py | 44 +++
 1 file changed, 44 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index cd4b4dc53cbc..1e8eb0357eef 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -6,6 +6,7 @@
 
 import pytest
 import u_boot_utils
+import re
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -104,6 +105,49 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec("cmd_dhcp")
+def test_net_dhcp_abort(u_boot_console):
+"""Test the dhcp command by pressing ctrl+c in the middle of dhcp request
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp = u_boot_console.config.env.get("env__net_dhcp_server", False)
+if not test_dhcp:
+pytest.skip("No DHCP server available")
+
+u_boot_console.run_command("setenv autoload no")
+
+# Phy reset before running dhcp command
+output = u_boot_console.run_command("mii device")
+eth_num = re.search(r"Current device: '(.+?)'", output).groups()[0]
+u_boot_console.run_command(f"mii device {eth_num}")
+output = u_boot_console.run_command("mii info")
+eth_addr = hex(int(re.search(r"PHY (.+?):", output).groups()[0], 16))
+u_boot_console.run_command(f"mii modify {eth_addr} 0 0x8000 0x8000")
+
+u_boot_console.run_command("dhcp", wait_for_prompt=False)
+try:
+u_boot_console.wait_for("Waiting for PHY auto negotiation to complete")
+except:
+pytest.skip("Timeout waiting for PHY auto negotiation to complete")
+
+u_boot_console.wait_for("done")
+
+# Sending Ctrl-C
+output = u_boot_console.run_command(
+chr(3), wait_for_echo=False, send_nl=False
+)
+
+assert "TIMEOUT" not in output
+assert "DHCP client bound to address " not in output
+assert "Abort" in output
+
+# Provide a time to recover from Abort - if it is not performed
+# There is message like: ethernet@ff0e: No link.
+u_boot_console.run_command("sleep 1")
+
 @pytest.mark.buildconfigspec('cmd_dhcp6')
 def test_net_dhcp6(u_boot_console):
 """Test the dhcp6 command.
-- 
2.25.1



[PATCH] test/py: net: Add a TFTP put test

2023-10-03 Thread Love Kumar
Execute tftpput command for uploading files to a server and validate its
size & CRC32.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_net.py | 69 +++
 1 file changed, 69 insertions(+)

diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index cd4b4dc53cbc..f69e3ea2dbba 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -6,6 +6,7 @@
 
 import pytest
 import u_boot_utils
+import datetime
 
 """
 Note: This test relies on boardenv_* containing configuration values to define
@@ -50,6 +51,7 @@ env__net_tftp_readable_file = {
 'addr': 0x1000,
 'size': 5058624,
 'crc32': 'c2244b26',
+'timeout': 5,
 }
 
 # Details regarding a file that may be read from a NFS server. This variable
@@ -260,3 +262,70 @@ def test_net_nfs(u_boot_console):
 
 output = u_boot_console.run_command('crc32 %x $filesize' % addr)
 assert expected_crc in output
+
+@pytest.mark.buildconfigspec("cmd_crc32")
+@pytest.mark.buildconfigspec("cmd_net")
+def test_net_tftpput(u_boot_console):
+"""Test the tftpput command.
+A file is downloaded from the TFTP server and then uploaded to the TFTP
+server, its size and its CRC32 are validated.
+The details of the file to download are provided by the boardenv_* file;
+see the comment at the beginning of this file.
+"""
+
+if not net_set_up:
+pytest.skip("Network not initialized")
+
+f = u_boot_console.config.env.get("env__net_tftp_readable_file", None)
+if not f:
+pytest.skip("No TFTP readable file to read")
+
+addr = f.get("addr", None)
+if not addr:
+addr = u_boot_utils.find_ram_base(u_boot_console)
+
+sz = f.get("size", None)
+timeout = f.get("timeout", u_boot_console.p.timeout)
+fn = f["fn"]
+fnu = "_".join([datetime.datetime.now().strftime("%y%m%d%H%M%S"), fn])
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fn))
+
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+expected_tftpb_crc = f.get("crc32", None)
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpb_crc in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command(
+"tftpput $fileaddr $filesize $serverip:%s" % (fnu)
+)
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+addr = addr + sz
+assert "TIMEOUT" not in output
+assert "Access violation" not in output
+assert expected_text in output
+
+with u_boot_console.temporary_timeout(timeout):
+output = u_boot_console.run_command("tftpboot %x %s" % (addr, fnu))
+
+expected_text = "Bytes transferred = "
+if sz:
+expected_text += "%d" % sz
+assert "TIMEOUT" not in output
+assert expected_text in output
+
+expected_tftpp_crc = expected_tftpb_crc
+
+output = u_boot_console.run_command("crc32 $fileaddr $filesize")
+assert expected_tftpp_crc in output
-- 
2.25.1



[PATCH v2] test/py: sleep: Add a test for the time command

2023-09-27 Thread Love Kumar
Execute "time ", and validate that it gives the approximately
the correct amount of command execution time.

Signed-off-by: Love Kumar 
---

Changes in v2:
- Used @pytest.mark.buildconfigspec('')
---
 test/py/tests/test_sleep.py | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/test/py/tests/test_sleep.py b/test/py/tests/test_sleep.py
index 392af29db224..66a57434bff7 100644
--- a/test/py/tests/test_sleep.py
+++ b/test/py/tests/test_sleep.py
@@ -41,3 +41,21 @@ def test_sleep(u_boot_console):
 if not u_boot_console.config.gdbserver:
 # margin is hopefully enough to account for any system overhead.
 assert elapsed < (sleep_time + sleep_margin)
+
+@pytest.mark.buildconfigspec("cmd_misc")
+def test_time(u_boot_console):
+"""Test the time command, and validate that it gives approximately the
+correct amount of command execution time."""
+
+sleep_skip = u_boot_console.config.env.get("env__sleep_accurate", True)
+if not sleep_skip:
+pytest.skip("sleep is not accurate")
+
+sleep_time = u_boot_console.config.env.get("env__sleep_time", 10)
+sleep_margin = u_boot_console.config.env.get("env__sleep_margin", 0.25)
+output = u_boot_console.run_command("time sleep %d" % sleep_time)
+execute_time = float(output.split()[1])
+assert sleep_time >= (execute_time - 0.01)
+if not u_boot_console.config.gdbserver:
+# margin is hopefully enough to account for any system overhead.
+assert sleep_time < (execute_time + sleep_margin)
-- 
2.25.1



[PATCH] test/py: sleep: Add a test for the time command

2023-09-26 Thread Love Kumar
Execute "time ", and validate that it gives the approximately
the correct amount of command execution time.

Signed-off-by: Love Kumar 
---
 test/py/tests/test_sleep.py | 20 
 1 file changed, 20 insertions(+)

diff --git a/test/py/tests/test_sleep.py b/test/py/tests/test_sleep.py
index 392af29db224..388f544d07df 100644
--- a/test/py/tests/test_sleep.py
+++ b/test/py/tests/test_sleep.py
@@ -41,3 +41,23 @@ def test_sleep(u_boot_console):
 if not u_boot_console.config.gdbserver:
 # margin is hopefully enough to account for any system overhead.
 assert elapsed < (sleep_time + sleep_margin)
+
+def test_time(u_boot_console):
+"""Test the time command, and validate that it gives approximately the
+correct amount of command execution time."""
+
+sleep_skip = u_boot_console.config.env.get("env__sleep_accurate", True)
+if not sleep_skip:
+pytest.skip("sleep is not accurate")
+
+if u_boot_console.config.buildconfig.get("config_cmd_misc", "n") != "y":
+pytest.skip("sleep command not supported")
+
+sleep_time = u_boot_console.config.env.get("env__sleep_time", 10)
+sleep_margin = u_boot_console.config.env.get("env__sleep_margin", 0.25)
+output = u_boot_console.run_command("time sleep %d" % sleep_time)
+execute_time = float(output.split()[1])
+assert sleep_time >= (execute_time - 0.01)
+if not u_boot_console.config.gdbserver:
+# margin is hopefully enough to account for any system overhead.
+assert sleep_time < (execute_time + sleep_margin)
-- 
2.25.1