Hello,
I'm trying to create a working fuse provisioning image for programming the fuses of our LS1046A SOCs. I'm following these guides:
The issue I'm hitting is that after enabling POVDD and running the provisioning image, the fuses never get blown. I can see the mirror registers contain the correct expected values when I probe with the codewarrior TAP, but they disappear after a reboot since the fuses are never blown.
When the fuse provisioner, runs I'm getting value 0x19 in the SCRATCHRW4 register. This value indicates an error in writing to the OTPMK (as per include/drivers/nxp/sfp/sfp_error_codes.h
#define ERROR_OTPMK_WRITE 0x19
I found that it is getting set by prog_otpmk() as the result of a write failure (drivers/nxp/sfp/fuse_prov.c):
ret = write_fuses(sfp_ccsr_regs->otpmk, fuse_hdr->otpmk, 8);
if (ret != 0) {
ret = (ret == ERROR_ALREADY_BLOWN) ?
ERROR_OTPMK_ALREADY_BLOWN
: ERROR_OTPMK_WRITE;
} else {
/* Check for DRV hamming error */
if ((sfp_read32((void *)(get_sfp_addr() + SFP_SVHESR_OFFSET))
& SFP_SVHESR_OTPMK_MASK) != 0) {
ret = ERROR_OTPMK_HAMMING_ERROR;
}
}
The error code returned from write_fuses() is ERROR_WRITE which indicates the read back failed:
static int write_fuses(uint32_t *fuse_addr, uint32_t *fuse_hdr_val, uint8_t len)
{
int i;
/* Check if fuse already blown or not */
for (i = 0; i < len; i++) {
if (sfp_read32(&fuse_addr[i]) != 0) {
return ERROR_ALREADY_BLOWN;
}
}
/* Write fuse in mirror registers */
for (i = 0; i < len; i++) {
sfp_write32(&fuse_addr[i], fuse_hdr_val[i]);
}
/* Read back to check if write success */
for (i = 0; i < len; i++) {
if (sfp_read32(&fuse_addr[i]) != fuse_hdr_val[i]) {
return ERROR_WRITE;
}
}
return 0;
}
This aligns with what I would expect to happen, based on the fact that OTPMK cannot be read back by design. This is explicitly mentioned in several documents:
"For obvious reasons, the SFP does not allow the value written to the OTPMK registers to
be read out. Once a non-zero value is written to any of the OTPMK registers, any read
will return all 1s"
Based on this, I'm not sure how this code is intended to work? The write_fuses() function will always fail on OTPMK because the read back will always return all 1's. I also verified this by reading the OTPMK registers in u-boot and observing they only return 1's. Am I misunderstanding or doing something wrong? OTPMK is required to enable secure boot, so surely this must have worked at some point, but it seems to me in the current state this code cannot be used to enable secure boot on Qoriq Trust platforms (although the documentation mentions support for LS1046A). We are using the nxp-qoriq atf v2.6 source code by the way. I checked other source versions and it seems this code hasn't really changed.