Skip to content

Commit 4673c82

Browse files
dgarskedanielinux
authored andcommitted
Add support for fixing up the Ethernet MAC using device serial number (matches U-Boot behavior).
1 parent 46677d7 commit 4673c82

File tree

3 files changed

+197
-8
lines changed

3 files changed

+197
-8
lines changed

docs/Targets.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,8 @@ set architecture riscv:rv64
10941094
### PolarFire Example Boot Output
10951095

10961096
```
1097-
wolfBoot Version: 2.7.0 (Dec 29 2025 11:34:01)
1097+
wolfBoot Version: 2.7.0 (Dec 31 2025 15:33:35)
1098+
Disk encryption enabled
10981099
Reading MBR...
10991100
Found GPT PTE at sector 1
11001101
Found valid boot signature in MBR
@@ -1111,12 +1112,13 @@ disk0.p3 (7_65AFFE00h@ 0_8900000)
11111112
Total partitions on disk0: 4
11121113
Checking primary OS image in 0,1...
11131114
Checking secondary OS image in 0,2...
1114-
Versions, A:1 B:1
1115+
Versions, A:1 B:0
11151116
Load address 0x8E000000
11161117
Attempting boot from P:A
1117-
Boot partition: 0x801FFD80 (sz 19767004, ver 0x1, type 0x601)
1118-
Loading image from disk...done. (846 ms)
1119-
Boot partition: 0x8E000000 (sz 19767004, ver 0x1, type 0x601)
1118+
Boot partition: 0x801FFD90 (sz 19767004, ver 0x0, type 0x0)
1119+
Loading image from disk...done. (877 ms)
1120+
Decrypting image...done. (2894 ms)
1121+
Boot partition: 0x8E000000 (sz 19767004, ver 0x0, type 0x0)
11201122
Checking image integrity...done. (1507 ms)
11211123
Verifying image signature...done. (68 ms)
11221124
Firmware Valid.
@@ -1128,6 +1130,11 @@ Image fdt-1: 0x8A000000 (19897 bytes)
11281130
Loading DTS: 0x8A000000 -> 0x8A000000 (19897 bytes)
11291131
Invalid elf, falling back to raw binary
11301132
Booting at 80200000
1133+
FDT: Version 17, Size 19897
1134+
FDT: Set chosen (13840), bootargs=earlycon root=/dev/mmcblk0p4 rootwait uio_pdrv_genirq.of_id=generic-uio
1135+
FDT: Device serial: 219A437C-6AE1F1C2-8EDC4324-685B2288
1136+
FDT: MAC0 = 00:04:A3:5B:22:88
1137+
FDT: MAC1 = 00:04:A3:5B:22:89
11311138
[ 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
11321139
[ 0.000000] Machine model: Microchip PolarFire-SoC VIDEO Kit
11331140
[ 0.000000] SBI specification v1.0 detected
@@ -1193,7 +1200,6 @@ Benchmark complete
11931200

11941201
### PolarFire TODO
11951202

1196-
* Add support for reading serial number and modifying ethernet MAC in device tree
11971203
* Add support for QSPI NOR flash
11981204
* Add support for full HSS replacement using wolfboot
11991205
- Machine level assembly startup

hal/mpfs250.c

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,89 @@ void hal_init(void)
5656
LIBWOLFBOOT_VERSION_STRING,__DATE__, __TIME__);
5757
}
5858

59+
/* ============================================================================
60+
* System Controller Mailbox Functions
61+
*
62+
* The MPFS system controller provides various system services via a mailbox
63+
* interface. Commands are sent by writing the opcode to the control register
64+
* and responses are read from the mailbox RAM.
65+
* ============================================================================ */
66+
67+
/**
68+
* mpfs_scb_mailbox_busy - Check if the system controller mailbox is busy
69+
*
70+
* Returns: non-zero if busy, 0 if ready
71+
*/
72+
static int mpfs_scb_mailbox_busy(void)
73+
{
74+
return (SCBCTRL_REG(SERVICES_SR_OFFSET) & SERVICES_SR_BUSY_MASK);
75+
}
76+
77+
/**
78+
* mpfs_read_serial_number - Read the device serial number via system services
79+
* @serial: Buffer to store the 16-byte device serial number
80+
*
81+
* This function sends a serial number request (opcode 0x00) to the system
82+
* controller and reads the 16-byte response from the mailbox RAM.
83+
*
84+
* Returns: 0 on success, negative error code on failure
85+
*/
86+
static int mpfs_read_serial_number(uint8_t *serial)
87+
{
88+
uint32_t cmd, status;
89+
int i, timeout;
90+
91+
if (serial == NULL) {
92+
return -1;
93+
}
94+
95+
/* Check if mailbox is busy */
96+
if (mpfs_scb_mailbox_busy()) {
97+
wolfBoot_printf("SCB mailbox busy\n");
98+
return -2;
99+
}
100+
101+
/* Send serial number request command (opcode 0x00)
102+
* Command format: [31:16] = opcode, [0] = request bit */
103+
cmd = (SYS_SERV_CMD_SERIAL_NUMBER << SERVICES_CR_COMMAND_SHIFT) |
104+
SERVICES_CR_REQ_MASK;
105+
SCBCTRL_REG(SERVICES_CR_OFFSET) = cmd;
106+
107+
/* Wait for request bit to clear (command accepted) */
108+
timeout = 10000;
109+
while ((SCBCTRL_REG(SERVICES_CR_OFFSET) & SERVICES_CR_REQ_MASK) && timeout > 0) {
110+
timeout--;
111+
}
112+
if (timeout == 0) {
113+
wolfBoot_printf("SCB mailbox request timeout\n");
114+
return -3;
115+
}
116+
117+
/* Wait for busy bit to clear (command completed) */
118+
timeout = 10000;
119+
while (mpfs_scb_mailbox_busy() && timeout > 0) {
120+
timeout--;
121+
}
122+
if (timeout == 0) {
123+
wolfBoot_printf("SCB mailbox busy timeout\n");
124+
return -4;
125+
}
126+
127+
/* Check status (upper 16 bits of status register) */
128+
status = (SCBCTRL_REG(SERVICES_SR_OFFSET) >> SERVICES_SR_STATUS_SHIFT) & 0xFFFF;
129+
if (status != 0) {
130+
wolfBoot_printf("SCB mailbox error: 0x%x\n", status);
131+
return -5;
132+
}
133+
134+
/* Read serial number from mailbox RAM (16 bytes) */
135+
for (i = 0; i < DEVICE_SERIAL_NUMBER_SIZE; i++) {
136+
serial[i] = SCBMBOX_BYTE(i);
137+
}
138+
139+
return 0;
140+
}
141+
59142
/* Linux kernel command line arguments */
60143
#ifndef LINUX_BOOTARGS
61144
#ifndef LINUX_BOOTARGS_ROOT
@@ -66,10 +149,17 @@ void hal_init(void)
66149
"earlycon root="LINUX_BOOTARGS_ROOT" rootwait uio_pdrv_genirq.of_id=generic-uio"
67150
#endif
68151

152+
/* Microchip OUI (Organizationally Unique Identifier) for MAC address */
153+
#define MICROCHIP_OUI_0 0x00
154+
#define MICROCHIP_OUI_1 0x04
155+
#define MICROCHIP_OUI_2 0xA3
156+
69157
int hal_dts_fixup(void* dts_addr)
70158
{
71159
int off, ret;
72160
struct fdt_header *fdt = (struct fdt_header *)dts_addr;
161+
uint8_t device_serial_number[DEVICE_SERIAL_NUMBER_SIZE];
162+
uint8_t mac_addr[6];
73163

74164
/* Verify FDT header */
75165
ret = fdt_check_header(dts_addr);
@@ -96,8 +186,68 @@ int hal_dts_fixup(void* dts_addr)
96186
fdt_fixup_str(fdt, off, "chosen", "bootargs", LINUX_BOOTARGS);
97187
}
98188

99-
/* TODO: Consider additional FDT fixups:
100-
* ethernet0: local-mac-address {0x00, 0x04, 0xA3, SERIAL2, SERIAL1, SERIAL0} */
189+
/* Read device serial number from system controller */
190+
ret = mpfs_read_serial_number(device_serial_number);
191+
if (ret != 0) {
192+
wolfBoot_printf("FDT: Failed to read serial number (%d)\n", ret);
193+
/* Continue without setting MAC addresses */
194+
return 0;
195+
}
196+
197+
wolfBoot_printf("FDT: Device serial: %02x%02x%02x%02x-%02x%02x%02x%02x-"
198+
"%02x%02x%02x%02x-%02x%02x%02x%02x\n",
199+
device_serial_number[15], device_serial_number[14],
200+
device_serial_number[13], device_serial_number[12],
201+
device_serial_number[11], device_serial_number[10],
202+
device_serial_number[9], device_serial_number[8],
203+
device_serial_number[7], device_serial_number[6],
204+
device_serial_number[5], device_serial_number[4],
205+
device_serial_number[3], device_serial_number[2],
206+
device_serial_number[1], device_serial_number[0]);
207+
208+
/* Build MAC address: Microchip OUI + lower 3 bytes of serial number
209+
* Format: {0x00, 0x04, 0xA3, serial[2], serial[1], serial[0]} */
210+
mac_addr[0] = MICROCHIP_OUI_0;
211+
mac_addr[1] = MICROCHIP_OUI_1;
212+
mac_addr[2] = MICROCHIP_OUI_2;
213+
mac_addr[3] = device_serial_number[2];
214+
mac_addr[4] = device_serial_number[1];
215+
mac_addr[5] = device_serial_number[0];
216+
217+
wolfBoot_printf("FDT: MAC0 = %02x:%02x:%02x:%02x:%02x:%02x\n",
218+
mac_addr[0], mac_addr[1], mac_addr[2],
219+
mac_addr[3], mac_addr[4], mac_addr[5]);
220+
221+
/* Set local-mac-address for ethernet@20110000 (mac0) */
222+
off = fdt_find_node_offset(fdt, -1, "ethernet@20110000");
223+
if (off >= 0) {
224+
ret = fdt_setprop(fdt, off, "local-mac-address", mac_addr, 6);
225+
if (ret != 0) {
226+
wolfBoot_printf("FDT: Failed to set mac0 address (%d)\n", ret);
227+
}
228+
}
229+
else {
230+
wolfBoot_printf("FDT: ethernet@20110000 not found\n");
231+
}
232+
233+
/* Set local-mac-address for ethernet@20112000 (mac1)
234+
* Use MAC address + 1 for the second interface */
235+
mac_addr[5] = device_serial_number[0] + 1;
236+
237+
wolfBoot_printf("FDT: MAC1 = %02x:%02x:%02x:%02x:%02x:%02x\n",
238+
mac_addr[0], mac_addr[1], mac_addr[2],
239+
mac_addr[3], mac_addr[4], mac_addr[5]);
240+
241+
off = fdt_find_node_offset(fdt, -1, "ethernet@20112000");
242+
if (off >= 0) {
243+
ret = fdt_setprop(fdt, off, "local-mac-address", mac_addr, 6);
244+
if (ret != 0) {
245+
wolfBoot_printf("FDT: Failed to set mac1 address (%d)\n", ret);
246+
}
247+
}
248+
else {
249+
wolfBoot_printf("FDT: ethernet@20112000 not found\n");
250+
}
101251

102252
return 0;
103253
}

hal/mpfs250.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,39 @@
131131
* ============================================================================ */
132132
#define EMMC_SD_BASE 0x20008000UL
133133

134+
/* ============================================================================
135+
* System Controller Mailbox
136+
* Control Base: 0x37020000
137+
* Mailbox RAM: 0x37020800
138+
*
139+
* Used for system services like reading the device serial number.
140+
* ============================================================================ */
141+
#define SCBCTRL_BASE 0x37020000UL
142+
#define SCBMBOX_BASE 0x37020800UL
143+
144+
/* System Services Control and Status Register offsets (from SCBCTRL_BASE) */
145+
#define SERVICES_CR_OFFSET 0x50u
146+
#define SERVICES_SR_OFFSET 0x54u
147+
148+
/* Control Register bits */
149+
#define SERVICES_CR_REQ_MASK 0x01u
150+
#define SERVICES_CR_COMMAND_SHIFT 16
151+
152+
/* Status Register bits */
153+
#define SERVICES_SR_BUSY_MASK 0x02u
154+
#define SERVICES_SR_STATUS_SHIFT 16
155+
156+
/* System Service command opcodes */
157+
#define SYS_SERV_CMD_SERIAL_NUMBER 0x00u
158+
159+
/* Device serial number size in bytes */
160+
#define DEVICE_SERIAL_NUMBER_SIZE 16
161+
162+
/* System Controller register access */
163+
#define SCBCTRL_REG(off) (*((volatile uint32_t*)(SCBCTRL_BASE + (off))))
164+
#define SCBMBOX_REG(off) (*((volatile uint32_t*)(SCBMBOX_BASE + (off))))
165+
#define SCBMBOX_BYTE(off) (*((volatile uint8_t*)(SCBMBOX_BASE + (off))))
166+
134167

135168
/* Crypto Engine: Athena F5200 TeraFire Crypto Processor (1x), 200 MHz */
136169
#define ATHENA_BASE (SYSREG_BASE + 0x125000)

0 commit comments

Comments
 (0)