STM32N6 boot from eMMC
1. Setup OTP
The default OTP configuration of the chip is to boot from norflash, so you need to modify OTP to boot from EMMC. (Note: OTP can only be modified once, please operate with caution!)
Open STM32CubeProgrammer software, check OTP_FUSES_STM32N6xx in External loaders, as shown below.

On the OTP page, change the boot_source of OTP11 of the STM32N6 chip to 2, indicating booting from EMMC1 (the default 0 is NorFlash booting), as shown below.

If you are using 1.8V IO, HSLV_VDDIO4 of OTP124 also needs to be set to 1 to improve performance. (The power domain of EMMC1 uses VDDIO4)

2. Configure EMMC registers
2.1 Access EXT_CSD registers
The focus is on the configuration of the EXT_CSD[179] register. By reading the EMMC standard document, we can know that the meaning of each bit of this register is as follows:

We should enable Boot partition 1 enable for boot and Boot acknowledge sent during boot operation Bit. This is based on empirical testing, and the ST official document does not mention this. Very important !!
Example code of reading ext_csd[179] register.
uint8_t ext_csd[512];
HAL_MMC_GetCardExtCSD(&MMCHandle, ext_csd, 1000);
printf("EXT_CSD[179] value 0x%x\n", ext_csd[179]);Example code of writing ext_csd[179] register.
uint32_t value = 0x00004800;
status = HAL_MMC_SwitchPartition(&MMCHandle, value);
if (status) {
printf("mmc switch partition failed %d", status);
}Why the write value is 0x00004800? The 0x48 here is actually the value to be written to the ext_csd[179] register to enable the two bits mentioned above.
The above operation only needs to be written once. The access type of EXT_CSD[179] register bit[6] and bit[5:3] is R/W/E type, where E means that the EMMC will save the value when the power is off. In this way, the required configuration will be used for the next power-on startup, and the BOOT can be performed normally.
2.2 CMD command analyse
Going deep into the function HAL_MMC_SwitchPartition, we can find that the function parameter Partition will "OR" the value 0x03B30000 and then sent to EMMC.

Here 03(Hex) represents the access type, and B3(Hex) is the index of the EXT_CSD register to be accessed, which is 179(Dec). So this function can be used to specifically access the EXT_CSD[179] register. If you want to access other registers, the method is similar. The cmd format can reference as below.

2.3 Write FSBL.bin
EMMC has USER partition, BOOT partition 1 and BOOT partition 2. By default, the USER partition is accessed when powering on. You need to switch to the BOOT partition 1 and write FSBL.bin into it. The method is as follows.
Still in the EXT_CSD[179] register, set bits[2:1] of the register to 1, indicating that you want to access the BOOT partition 1.

Simple example code can references as below. HAL_MMC_BOOT_PARTITION1 is a macro defined by ST, and its value is 0x00000100, which is consistent with the register writing method introduced before.
status = HAL_MMC_SwitchPartition(&MMCHandle, HAL_MMC_BOOT_PARTITION1);
if (status) {
printf("mmc switch partition failed %d", status);
}
if(HAL_MMC_WriteBlocks(&MMCHandle, FSBL_trusted, fsbl_start_addr, fsbl_block_num, 1000) != HAL_OK) {
printf("write fsbl failed\n");
}After finished, we can boot from EMMC next time when power on.
