From 4673c8272dc40f8283ccdfd25d08556838c3377f Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 31 Dec 2025 15:35:23 -0800 Subject: [PATCH] Add support for fixing up the Ethernet MAC using device serial number (matches U-Boot behavior). --- docs/Targets.md | 18 ++++-- hal/mpfs250.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++- hal/mpfs250.h | 33 +++++++++++ 3 files changed, 197 insertions(+), 8 deletions(-) diff --git a/docs/Targets.md b/docs/Targets.md index 32f1ee84..f78c7095 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1094,7 +1094,8 @@ set architecture riscv:rv64 ### PolarFire Example Boot Output ``` -wolfBoot Version: 2.7.0 (Dec 29 2025 11:34:01) +wolfBoot Version: 2.7.0 (Dec 31 2025 15:33:35) +Disk encryption enabled Reading MBR... Found GPT PTE at sector 1 Found valid boot signature in MBR @@ -1111,12 +1112,13 @@ disk0.p3 (7_65AFFE00h@ 0_8900000) Total partitions on disk0: 4 Checking primary OS image in 0,1... Checking secondary OS image in 0,2... -Versions, A:1 B:1 +Versions, A:1 B:0 Load address 0x8E000000 Attempting boot from P:A -Boot partition: 0x801FFD80 (sz 19767004, ver 0x1, type 0x601) -Loading image from disk...done. (846 ms) -Boot partition: 0x8E000000 (sz 19767004, ver 0x1, type 0x601) +Boot partition: 0x801FFD90 (sz 19767004, ver 0x0, type 0x0) +Loading image from disk...done. (877 ms) +Decrypting image...done. (2894 ms) +Boot partition: 0x8E000000 (sz 19767004, ver 0x0, type 0x0) Checking image integrity...done. (1507 ms) Verifying image signature...done. (68 ms) Firmware Valid. @@ -1128,6 +1130,11 @@ Image fdt-1: 0x8A000000 (19897 bytes) Loading DTS: 0x8A000000 -> 0x8A000000 (19897 bytes) Invalid elf, falling back to raw binary Booting at 80200000 +FDT: Version 17, Size 19897 +FDT: Set chosen (13840), bootargs=earlycon root=/dev/mmcblk0p4 rootwait uio_pdrv_genirq.of_id=generic-uio +FDT: Device serial: 219A437C-6AE1F1C2-8EDC4324-685B2288 +FDT: MAC0 = 00:04:A3:5B:22:88 +FDT: MAC1 = 00:04:A3:5B:22:89 [ 0.000000] Linux version 6.12.22-linux4microchip+fpga-2025.07-g032a7095303a (oe-user@oe-host) (riscv64-oe-linux-gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42.0.20240723) #1 SMP Tue Jul 22 10:04:20 UTC 2025 [ 0.000000] Machine model: Microchip PolarFire-SoC VIDEO Kit [ 0.000000] SBI specification v1.0 detected @@ -1193,7 +1200,6 @@ Benchmark complete ### PolarFire TODO -* Add support for reading serial number and modifying ethernet MAC in device tree * Add support for QSPI NOR flash * Add support for full HSS replacement using wolfboot - Machine level assembly startup diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 4d24f630..2137cebf 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -56,6 +56,89 @@ void hal_init(void) LIBWOLFBOOT_VERSION_STRING,__DATE__, __TIME__); } +/* ============================================================================ + * System Controller Mailbox Functions + * + * The MPFS system controller provides various system services via a mailbox + * interface. Commands are sent by writing the opcode to the control register + * and responses are read from the mailbox RAM. + * ============================================================================ */ + +/** + * mpfs_scb_mailbox_busy - Check if the system controller mailbox is busy + * + * Returns: non-zero if busy, 0 if ready + */ +static int mpfs_scb_mailbox_busy(void) +{ + return (SCBCTRL_REG(SERVICES_SR_OFFSET) & SERVICES_SR_BUSY_MASK); +} + +/** + * mpfs_read_serial_number - Read the device serial number via system services + * @serial: Buffer to store the 16-byte device serial number + * + * This function sends a serial number request (opcode 0x00) to the system + * controller and reads the 16-byte response from the mailbox RAM. + * + * Returns: 0 on success, negative error code on failure + */ +static int mpfs_read_serial_number(uint8_t *serial) +{ + uint32_t cmd, status; + int i, timeout; + + if (serial == NULL) { + return -1; + } + + /* Check if mailbox is busy */ + if (mpfs_scb_mailbox_busy()) { + wolfBoot_printf("SCB mailbox busy\n"); + return -2; + } + + /* Send serial number request command (opcode 0x00) + * Command format: [31:16] = opcode, [0] = request bit */ + cmd = (SYS_SERV_CMD_SERIAL_NUMBER << SERVICES_CR_COMMAND_SHIFT) | + SERVICES_CR_REQ_MASK; + SCBCTRL_REG(SERVICES_CR_OFFSET) = cmd; + + /* Wait for request bit to clear (command accepted) */ + timeout = 10000; + while ((SCBCTRL_REG(SERVICES_CR_OFFSET) & SERVICES_CR_REQ_MASK) && timeout > 0) { + timeout--; + } + if (timeout == 0) { + wolfBoot_printf("SCB mailbox request timeout\n"); + return -3; + } + + /* Wait for busy bit to clear (command completed) */ + timeout = 10000; + while (mpfs_scb_mailbox_busy() && timeout > 0) { + timeout--; + } + if (timeout == 0) { + wolfBoot_printf("SCB mailbox busy timeout\n"); + return -4; + } + + /* Check status (upper 16 bits of status register) */ + status = (SCBCTRL_REG(SERVICES_SR_OFFSET) >> SERVICES_SR_STATUS_SHIFT) & 0xFFFF; + if (status != 0) { + wolfBoot_printf("SCB mailbox error: 0x%x\n", status); + return -5; + } + + /* Read serial number from mailbox RAM (16 bytes) */ + for (i = 0; i < DEVICE_SERIAL_NUMBER_SIZE; i++) { + serial[i] = SCBMBOX_BYTE(i); + } + + return 0; +} + /* Linux kernel command line arguments */ #ifndef LINUX_BOOTARGS #ifndef LINUX_BOOTARGS_ROOT @@ -66,10 +149,17 @@ void hal_init(void) "earlycon root="LINUX_BOOTARGS_ROOT" rootwait uio_pdrv_genirq.of_id=generic-uio" #endif +/* Microchip OUI (Organizationally Unique Identifier) for MAC address */ +#define MICROCHIP_OUI_0 0x00 +#define MICROCHIP_OUI_1 0x04 +#define MICROCHIP_OUI_2 0xA3 + int hal_dts_fixup(void* dts_addr) { int off, ret; struct fdt_header *fdt = (struct fdt_header *)dts_addr; + uint8_t device_serial_number[DEVICE_SERIAL_NUMBER_SIZE]; + uint8_t mac_addr[6]; /* Verify FDT header */ ret = fdt_check_header(dts_addr); @@ -96,8 +186,68 @@ int hal_dts_fixup(void* dts_addr) fdt_fixup_str(fdt, off, "chosen", "bootargs", LINUX_BOOTARGS); } - /* TODO: Consider additional FDT fixups: - * ethernet0: local-mac-address {0x00, 0x04, 0xA3, SERIAL2, SERIAL1, SERIAL0} */ + /* Read device serial number from system controller */ + ret = mpfs_read_serial_number(device_serial_number); + if (ret != 0) { + wolfBoot_printf("FDT: Failed to read serial number (%d)\n", ret); + /* Continue without setting MAC addresses */ + return 0; + } + + wolfBoot_printf("FDT: Device serial: %02x%02x%02x%02x-%02x%02x%02x%02x-" + "%02x%02x%02x%02x-%02x%02x%02x%02x\n", + device_serial_number[15], device_serial_number[14], + device_serial_number[13], device_serial_number[12], + device_serial_number[11], device_serial_number[10], + device_serial_number[9], device_serial_number[8], + device_serial_number[7], device_serial_number[6], + device_serial_number[5], device_serial_number[4], + device_serial_number[3], device_serial_number[2], + device_serial_number[1], device_serial_number[0]); + + /* Build MAC address: Microchip OUI + lower 3 bytes of serial number + * Format: {0x00, 0x04, 0xA3, serial[2], serial[1], serial[0]} */ + mac_addr[0] = MICROCHIP_OUI_0; + mac_addr[1] = MICROCHIP_OUI_1; + mac_addr[2] = MICROCHIP_OUI_2; + mac_addr[3] = device_serial_number[2]; + mac_addr[4] = device_serial_number[1]; + mac_addr[5] = device_serial_number[0]; + + wolfBoot_printf("FDT: MAC0 = %02x:%02x:%02x:%02x:%02x:%02x\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + /* Set local-mac-address for ethernet@20110000 (mac0) */ + off = fdt_find_node_offset(fdt, -1, "ethernet@20110000"); + if (off >= 0) { + ret = fdt_setprop(fdt, off, "local-mac-address", mac_addr, 6); + if (ret != 0) { + wolfBoot_printf("FDT: Failed to set mac0 address (%d)\n", ret); + } + } + else { + wolfBoot_printf("FDT: ethernet@20110000 not found\n"); + } + + /* Set local-mac-address for ethernet@20112000 (mac1) + * Use MAC address + 1 for the second interface */ + mac_addr[5] = device_serial_number[0] + 1; + + wolfBoot_printf("FDT: MAC1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + off = fdt_find_node_offset(fdt, -1, "ethernet@20112000"); + if (off >= 0) { + ret = fdt_setprop(fdt, off, "local-mac-address", mac_addr, 6); + if (ret != 0) { + wolfBoot_printf("FDT: Failed to set mac1 address (%d)\n", ret); + } + } + else { + wolfBoot_printf("FDT: ethernet@20112000 not found\n"); + } return 0; } diff --git a/hal/mpfs250.h b/hal/mpfs250.h index fe324444..36c3bda2 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -131,6 +131,39 @@ * ============================================================================ */ #define EMMC_SD_BASE 0x20008000UL +/* ============================================================================ + * System Controller Mailbox + * Control Base: 0x37020000 + * Mailbox RAM: 0x37020800 + * + * Used for system services like reading the device serial number. + * ============================================================================ */ +#define SCBCTRL_BASE 0x37020000UL +#define SCBMBOX_BASE 0x37020800UL + +/* System Services Control and Status Register offsets (from SCBCTRL_BASE) */ +#define SERVICES_CR_OFFSET 0x50u +#define SERVICES_SR_OFFSET 0x54u + +/* Control Register bits */ +#define SERVICES_CR_REQ_MASK 0x01u +#define SERVICES_CR_COMMAND_SHIFT 16 + +/* Status Register bits */ +#define SERVICES_SR_BUSY_MASK 0x02u +#define SERVICES_SR_STATUS_SHIFT 16 + +/* System Service command opcodes */ +#define SYS_SERV_CMD_SERIAL_NUMBER 0x00u + +/* Device serial number size in bytes */ +#define DEVICE_SERIAL_NUMBER_SIZE 16 + +/* System Controller register access */ +#define SCBCTRL_REG(off) (*((volatile uint32_t*)(SCBCTRL_BASE + (off)))) +#define SCBMBOX_REG(off) (*((volatile uint32_t*)(SCBMBOX_BASE + (off)))) +#define SCBMBOX_BYTE(off) (*((volatile uint8_t*)(SCBMBOX_BASE + (off)))) + /* Crypto Engine: Athena F5200 TeraFire Crypto Processor (1x), 200 MHz */ #define ATHENA_BASE (SYSREG_BASE + 0x125000)