-
Notifications
You must be signed in to change notification settings - Fork 50
Ambarella upstream #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
50cf17e
3240991
0abdc5e
35e2579
36362d5
ad42769
d4eb618
6a0fc53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
2025-05-17 09:50:45,266 [DEBUG] Searching for USB device paths matching 4255:0013... | ||
2025-05-17 09:50:45,282 [DEBUG] recovery_config:{'soc_model': 'cv22', 'soc_family': 'ambarella', 'usb_path': (1, (1, 2)), 'firmware': {'vid': 7054, 'pid': 49186, 'protocol': 'amba', 'firmware': {'dram_script': {'path': 'cv22_lpddr4_408MHz.ads', 'description': 'DRAM initialization script for CV22 LPDDR4 at 408MHz'}, 'bootloader': {'path': 'cv22_bld_linux_emmc.bin', 'description': 'CV22 bootloader for Linux eMMC boot'}}, 'steps': [{'name': 'Initialize DRAM', 'action': 'initialize_dram', 'description': 'Initialize device DRAM using ADS script'}, {'name': 'Load bootloader', 'action': 'load_bootloader', 'description': 'Load bootloader to device memory'}, {'name': 'Flash firmware', 'action': 'flash_firmware', 'description': 'Flash firmware image to device', 'args': {'firmware': 'firmware.bin'}}], 'description': 'Recovery process for Ambarella CV22 devices:\n1. Device enters USB recovery mode\n2. Initialize DRAM using ADS script\n3. Load bootloader to memory\n4. Flash firmware image\n5. Device boots from flashed firmware\n', 'notes': '- Ensure device is in USB recovery mode before starting\n- DRAM script and bootloader files must be in firmware directory\n- Firmware image should be compatible with CV22\n'}, 'args': {'soc': 'cv22', 'firmware_file': ['src/snagrecover/templates/ambarella-cv22.yaml'], 'firmware': None, 'uart': None, 'baudrate': 115200, 'netns': 'snagbootnet', 'loglevel': 'debug', 'logfile': 'board_recovery.log', 'rom_usb': None, 'usb_path': None, 'list_socs': False, 'version': False, 'template': None, 'udev': False, 'am335x_setup': False}} | ||
2025-05-17 09:50:45,283 [INFO] Starting recovery of cv22 board | ||
2025-05-17 09:50:45,289 [INFO] Done recovering cv22 board | ||
2025-05-17 09:50:45,290 [INFO] Logs were appended to board_recovery.log | ||
2025-05-17 09:50:45,290 [INFO] Done recovering cv22 board | ||
2025-05-17 09:52:22,581 [DEBUG] Searching for USB device paths matching 4255:0013... | ||
2025-05-17 09:52:22,594 [DEBUG] recovery_config:{'soc_model': 'cv22', 'soc_family': 'ambarella', 'usb_path': (1, (1, 2)), 'firmware': {'vid': 7054, 'pid': 49186, 'protocol': 'amba', 'firmware': {'dram_script': {'path': 'cv22_lpddr4_408MHz.ads', 'description': 'DRAM initialization script for CV22 LPDDR4 at 408MHz'}, 'bootloader': {'path': 'cv22_bld_linux_emmc.bin', 'description': 'CV22 bootloader for Linux eMMC boot'}}, 'steps': [{'name': 'Initialize DRAM', 'action': 'initialize_dram', 'description': 'Initialize device DRAM using ADS script'}, {'name': 'Load bootloader', 'action': 'load_bootloader', 'description': 'Load bootloader to device memory'}, {'name': 'Flash firmware', 'action': 'flash_firmware', 'description': 'Flash firmware image to device', 'args': {'firmware': 'firmware.bin'}}], 'description': 'Recovery process for Ambarella CV22 devices:\n1. Device enters USB recovery mode\n2. Initialize DRAM using ADS script\n3. Load bootloader to memory\n4. Flash firmware image\n5. Device boots from flashed firmware\n', 'notes': '- Ensure device is in USB recovery mode before starting\n- DRAM script and bootloader files must be in firmware directory\n- Firmware image should be compatible with CV22\n'}, 'args': {'soc': 'cv22', 'firmware_file': ['src/snagrecover/templates/ambarella-cv22.yaml'], 'firmware': None, 'uart': None, 'baudrate': 115200, 'netns': 'snagbootnet', 'loglevel': 'debug', 'logfile': 'board_recovery.log', 'rom_usb': None, 'usb_path': None, 'list_socs': False, 'version': False, 'template': None, 'udev': False, 'am335x_setup': False}} | ||
2025-05-17 09:52:22,594 [INFO] Starting recovery of cv22 board | ||
2025-05-17 09:52:22,601 [INFO] Done recovering cv22 board | ||
2025-05-17 09:52:22,601 [INFO] Logs were appended to board_recovery.log | ||
2025-05-17 09:52:22,601 [INFO] Done recovering cv22 board |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,3 +47,22 @@ ideal scenario, each board is plugged into a separate root hub port, but if an | |
external hub is absolutely necessary, using one with a higher capacity or making | ||
sure that it is powered by an independent supply can help. | ||
|
||
## Ambarella SoC recovery issues | ||
|
||
### USB device not detected | ||
|
||
If the Ambarella SoC is not detected as a USB device, make sure: | ||
1. The board is properly set to USB boot mode using the appropriate jumpers or switches | ||
2. The USB cable is connected to the correct port (usually the OTG port) | ||
3. The board is powered on | ||
|
||
### DRAM initialization fails | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, this applies to every board which relies on closed-source firmware binaries. |
||
|
||
DRAM initialization can fail if the ADS script doesn't match the specific memory configuration of your board. Make sure you're using the correct ADS script for your specific board model and memory type. | ||
|
||
### Bootloader fails to enter Amboot mode | ||
|
||
If the bootloader fails to enter Amboot mode: | ||
1. Check that you're using the correct bootloader binary for your SoC model | ||
2. Ensure the board has enough power (some boards may require a powered USB hub) | ||
3. Try resetting the board and starting the recovery process again | ||
phodina marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# This file is part of Snagboot | ||
# Copyright (C) 2025 Petr Hodina | ||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
# | ||
|
||
import struct | ||
from dataclasses import dataclass | ||
from pathlib import Path | ||
from typing import Optional | ||
|
||
from .firmware import Firmware, FirmwareError | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These + same comment as for the previous commit regarding relative path imports. |
||
|
||
FIRM_OFFSET_VERSION = 0x3C | ||
FIRM_OFFSET_MEMFW_RESULT = 0x40 | ||
FIRM_OFFSET_MEMFW_CMD = 0x50 | ||
FIRM_OFFSET_MEMFW_PROG = 0x60 | ||
|
||
BOARD_INFO_MAGIC = 0x12345678 | ||
BOARD_INFO_ADDR = 0x100000 | ||
PTB_PTR = 0x200000 | ||
|
||
FW_INFO_MAGIC = 0x87654321 | ||
FW_INFO_ADDR = 0x110000 | ||
|
||
|
||
@dataclass | ||
class AmbaFirmwareInfo: | ||
version: int | ||
memfw_result_addr: int | ||
memfw_cmd_addr: int | ||
memfw_prog_addr: int | ||
|
||
|
||
class AmbaFirmware(Firmware): | ||
def __init__( | ||
self, | ||
bootloader_path: Optional[Path] = None, | ||
dram_script_path: Optional[Path] = None, | ||
): | ||
super().__init__() | ||
self.bootloader_path = bootloader_path | ||
self.dram_script_path = dram_script_path | ||
self._bootloader_data: Optional[bytes] = None | ||
self._dram_script_data: Optional[str] = None | ||
|
||
def load(self) -> None: | ||
if self.bootloader_path: | ||
try: | ||
with open(self.bootloader_path, "rb") as f: | ||
self._bootloader_data = f.read() | ||
except OSError as e: | ||
raise FirmwareError("Failed to load bootloader") from e | ||
|
||
if self.dram_script_path: | ||
try: | ||
with open(self.dram_script_path, "r") as f: | ||
self._dram_script_data = f.read() | ||
except OSError as e: | ||
raise FirmwareError("Failed to load DRAM script") from e | ||
|
||
@property | ||
def bootloader(self) -> bytes: | ||
if not self._bootloader_data: | ||
raise FirmwareError("Bootloader not loaded") | ||
return self._bootloader_data | ||
|
||
@property | ||
def dram_script(self) -> str: | ||
if not self._dram_script_data: | ||
raise FirmwareError("DRAM script not loaded") | ||
return self._dram_script_data | ||
|
||
@staticmethod | ||
def get_firmware_info(firmware_path: Path) -> AmbaFirmwareInfo: | ||
try: | ||
with open(firmware_path, "rb") as f: | ||
f.seek(FIRM_OFFSET_VERSION) | ||
version = struct.unpack("<I", f.read(4))[0] | ||
|
||
f.seek(FIRM_OFFSET_MEMFW_RESULT) | ||
result_addr = struct.unpack("<I", f.read(4))[0] | ||
|
||
f.seek(FIRM_OFFSET_MEMFW_CMD) | ||
cmd_addr = struct.unpack("<I", f.read(4))[0] | ||
|
||
f.seek(FIRM_OFFSET_MEMFW_PROG) | ||
prog_addr = struct.unpack("<I", f.read(4))[0] | ||
|
||
return AmbaFirmwareInfo( | ||
version=version, | ||
memfw_result_addr=result_addr, | ||
memfw_cmd_addr=cmd_addr, | ||
memfw_prog_addr=prog_addr, | ||
) | ||
|
||
except (OSError, struct.error) as e: | ||
raise FirmwareError("Failed to extract firmware info") from e | ||
|
||
@staticmethod | ||
def pack_board_info() -> bytes: | ||
return struct.pack( | ||
"<IIII", | ||
BOARD_INFO_MAGIC, | ||
0x6F547541, # 'AuTo' in little endian | ||
PTB_PTR, | ||
0, | ||
) # reserved | ||
|
||
@staticmethod | ||
def pack_firmware_info(fw_info: AmbaFirmwareInfo) -> bytes: | ||
return struct.pack( | ||
"<IIII", | ||
FW_INFO_MAGIC, | ||
fw_info.memfw_cmd_addr, | ||
fw_info.memfw_result_addr, | ||
0, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -223,6 +223,10 @@ def run_firmware(port, fw_name: str, subfw_name: str = ""): | |
from snagrecover.firmware.bcm import bcm_run | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. commit-wide comment: the commit history of Snagboot should be bisectable as much as possible, meaning each commit should allow Snagboot to run without errors. In this commit, you're adding references to modules which don't exist yet. I'd prefer if you reordered the commits so that each one is valid Python. So in this specific case, the commits adding the protocol and firmware code should come before this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, will rearrange the code so it's self contained and does not require any future code. |
||
|
||
bcm_run(port, fw_name, fw_blob, subfw_name) | ||
elif soc_family == "ambarella": | ||
from snagrecover.firmware.amba_fw import run_firmware as amba_run | ||
|
||
amba_run(port, fw_name, subfw_name) | ||
else: | ||
raise Exception(f"Unsupported SoC family {soc_family}") | ||
logger.info(f"Done installing firmware {fw_name}") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# This file is part of Snagboot | ||
# Copyright (C) 2023 Bootlin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The copyright holder is you, not Bootlin. The rest of the license header is OK. |
||
# | ||
# This program is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU General Public License | ||
# as published by the Free Software Foundation; either version 2 | ||
# of the License, or (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
# | ||
|
||
import struct | ||
from dataclasses import dataclass | ||
from enum import IntEnum | ||
from typing import Tuple | ||
|
||
from ..usb import UsbDevice, UsbError | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UsbDevice and UsbError are not defined in usb.py, are you missing some commits in your series? Also, please use |
||
|
||
CMD_SIGNATURE = 0x55434D44 | ||
RSP_SIGNATURE = 0x55525350 | ||
|
||
|
||
class AmbaUsbError(Exception): | ||
pass | ||
|
||
|
||
class AmbaInquiryType(IntEnum): | ||
CHIP = 0x00000001 | ||
ADDR = 0x00000002 | ||
REG = 0x00000003 | ||
|
||
|
||
class AmbaCommand(IntEnum): | ||
RDY_TO_RCV = 0 | ||
RCV_DATA = 1 | ||
RDY_TO_SND = 2 | ||
SND_DATA = 3 | ||
INQUIRY_STATUS = 4 | ||
|
||
|
||
class AmbaResponse(IntEnum): | ||
SUCCESS = 0 | ||
FAILED = 1 | ||
IN_BLD = 2 | ||
|
||
|
||
@dataclass | ||
class AmbaDeviceInfo: | ||
chip_type: int | ||
dram_start: int | ||
|
||
|
||
class AmbaProtocol: | ||
def __init__(self, device: UsbDevice): | ||
self.device = device | ||
self._cmd_buf = bytearray(32) | ||
self._rsp_buf = bytearray(16) | ||
|
||
def _pack_command(self, cmd: int, *params) -> bytes: | ||
struct.pack_into( | ||
"<IIIIIIII", | ||
self._cmd_buf, | ||
0, | ||
CMD_SIGNATURE, | ||
cmd, | ||
*(params + (0,) * (6 - len(params))), | ||
) | ||
return self._cmd_buf | ||
|
||
def _unpack_response(self) -> Tuple[int, int, int, int]: | ||
return struct.unpack_from("<IIII", self._rsp_buf) | ||
|
||
def send_command(self, cmd: int, *params) -> Tuple[int, int, int]: | ||
try: | ||
cmd_buf = self._pack_command(cmd, *params) | ||
self.device.write(cmd_buf) | ||
|
||
self.device.read(self._rsp_buf) | ||
sig, rsp, p0, p1 = self._unpack_response() | ||
|
||
if sig != RSP_SIGNATURE: | ||
raise AmbaUsbError("Invalid response signature") | ||
|
||
return rsp, p0, p1 | ||
|
||
except UsbError as e: | ||
raise AmbaUsbError("USB communication error") from e | ||
|
||
def get_device_info(self) -> AmbaDeviceInfo: | ||
rsp, chip, _ = self.send_command( | ||
AmbaCommand.INQUIRY_STATUS, AmbaInquiryType.CHIP | ||
) | ||
if rsp != AmbaResponse.SUCCESS: | ||
raise AmbaUsbError("Failed to get chip type") | ||
|
||
rsp, dram_start, _ = self.send_command( | ||
AmbaCommand.INQUIRY_STATUS, AmbaInquiryType.ADDR | ||
) | ||
if rsp != AmbaResponse.SUCCESS: | ||
raise AmbaUsbError("Failed to get DRAM start address") | ||
|
||
return AmbaDeviceInfo(chip, dram_start) | ||
|
||
def send_file(self, addr: int, data: bytes) -> None: | ||
rsp, _, _ = self.send_command(AmbaCommand.RDY_TO_RCV, addr) | ||
if rsp != AmbaResponse.SUCCESS: | ||
raise AmbaUsbError("Device not ready to receive") | ||
|
||
rsp, _, _ = self.send_command(AmbaCommand.RCV_DATA) | ||
if rsp != AmbaResponse.SUCCESS: | ||
raise AmbaUsbError("Failed to initiate data transfer") | ||
|
||
try: | ||
self.device.write(data) | ||
except UsbError as e: | ||
raise AmbaUsbError("Failed to send data") from e | ||
|
||
rsp, _, _ = self.send_command( | ||
AmbaCommand.RDY_TO_RCV, | ||
0x80000000, | ||
addr, | ||
) | ||
if rsp != AmbaResponse.SUCCESS: | ||
raise AmbaUsbError("Data transfer failed") |
Uh oh!
There was an error while loading. Please reload this page.