diff --git a/boards/common/rtkprog.board.cmake b/boards/common/rtkprog.board.cmake new file mode 100644 index 0000000000000..2176810eabf5a --- /dev/null +++ b/boards/common/rtkprog.board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_finalize_runner_args(rtkprog) \ No newline at end of file diff --git a/boards/realtek/rtl87x2j_evb/board.cmake b/boards/realtek/rtl87x2j_evb/board.cmake index 10fc2f8f1ac7e..312100df000aa 100644 --- a/boards/realtek/rtl87x2j_evb/board.cmake +++ b/boards/realtek/rtl87x2j_evb/board.cmake @@ -4,3 +4,4 @@ board_runner_args(jlink "--device=RTL87X2J" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/mpcli.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/rtkprog.board.cmake) \ No newline at end of file diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index b3de2be4a7a9c..7b366bc8fc139 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -658,6 +658,22 @@ using the ``--device`` option: For more about the UF2 format and its tooling, see `USB Flashing Format (UF2)`_. +.. _runner_rtkprog: + +Realtek Alternate Flash Programmer (rtkprog) +******************************************** + +``rtkprog`` is an open source implementation of the protocol needed to flash Realtek RTL87x2x +Bluetooth SoCs via UART. + +.. code-block:: console + + west flash --runner rtkprog + +.. _rtkprog Source Code: https://github.com/a-labs-io/rtkprog +.. _rtkprog Python package: https://pypi.org/p/rtkprog + + .. _runner_mpcli: Realtek Bee Flash Programmer (MPCli) Host Tools diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 7fa6845112b89..54dc80806c530 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -59,6 +59,7 @@ def _import_runner_module(runner_name): 'renode', 'renode-robot', 'rfp', + 'rtkprog', 'rtsflash', 'sftool', 'silabs_commander', diff --git a/scripts/west_commands/runners/rtkprog.py b/scripts/west_commands/runners/rtkprog.py new file mode 100644 index 0000000000000..42f3f73b6a8c2 --- /dev/null +++ b/scripts/west_commands/runners/rtkprog.py @@ -0,0 +1,110 @@ +# Copyright (c) 2026, A-Labs GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +'''Runner for flashing Realtek devices with rtkprog.''' + +from pathlib import Path + +from runners.core import FileType, RunnerCaps, ZephyrBinaryRunner + + +class RtkProgBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for rtkprog.''' + + def __init__(self, cfg, port, build_dir, bin_address, chip_erase, reset): + super().__init__(cfg) + self.port = port + self.build_dir = build_dir + self.bin_address = bin_address + self.chip_erase = chip_erase + self.reset = reset + if not reset: + raise ValueError('rtkprog always resets') + self.app_bin_file = cfg.bin_file + self.ext_file = cfg.file + self.ext_file_type = cfg.file_type + + @classmethod + def name(cls): + return 'rtkprog' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash'}, file=True, erase=False, reset=True) + + @classmethod + def do_add_parser(cls, parser): + argument_parser = parser + + argument_parser.add_argument( + '--port', + required=False, + type=str, + help='Serial communication port (e.g., COM3, /dev/ttyUSB0)', + ) + argument_parser.add_argument( + '--bin-address', + type=str, + help='Download address (hex format, e.g., 0x8000000)', + ) + return parser + + @classmethod + def do_create(cls, cfg, args): + return RtkProgBinaryRunner( + cfg, + args.port, + build_dir=cfg.build_dir, + bin_address=args.bin_address, + chip_erase=args.erase, + reset=args.reset, + ) + + def execute_rtkprog(self, bin_file_path, download_address): + """ + Execute rtkprog command with the given configuration file. + """ + cmd_args = [ + 'rtkprog', + ] + + # global args need to come before command + if self.port: + cmd_args.extend(['--port', self.port]) + + # command and command args + cmd_args.extend( + [ + 'write', + '-w', + download_address + ',0x0,' + str(bin_file_path), + ] + ) + + self.check_call(cmd_args) + + def get_flash_parameters(self): + """Get file path and download address for flashing.""" + if self.ext_file: + # Use external binary file + if self.ext_file_type != FileType.BIN: + raise ValueError('Cannot flash; runner only supports bin type') + + bin_file_path = Path(self.ext_file) + else: + # Use build system generated file + bin_file_path = Path(self.app_bin_file) + + download_address = self.bin_address or hex( + self.flash_address_from_build_conf(self.build_conf) + ) + + return bin_file_path, download_address + + def do_run(self, command, **kwargs): + self.require('rtkprog') + + bin_file_path, download_address = self.get_flash_parameters() + + self.execute_rtkprog(bin_file_path, download_address) \ No newline at end of file diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 8bfcd61f9f8b6..d54bfa83899dd 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -50,6 +50,7 @@ def test_runner_imports(): 'renode', 'renode-robot', 'rfp', + 'rtkprog', 'sftool', 'silabs_commander', 'spi_burn',