From ec01e13a22c81137a8e673da4355c779016c49e0 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 30 Dec 2025 16:31:03 -0800 Subject: [PATCH 1/6] Fixes for mmc_write. --- hal/mpfs250.c | 144 ++++++++++++++++++++++++-------------------------- hal/mpfs250.h | 4 +- 2 files changed, 71 insertions(+), 77 deletions(-) diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 65e7176c11..4a264a8c3a 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -310,6 +310,14 @@ void mmc_irq_handler(void) /* Check for DMA interrupt */ if (status & EMMC_SD_SRS12_DMAINT) { + /* Read updated DMA address - engine will increment block */ + uint32_t* addr = (uint32_t*)(uintptr_t)((((uint64_t)EMMC_SD_SRS23) << 32) | + EMMC_SD_SRS22); + /* Set new DMA address for next boundary */ + EMMC_SD_SRS22 = (uint32_t)(uintptr_t)addr; + EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)addr) >> 32); + /* triggers next DMA block on write of top bit */ + g_mmc_irq_status |= MMC_IRQ_FLAG_DMAINT; EMMC_SD_SRS12 = EMMC_SD_SRS12_DMAINT; /* Clear interrupt */ } @@ -390,7 +398,6 @@ static int mmc_wait_irq(uint32_t expected_flags, uint32_t timeout) return 0; } } - /* Brief delay while waiting */ asm volatile("nop"); } return -1; /* Timeout */ @@ -591,6 +598,7 @@ static uint32_t mmc_get_response_type(uint8_t resp_type) return cmd_reg; } +#define DEVICE_BUSY 1 static int mmc_send_cmd_internal(uint32_t cmd_type, uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) { @@ -619,24 +627,18 @@ static int mmc_send_cmd_internal(uint32_t cmd_type, while ((EMMC_SD_SRS12 & (EMMC_SD_SRS12_CC | EMMC_SD_SRS12_TC | EMMC_SD_SRS12_EINT)) == 0 && --timeout > 0); - if (timeout == 0 || (EMMC_SD_SRS12 & EMMC_SD_SRS12_EINT)) { - wolfBoot_printf("mmc_send_cmd:%s error SRS12: 0x%08X\n", - (timeout == 0) ? " timeout" : "", EMMC_SD_SRS12); + if (timeout == 0) { + wolfBoot_printf("mmc_send_cmd: timeout waiting for command complete\n"); + status = -1; /* error */ + } + else if (EMMC_SD_SRS12 & EMMC_SD_SRS12_EINT) { + wolfBoot_printf("mmc_send_cmd: error SRS12: 0x%08X\n", EMMC_SD_SRS12); status = -1; /* error */ } EMMC_SD_SRS12 = EMMC_SD_SRS12_CC; /* clear command complete */ while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_CICMD) != 0); - return status; -} - -#define DEVICE_BUSY 1 -int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) -{ - /* send command */ - int status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_NORMAL, cmd_index, - cmd_arg, resp_type); if (status == 0) { /* check for device busy */ if (resp_type == EMMC_SD_RESP_R1 || resp_type == EMMC_SD_RESP_R1B) { @@ -648,8 +650,17 @@ int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) } } + return status; +} + +int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) +{ + /* send command */ + int status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_NORMAL, cmd_index, + cmd_arg, resp_type); + /* clear all status interrupts - * (except current limit, card interrupt/removal/insert) */ + * (except current limit, card interrupt/removal/insert) */ EMMC_SD_SRS12 = ~(EMMC_SD_SRS12_ECL | EMMC_SD_SRS12_CINT | EMMC_SD_SRS12_CR | @@ -737,7 +748,7 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, /* wait for command and data line busy to clear */ while ((EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); - /* set transfer block count */ + /* set transfer block count and block size */ EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | sz; cmd_reg = ((cmd_index << EMMC_SD_SRS03_CIDX_SHIFT) | @@ -762,10 +773,8 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | EMMC_SD_SRS01_DMA_BUFF_512KB | EMMC_SD_BLOCK_SIZE; - /* SDMA mode (for 32-bit transfers) */ + /* SDMA mode */ EMMC_SD_SRS10 |= EMMC_SD_SRS10_DMA_SDMA; - EMMC_SD_SRS15 |= EMMC_SD_SRS15_HV4E; - EMMC_SD_SRS16 &= ~EMMC_SD_SRS16_A64S; /* set SDMA destination address */ EMMC_SD_SRS22 = (uint32_t)(uintptr_t)dst; EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)dst) >> 32); @@ -773,6 +782,10 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, /* Enable SDMA interrupts */ mmc_enable_sdma_interrupts(); } + else { + EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | + EMMC_SD_BLOCK_SIZE; + } } EMMC_SD_SRS02 = block_addr; /* cmd argument */ @@ -780,9 +793,8 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, if (cmd_reg & EMMC_SD_SRS03_DMAE) { while (1) { /* DMA mode with interrupt support */ - /* Wait for DMA interrupt, transfer complete, or error */ - status = mmc_wait_irq(MMC_IRQ_FLAG_DMAINT | MMC_IRQ_FLAG_TC, - 0x00FFFFFF); + /* Wait for transfer complete or error */ + status = mmc_wait_irq(MMC_IRQ_FLAG_TC, 0x00FFFFFF); if (status != 0) { /* Timeout or error */ wolfBoot_printf("mmc_read: SDMA interrupt timeout/error\n"); @@ -795,17 +807,6 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; break; /* Transfer complete */ } - - /* Check for DMA boundary interrupt - need to update address */ - if (g_mmc_irq_status & MMC_IRQ_FLAG_DMAINT) { - g_mmc_irq_status &= ~MMC_IRQ_FLAG_DMAINT; - /* Read updated DMA address - engine will have incremented */ - dst = (uint32_t*)(uintptr_t)((((uint64_t)EMMC_SD_SRS23) << 32) | - EMMC_SD_SRS22); - /* Set new DMA address for next boundary */ - EMMC_SD_SRS22 = (uint32_t)(uintptr_t)dst; - EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)dst) >> 32); - } } /* Disable SDMA interrupts after transfer */ @@ -829,6 +830,10 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, } sz -= read_sz; } + + if (reg & EMMC_SD_SRS12_EINT) { + break; /* error */ + } } } @@ -839,7 +844,7 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, if (cmd_index == MMC_CMD18_READ_MULTIPLE) { (void)mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1); /* use R1B for write */ + EMMC_SD_RESP_R1); } /* wait for idle */ @@ -895,20 +900,15 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, /* wait for command and data line busy to clear */ while ((EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); - /* set transfer block count */ + /* set transfer block count and block size */ EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | sz; - /* Build command register for write: - * - DTDS=0 for write direction (DTDS=1 is read) - * - DPS=1 data present - * - BCE=1 block count enable - * - RECE=1 response error check enable - * - RID=1 response interrupt disable - */ + /* Build command register for write */ cmd_reg = ((cmd_index << EMMC_SD_SRS03_CIDX_SHIFT) | EMMC_SD_SRS03_DPS | /* Data present, no DTDS = write direction */ EMMC_SD_SRS03_BCE | EMMC_SD_SRS03_RECE | EMMC_SD_SRS03_RID | - EMMC_SD_SRS03_RESP_48 | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE); + EMMC_SD_SRS03_RESP_48 | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE + ); if (cmd_index == MMC_CMD25_WRITE_MULTIPLE) { cmd_reg |= EMMC_SD_SRS03_MSBS; /* enable multi-block select */ @@ -930,20 +930,20 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, /* Enable SDMA interrupts */ mmc_enable_sdma_interrupts(); } + else { + /* set transfer block count and block size */ + EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | + EMMC_SD_BLOCK_SIZE; + } } - /* wait for cmd/data line not busy */ - while ((EMMC_SD_SRS09 & - (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); - EMMC_SD_SRS02 = block_addr; /* cmd argument */ EMMC_SD_SRS03 = cmd_reg; /* execute command */ if (cmd_reg & EMMC_SD_SRS03_DMAE) { while (1) { /* DMA mode with interrupt support */ - /* Wait for DMA interrupt, transfer complete, or error */ - status = mmc_wait_irq(MMC_IRQ_FLAG_DMAINT | MMC_IRQ_FLAG_TC, - 0x00FFFFFF); + /* Wait for transfer complete or error */ + status = mmc_wait_irq(MMC_IRQ_FLAG_TC, 0x00FFFFFF); if (status != 0) { /* Timeout or error */ wolfBoot_printf("mmc_write: SDMA interrupt timeout/error\n"); @@ -956,17 +956,6 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; break; /* Transfer complete */ } - - /* Check for DMA boundary interrupt - need to update address */ - if (g_mmc_irq_status & MMC_IRQ_FLAG_DMAINT) { - g_mmc_irq_status &= ~MMC_IRQ_FLAG_DMAINT; - /* Read updated DMA address - engine will have incremented */ - src = (const uint32_t*)(uintptr_t)((((uint64_t)EMMC_SD_SRS23) << 32) | - EMMC_SD_SRS22); - /* Set new DMA address for next boundary */ - EMMC_SD_SRS22 = (uint32_t)(uintptr_t)src; - EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)src) >> 32); - } } /* Disable SDMA interrupts after transfer */ @@ -990,11 +979,14 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, } sz -= write_sz; } - - /* wait for trasnfer complete (or error) */ - while (((reg = EMMC_SD_SRS12) & - (EMMC_SD_SRS12_TC | EMMC_SD_SRS12_EINT)) == 0); + if (reg & EMMC_SD_SRS12_EINT) { + break; /* error */ + } } + + /* wait for transfer complete (or error) BEFORE checking status */ + while (((reg = EMMC_SD_SRS12) & + (EMMC_SD_SRS12_TC | EMMC_SD_SRS12_EINT)) == 0); } /* check for any errors */ @@ -1002,18 +994,17 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, if ((reg & EMMC_SD_SRS12_ERR_STAT) == 0) { /* no errors */ /* if multi-block write, send CMD12 to stop transfer */ if (cmd_index == MMC_CMD25_WRITE_MULTIPLE) { + /* CMD12 requires CMD_ABORT type per SD spec */ status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1B); /* R1B for write with busy */ + EMMC_SD_RESP_R1B); if (status != 0) { wolfBoot_printf("mmc_write: CMD12 stop transfer error\n"); } } - /* wait for card to finish programming (DAT0 goes high when ready) */ - if (status == 0) { - status = mmc_wait_busy(1); - } + /* wait for idle */ + status = mmc_wait_busy(0); } else { wolfBoot_printf("mmc_write: error SRS12: 0x%08X\n", reg); @@ -1393,7 +1384,7 @@ int mmc_init(void) plic_init_mmc(); /* Set initial timeout to 500ms */ - status = mmc_set_timeout(EMMC_SD_DATA_TIMEOUT_US); + status = mmc_set_timeout(EMMC_SD_INIT_TIMEOUT_US); if (status != 0) { return status; } @@ -1548,9 +1539,9 @@ int mmc_init(void) status = mmc_wait_busy(1); } } + irq_restore = EMMC_SD_SRS13; if (status == 0) { /* disable card insert interrupt while changing bus width to avoid false triggers */ - irq_restore = EMMC_SD_SRS13; EMMC_SD_SRS13 = (irq_restore & ~EMMC_SD_SRS13_CINT_SE); status = mmc_set_bus_width(4); @@ -1595,8 +1586,11 @@ int mmc_init(void) status = 0; /* Don't fail init on tuning failure */ } #endif - - EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ + } + EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ + if (status == 0) { + /* Set data timeout to 3000ms */ + status = mmc_set_timeout(EMMC_SD_DATA_TIMEOUT_US); } return status; } @@ -1675,8 +1669,8 @@ int disk_write(int drv, uint64_t start, uint32_t count, const uint8_t *buf) write_sz = EMMC_SD_BLOCK_SIZE; } if (write_sz < EMMC_SD_BLOCK_SIZE || /* partial block */ - start_offset != 0 || /* start not block aligned */ - ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ + start_offset != 0 || /* start not block aligned */ + ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ { /* read-modify-write for partial block */ status = mmc_read(MMC_CMD17_READ_SINGLE, block_addr, diff --git a/hal/mpfs250.h b/hal/mpfs250.h index d2055698d9..6bf9ec9eef 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -817,8 +817,8 @@ #define EMMC_SD_DEBOUNCE_TIME 0x300000U /* Timeout values */ -#define EMMC_SD_DATA_TIMEOUT_US 750000U /* 750ms data timeout */ -#define EMMC_SD_CMD_TIMEOUT_MS 3000U /* 3s command timeout */ +#define EMMC_SD_INIT_TIMEOUT_US (500U * 1000U) /* 500ms init timeout */ +#define EMMC_SD_DATA_TIMEOUT_US (3000U * 1000U) /* 3000ms data timeout */ #define WOLFBOOT_CARDTYPE_SD 1 #define WOLFBOOT_CARDTYPE_EMMC 2 From 1225be46c371f05a94f8ca2a47580e158f4ce6d4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 30 Dec 2025 16:47:02 -0800 Subject: [PATCH 2/6] Support for CUSTOM_ENCRYPT_KEY that allows customer to supply their own implementation --- docs/Targets.md | 15 ++-- docs/encrypted_partitions.md | 49 ++++++++++++ hal/mpfs250.c | 4 +- options.mk | 3 + src/libwolfboot.c | 66 ++++++++++------ src/update_disk.c | 145 +++++++++++++++++++++++++++++------ tools/keytools/sign.c | 3 + 7 files changed, 229 insertions(+), 56 deletions(-) diff --git a/docs/Targets.md b/docs/Targets.md index e3c5a70cb1..0149a14b0a 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1047,23 +1047,20 @@ int wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce); int wolfBoot_erase_encrypt_key(void); /* called automatically by wolfBoot_success() */ ``` +To use your own implementation for getting the encryption key use `CUSTOM_ENCRYPT_KEY` and `OBJS_EXTRA=src/my_custom_encrypt_key.o`. Then provide your own implementation of `int wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce);` + To sign and encrypt an image, create a key file with the concatenated key and nonce, then use the sign tool: ```sh -# Create key file (32-byte key + 16-byte IV for AES-256) -echo -n "0123456789abcdef0123456789abcdef0123456789abcdef" > enc_key.der +# Create key file (32-byte key + 16-byte nonce for AES-256) +printf "0123456789abcdef0123456789abcdef0123456789abcdef" > /tmp/enc_key.der # Sign and encrypt -./tools/keytools/sign --ecc384 --sha384 --aes256 --encrypt enc_key.der \ +./tools/keytools/sign --ecc384 --sha384 --aes256 --encrypt /tmp/enc_key.der \ fitImage wolfboot_signing_private_key.der 1 ``` -In your application, set the encryption key before triggering an update: - -```c -wolfBoot_set_encrypt_key(enc_key, enc_iv); -wolfBoot_update_trigger(); -``` +The result is `fitImage_v1_signed_and_encrypted.bin`, which gets placed into your OFP_A or OFP_B partitions. During boot, wolfBoot decrypts the image headers from disk to select the best candidate, loads and decrypts the full image to RAM, then verifies integrity and authenticity before booting. On successful boot, `wolfBoot_success()` clears the key from RAM. diff --git a/docs/encrypted_partitions.md b/docs/encrypted_partitions.md index 5ac13d2085..c977a95f14 100644 --- a/docs/encrypted_partitions.md +++ b/docs/encrypted_partitions.md @@ -36,6 +36,55 @@ wolfBoot upon next boot. Aside from setting the temporary key, the update mechanism remains the same for distributing, uploading and installing firmware updates through wolfBoot. +### Custom encryption key storage + +You can use the `CUSTOM_ENCRYPT_KEY` option to implement your own functions for: +`wolfBoot_get_encrypt_key`, `wolfBoot_set_encrypt_key` and +`wolfBoot_erase_encrypt_key`. + +To enable: + +1) Add `CUSTOM_ENCRYPT_KEY=1` to your `.config` +2) Add your own .c file using `OBJS_EXTRA`. For example, for your own + `src/custom_encrypt_key.c` add this to your `.config`: + `OBJS_EXTRA=src/custom_encrypt_key.o` + +Your custom implementation must provide these functions: + +```c +int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce); +int wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce); +int wolfBoot_erase_encrypt_key(void); +``` + +Example custom function for testing: + +```c +#include "wolfboot/wolfboot.h" +#include "image.h" + +int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce) +{ + int i; + /* Test key: "0123456789abcdef0123456789abcdef" (32 bytes for AES-256) */ + const char test_key[] = "0123456789abcdef0123456789abcdef"; + /* Test nonce: "0123456789abcdef" (16 bytes) */ + const char test_nonce[] = "0123456789abcdef"; + + for (i = 0; i < ENCRYPT_KEY_SIZE && i < (int)sizeof(test_key); i++) { + key[i] = (uint8_t)test_key[i]; + } + for (i = 0; i < ENCRYPT_NONCE_SIZE && i < (int)sizeof(test_nonce); i++) { + nonce[i] = (uint8_t)test_nonce[i]; + } + return 0; +} +``` + +Note: On platforms that use the src/update_disk.c loader it only reads from a +GPT partition and with ENCRYPT=1 it only needs `wolfBoot_get_encrypt_key` implemented. + + ### Libwolfboot API The API to communicate with the bootloader from the application is expanded when this feature is enabled, diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 4a264a8c3a..f81cb28c80 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -1605,7 +1605,7 @@ int disk_read(int drv, uint64_t start, uint32_t count, uint8_t *buf) uint32_t start_offset = (start % EMMC_SD_BLOCK_SIZE); (void)drv; /* only one drive supported */ -#if 1 //def DEBUG_MMC +#ifdef DEBUG_MMC wolfBoot_printf("disk_read: drv:%d, start:%llu, count:%d, dst:%p\n", drv, start, count, buf); #endif @@ -1657,7 +1657,7 @@ int disk_write(int drv, uint64_t start, uint32_t count, const uint8_t *buf) uint32_t start_offset = (start % EMMC_SD_BLOCK_SIZE); (void)drv; /* only one drive supported */ -#if 1 //def DEBUG_MMC +#ifdef DEBUG_MMC wolfBoot_printf("disk_write: drv:%d, start:%llu, count:%d, src:%p\n", drv, start, count, buf); #endif diff --git a/options.mk b/options.mk index 6af4fa668e..9cd1b84a73 100644 --- a/options.mk +++ b/options.mk @@ -563,6 +563,9 @@ ifeq ($(ENCRYPT),1) endif endif endif + ifeq ($(CUSTOM_ENCRYPT_KEY),1) + CFLAGS+=-D"CUSTOM_ENCRYPT_KEY" + endif endif ifeq ($(EXT_FLASH),1) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index d38084863b..6f573d8271 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -1491,6 +1491,7 @@ static int RAMFUNCTION hal_set_key(const uint8_t *k, const uint8_t *nonce) return ret; #endif } +#ifndef CUSTOM_ENCRYPT_KEY /** * @brief Set the encryption key. * @@ -1545,7 +1546,8 @@ int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce) #endif return 0; } -#endif +#endif /* UNIT_TEST */ + /** * @brief Erase the encryption key. * @@ -1575,6 +1577,7 @@ int RAMFUNCTION wolfBoot_erase_encrypt_key(void) #endif return 0; } +#endif /* !CUSTOM_ENCRYPT_KEY */ #if defined(__WOLFBOOT) || defined(UNIT_TEST) @@ -1585,20 +1588,31 @@ ChaCha chacha; int RAMFUNCTION chacha_init(void) { -#if defined(MMU) || defined(UNIT_TEST) - const uint8_t *key = ENCRYPT_KEY; +#ifdef CUSTOM_ENCRYPT_KEY + uint8_t stored_nonce[ENCRYPT_NONCE_SIZE]; + uint8_t key[ENCRYPT_KEY_SIZE]; #else - const uint8_t *key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + - ENCRYPT_TMP_SECRET_OFFSET); -#endif - uint8_t ff[ENCRYPT_KEY_SIZE]; const uint8_t* stored_nonce; - -#ifdef NVM_FLASH_WRITEONCE - key -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT); + uint8_t *key; #endif + uint8_t ff[ENCRYPT_KEY_SIZE]; +#ifdef CUSTOM_ENCRYPT_KEY + int ret = wolfBoot_get_encrypt_key(key, stored_nonce); + if (ret != 0) + return ret; +#else + #if defined(MMU) || defined(UNIT_TEST) + key = ENCRYPT_KEY; + #else + key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + + ENCRYPT_TMP_SECRET_OFFSET); + #endif + #ifdef NVM_FLASH_WRITEONCE + key -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT); + #endif stored_nonce = key + ENCRYPT_KEY_SIZE; +#endif XMEMSET(&chacha, 0, sizeof(chacha)); @@ -1632,9 +1646,14 @@ Aes aes_dec, aes_enc; */ int aes_init(void) { - int devId; + int devId = INVALID_DEVID; +#if defined(CUSTOM_ENCRYPT_KEY) && !defined(WOLFBOOT_RENESAS_TSIP) + uint8_t stored_nonce[ENCRYPT_NONCE_SIZE]; + uint8_t key[ENCRYPT_KEY_SIZE]; +#else uint8_t *stored_nonce; uint8_t *key; +#endif uint8_t ff[ENCRYPT_KEY_SIZE]; #ifdef WOLFBOOT_RENESAS_TSIP @@ -1645,19 +1664,20 @@ int aes_init(void) key = enc_key->encrypted_user_key; stored_nonce = enc_key->initial_vector; wolfCrypt_Init(); /* required to setup the crypto callback defaults */ -#else /* non TSIP */ - devId = INVALID_DEVID; -#if defined(MMU) || defined(UNIT_TEST) - key = ENCRYPT_KEY; +#elif defined(CUSTOM_ENCRYPT_KEY) + wolfBoot_get_encrypt_key(key, stored_nonce); #else - key = (uint8_t*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + - ENCRYPT_TMP_SECRET_OFFSET); -#endif -#ifdef NVM_FLASH_WRITEONCE - key -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT); -#endif - stored_nonce = key + ENCRYPT_KEY_SIZE; -#endif /* WOLFBOOT_RENESAS_TSIP */ + #if defined(MMU) || defined(UNIT_TEST) + key = ENCRYPT_KEY; + #else + key = (uint8_t*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + + ENCRYPT_TMP_SECRET_OFFSET); + #endif + #ifdef NVM_FLASH_WRITEONCE + key -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT); + #endif + stored_nonce = key + ENCRYPT_KEY_SIZE; +#endif /* non TSIP */ XMEMSET(&aes_enc, 0, sizeof(aes_enc)); XMEMSET(&aes_dec, 0, sizeof(aes_dec)); diff --git a/src/update_disk.c b/src/update_disk.c index dbc832355b..614eedf0e7 100644 --- a/src/update_disk.c +++ b/src/update_disk.c @@ -52,6 +52,9 @@ defined(ENCRYPT_WITH_CHACHA) #define DISK_ENCRYPT #include "encrypt.h" + +/* Module-level storage for encryption nonce */ +static uint8_t disk_encrypt_nonce[ENCRYPT_NONCE_SIZE]; #endif #include @@ -91,6 +94,92 @@ #endif #ifdef DISK_ENCRYPT + +/* Module-level storage for encryption key */ +static uint8_t disk_encrypt_key[ENCRYPT_KEY_SIZE]; + +/** + * @brief Get the version from an already-decrypted header. + * + * This function extracts the version from a decrypted header blob + * without calling wolfBoot_get_blob_version, which might try to + * decrypt again if EXT_ENCRYPTED && MMU is defined. + * + * @param hdr Pointer to the decrypted header. + * + * @return The version number, or 0 if not found. + */ +static uint32_t get_decrypted_blob_version(uint8_t *hdr) +{ + uint32_t *magic = (uint32_t *)hdr; + uint16_t tlv_type, tlv_len; + uint8_t *p = hdr + IMAGE_HEADER_OFFSET; + uint8_t *max_p = hdr + IMAGE_HEADER_SIZE; + + if (*magic != WOLFBOOT_MAGIC) + return 0; + + /* Search for version TLV */ + while (p + 4 < max_p) { + tlv_type = *((uint16_t*)p); + tlv_len = *((uint16_t*)(p + 2)); + + if (tlv_type == 0 || tlv_type == 0xFFFF) + break; + + /* Skip padding bytes */ + if ((p[0] == 0xFF) || ((((uintptr_t)p) & 0x01) != 0)) { + p++; + continue; + } + + if (tlv_type == HDR_VERSION && tlv_len == 4) { + uint32_t ver = *((uint32_t*)(p + 4)); + return ver; + } + + p += 4 + tlv_len; + } + return 0; +} + +/** + * @brief Set up decryption context with IV at specified block offset. + * + * This function sets up the AES/ChaCha context with the IV positioned + * at the specified block offset. It matches how sign.c sets up encryption. + * + * @param block_offset Block offset for IV counter (0 = start of image). + */ +static void disk_crypto_set_iv(uint32_t block_offset) +{ +#if defined(ENCRYPT_WITH_CHACHA) + wc_Chacha_SetIV(&chacha, disk_encrypt_nonce, block_offset); +#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256) + /* For AES CTR, we need to construct the IV with the counter. + * The sign tool uses the IV directly without byte-reversal, + * so we must match that behavior here. */ + uint8_t iv[ENCRYPT_BLOCK_SIZE]; + uint32_t ctr; + + /* Copy nonce/IV (first 12 bytes for CTR nonce, last 4 for counter) */ + memcpy(iv, disk_encrypt_nonce, ENCRYPT_NONCE_SIZE); + + /* Add block offset to the counter portion (last 4 bytes, big-endian) */ + /* The IV from sign.c is already in the correct format, we just need + * to add the block offset to the counter portion */ + ctr = ((uint32_t)iv[12] << 24) | ((uint32_t)iv[13] << 16) | + ((uint32_t)iv[14] << 8) | (uint32_t)iv[15]; + ctr += block_offset; + iv[12] = (uint8_t)(ctr >> 24); + iv[13] = (uint8_t)(ctr >> 16); + iv[14] = (uint8_t)(ctr >> 8); + iv[15] = (uint8_t)(ctr); + + wc_AesSetIV(&aes_dec, iv); +#endif +} + /** * @brief Decrypt an image header in RAM. * @@ -104,13 +193,14 @@ */ static int decrypt_header(const uint8_t *src, uint8_t *dst) { - uint32_t i; uint32_t magic; - for (i = 0; i < IMAGE_HEADER_SIZE; i += ENCRYPT_BLOCK_SIZE) { - wolfBoot_crypto_set_iv(NULL, i / ENCRYPT_BLOCK_SIZE); - crypto_decrypt(dst + i, src + i, ENCRYPT_BLOCK_SIZE); - } + /* Reset IV to start of image (block 0) */ + disk_crypto_set_iv(0); + + /* Decrypt header - CTR mode handles counter increment internally */ + crypto_decrypt(dst, src, IMAGE_HEADER_SIZE); + magic = *((uint32_t*)dst); if (magic != WOLFBOOT_MAGIC) return -1; @@ -130,22 +220,12 @@ static int decrypt_header(const uint8_t *src, uint8_t *dst) */ static int decrypt_image(uint8_t *data, uint32_t size) { - uint32_t iv_counter = 0; - uint32_t offset = 0; - uint8_t dec_block[ENCRYPT_BLOCK_SIZE]; + /* Reset IV to start of image (block 0) */ + disk_crypto_set_iv(0); - while (offset < size) { - uint32_t chunk = size - offset; - if (chunk > ENCRYPT_BLOCK_SIZE) - chunk = ENCRYPT_BLOCK_SIZE; + /* Decrypt entire image - CTR mode handles counter increment internally */ + crypto_decrypt(data, data, size); - wolfBoot_crypto_set_iv(NULL, iv_counter); - crypto_decrypt(dec_block, data + offset, chunk); - memcpy(data + offset, dec_block, chunk); - - offset += ENCRYPT_BLOCK_SIZE; - iv_counter++; - } return 0; } #endif /* DISK_ENCRYPT */ @@ -189,11 +269,17 @@ void RAMFUNCTION wolfBoot_start(void) uint64_t start_us, elapsed_ms; #ifdef DISK_ENCRYPT - /* Initialize encryption */ + /* Initialize encryption - this sets up the cipher with key from storage */ if (wolfBoot_initialize_encryption() != 0) { wolfBoot_printf("Error initializing encryption\r\n"); wolfBoot_panic(); } + /* Retrieve encryption key and nonce for disk decryption */ + if (wolfBoot_get_encrypt_key(disk_encrypt_key, disk_encrypt_nonce) != 0) { + wolfBoot_printf("Error getting encryption key\r\n"); + wolfBoot_panic(); + } + wolfBoot_printf("Disk encryption enabled\r\n"); #endif ret = disk_init(BOOT_DISK); @@ -212,7 +298,9 @@ void RAMFUNCTION wolfBoot_start(void) == IMAGE_HEADER_SIZE) { #ifdef DISK_ENCRYPT if (decrypt_header(p_hdr, dec_hdr) == 0) { - pA_ver = wolfBoot_get_blob_version(dec_hdr); + /* Use local version parser to avoid double-decryption issue + * when EXT_ENCRYPTED && MMU is also defined */ + pA_ver = get_decrypted_blob_version(dec_hdr); } #else pA_ver = wolfBoot_get_blob_version((uint8_t*)p_hdr); @@ -225,7 +313,9 @@ void RAMFUNCTION wolfBoot_start(void) == IMAGE_HEADER_SIZE) { #ifdef DISK_ENCRYPT if (decrypt_header(p_hdr, dec_hdr) == 0) { - pB_ver = wolfBoot_get_blob_version(dec_hdr); + /* Use local version parser to avoid double-decryption issue + * when EXT_ENCRYPTED && MMU is also defined */ + pB_ver = get_decrypted_blob_version(dec_hdr); } #else pB_ver = wolfBoot_get_blob_version((uint8_t*)p_hdr); @@ -275,8 +365,19 @@ void RAMFUNCTION wolfBoot_start(void) continue; } +#ifdef DISK_ENCRYPT + /* Decrypt header to parse image size */ + if (decrypt_header(p_hdr, dec_hdr) != 0) { + wolfBoot_printf("Error decrypting header for %s\r\n", part_name); + selected ^= 1; + continue; + } + memset(&os_image, 0, sizeof(os_image)); + ret = wolfBoot_open_image_address(&os_image, (void*)dec_hdr); +#else memset(&os_image, 0, sizeof(os_image)); ret = wolfBoot_open_image_address(&os_image, (void*)p_hdr); +#endif if (ret < 0) { wolfBoot_printf("Error parsing loaded image\r\n"); selected ^= 1; diff --git a/tools/keytools/sign.c b/tools/keytools/sign.c index 712b1c8bac..b888fc59c9 100644 --- a/tools/keytools/sign.c +++ b/tools/keytools/sign.c @@ -1808,6 +1808,8 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz, fsize = ftell(f); fseek(f, 0, SEEK_SET); /* restart the _signed file from 0 */ + printf("Encrypting %u bytes...\n", fsize); + if (CMD.encrypt == ENC_CHACHA) { ChaCha cha; #ifndef HAVE_CHACHA @@ -1845,6 +1847,7 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz, } } fclose(fef); + printf("Encryption complete.\n"); } printf("Output image(s) successfully created.\n"); ret = 0; From 5313203e5e06b99b2b527d7af8142c4d116c03ba Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 31 Dec 2025 09:57:37 -0800 Subject: [PATCH 3/6] Add eMMC support. --- config/examples/polarfire_mpfs250.config | 9 +- hal/mpfs250.c | 644 ++++++++++++++++------- hal/mpfs250.h | 40 ++ 3 files changed, 515 insertions(+), 178 deletions(-) diff --git a/config/examples/polarfire_mpfs250.config b/config/examples/polarfire_mpfs250.config index 36e3411fea..bc86fe7875 100644 --- a/config/examples/polarfire_mpfs250.config +++ b/config/examples/polarfire_mpfs250.config @@ -31,6 +31,10 @@ NO_ARM_ASM?=0 # Optional: Use smaller SHA512 #CFLAGS_EXTRA+=-DUSE_SLOW_SHA512 +# SDCard (default) +# Optionally use eMMC +#CFLAGS+=-DUSE_EMMC + # DDR Address for wolfBoot to start from WOLFBOOT_ORIGIN?=0x80000000 @@ -45,20 +49,23 @@ WOLFBOOT_LOAD_ADDRESS?=0x8E000000 WOLFBOOT_NO_PARTITIONS=1 CFLAGS_EXTRA+=-DBOOT_PART_A=1 CFLAGS_EXTRA+=-DBOOT_PART_B=2 -# Speed up disk partition read (512KB chunks) +# Speed up disk partition read (512KB chunks - max DMA size) CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000 # DTS (Device Tree) WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000 # Optional Encryption +#CUSTOM_ENCRYPT_KEY=1 #ENCRYPT=1 #ENCRYPT_WITH_AES256=1 +#OBJS_EXTRA=src/my_custom_encrypt_key.o # Optional EMMC_SD debugging logs #CFLAGS_EXTRA+=-DDEBUG_MMC # Optional disk debugging logs #CFLAGS_EXTRA+=-DDEBUG_DISK +#CFLAGS_EXTRA+=-DDISK_TEST # Used by test-application for ELF WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80200000 diff --git a/hal/mpfs250.c b/hal/mpfs250.c index f81cb28c80..30e8cc505f 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -717,6 +717,437 @@ int mmc_card_init(uint32_t acmd41_arg, uint32_t *ocr_reg) return status; } +#ifndef USE_EMMC +/* ========================================================================== + * SD Card-specific Initialization Functions + * ========================================================================== */ + +/* Forward declarations - defined later in the file */ +static uint32_t get_srs_bits(int from, int count); +int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t sz); +int mmc_set_bus_width(uint32_t bus_width); +int mmc_set_function(uint32_t function_number, uint32_t group_number); +#ifdef ENABLE_MMC_SD_TUNING +static int mmc_tune(uint8_t phy_addr, uint32_t clk_khz); +#endif + +/* Full SD card initialization sequence + * Returns 0 on success */ +static int sdcard_card_full_init(void) +{ + int status = 0; + uint32_t reg; + uint32_t ctrl_volts, card_volts; + uint32_t irq_restore; + int xpc, si8r; + + /* Set power to 3.3v and send init commands */ + ctrl_volts = EMMC_SD_SRS10_BVS_3_3V; /* default to 3.3v */ + status = mmc_power_init_seq(ctrl_volts); + if (status == 0) { + uint32_t max_ma_3_3v, max_ma_1_8v; + /* determine host controller capabilities */ + reg = EMMC_SD_SRS18; + max_ma_3_3v = ((reg & EMMC_SD_SRS18_MC33_MASK) >> EMMC_SD_SRS18_MC33_SHIFT) * 4; + max_ma_1_8v = ((reg & EMMC_SD_SRS18_MC18_MASK) >> EMMC_SD_SRS18_MC18_SHIFT) * 4; + /* does controller support eXtended Power Control (XPC)? */ + xpc = (max_ma_1_8v >= 150) && (max_ma_3_3v >= 150) ? 1 : 0; + /* does controller support UHS-I (Ultra High Speed Interface) v1.8 signaling? */ + si8r = ((EMMC_SD_SRS16 & EMMC_SD_SRS16_VS18) && /* 1.8v supported */ + (EMMC_SD_SRS17 & (EMMC_SD_SRS17_DDR50 | /* DDR50, SDR104 or SDR50 supported */ + EMMC_SD_SRS17_SDR104 | + EMMC_SD_SRS17_SDR50))) ? 1 : 0; + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: xpc:%d, si8r:%d, max_ma (3.3v:%d 1.8v:%d)\n", + xpc, si8r, max_ma_3_3v, max_ma_1_8v); + #endif + } + + if (status == 0) { + reg = 0; + /* get operating conditions */ + status = mmc_card_init(0, ®); + if (status == 0) { + /* pick host and card operating voltages */ + if (reg & SDCARD_REG_OCR_3_3_3_4) { /* 3.3v - 3.4v */ + card_volts = SDCARD_REG_OCR_3_3_3_4; + } + else if (reg & SDCARD_REG_OCR_3_2_3_3) { /* 3.2v - 3.3v */ + card_volts = SDCARD_REG_OCR_3_2_3_3; + } + else if (reg & SDCARD_REG_OCR_3_1_3_2) { /* 3.1v - 3.2v */ + card_volts = SDCARD_REG_OCR_3_1_3_2; + } + else if (reg & SDCARD_REG_OCR_3_0_3_1) { /* 3.0v - 3.1v */ + card_volts = SDCARD_REG_OCR_3_0_3_1; + ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; + } + else if (reg & SDCARD_REG_OCR_2_9_3_0) { /* 2.9v - 3.0v */ + card_volts = SDCARD_REG_OCR_2_9_3_0; + ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; + } + else { /* default to v3.3 */ + card_volts = SDCARD_REG_OCR_3_3_3_4; + } + /* if needed change operating voltage and re-init */ + if (ctrl_volts != EMMC_SD_SRS10_BVS_3_3V) { + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: changing operating voltage to 3.0v\n"); + #endif + status = mmc_power_init_seq(ctrl_volts); + } + } + } + + if (status == 0) { + /* configure operating conditions */ + uint32_t cmd_arg = SDCARD_ACMD41_HCS; + cmd_arg |= card_volts; + if (si8r) { + cmd_arg |= SDCARD_REG_OCR_S18RA; + } + if (xpc) { + cmd_arg |= SDCARD_REG_OCR_XPC; + } + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: sending OCR arg: 0x%08X\n", cmd_arg); + #endif + + /* retry until OCR ready */ + do { + status = mmc_card_init(cmd_arg, ®); + } while (status == 0 && (reg & SDCARD_REG_OCR_READY) == 0); + } + + if (status == 0) { + /* Get card identification */ + status = mmc_send_cmd(MMC_CMD2_ALL_SEND_CID, 0, EMMC_SD_RESP_R2); + } + + if (status == 0) { + /* Set relative address - SD card assigns its own RCA */ + status = mmc_send_cmd(MMC_CMD3_SET_REL_ADDR, 0, EMMC_SD_RESP_R6); + } + + if (status == 0) { + g_rca = ((EMMC_SD_SRS04 >> SD_RCA_SHIFT) & 0xFFFF); + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: rca: %d\n", g_rca); + #endif + } + + if (status == 0) { + /* read CSD register from device */ + status = mmc_send_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, + EMMC_SD_RESP_R2); + } + + if (status == 0) { + /* Get sector size and count */ + uint32_t csd_struct; + uint32_t bl_len, c_size, c_size_mult; + bl_len = get_srs_bits(22, 4); + g_sector_size = (1U << bl_len); + + csd_struct = get_srs_bits(126, 2); + switch (csd_struct) { + case 0: + c_size = get_srs_bits(62, 12); + c_size_mult = get_srs_bits(47, 3); + g_sector_count = (c_size + 1) << (c_size_mult + 2); + break; + case 1: + c_size = get_srs_bits(48, 22); + g_sector_count = (c_size + 1) << 10; + break; + default: + /* invalid CSD structure */ + status = -1; + break; + } + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: csd_version: %d, sector: size %d count %d\n", + csd_struct, g_sector_size, g_sector_count); + #endif + } + + if (status == 0) { + /* select card */ + status = mmc_send_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, + EMMC_SD_RESP_R1B); + if (status == DEVICE_BUSY) { + status = mmc_wait_busy(1); + } + } + + irq_restore = EMMC_SD_SRS13; + if (status == 0) { + /* disable card insert interrupt while changing bus width to avoid false triggers */ + EMMC_SD_SRS13 = (irq_restore & ~EMMC_SD_SRS13_CINT_SE); + + status = mmc_set_bus_width(4); + } + + if (status == 0) { + /* Get SCR registers - 8 bytes */ + uint32_t scr_reg[SCR_REG_DATA_SIZE/sizeof(uint32_t)]; + status = mmc_read(SD_ACMD51_SEND_SCR, 0, scr_reg, + sizeof(scr_reg)); + } + + if (status == 0) { + /* set UHS mode to SDR25 and driver strength to Type B */ + uint32_t card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR25; + status = mmc_set_function(card_access_mode, 1); + if (status == 0) { + /* set driver strength */ + reg = EMMC_SD_SRS15; + reg &= ~EMMC_SD_SRS15_DSS_MASK; + reg |= EMMC_SD_SRS15_DSS_TYPE_B; /* default */ + EMMC_SD_SRS15 = reg; + + /* enable high speed */ + EMMC_SD_SRS10 |= EMMC_SD_SRS10_HSE; + + /* set UHS mode */ + reg = EMMC_SD_SRS15; + reg &= ~EMMC_SD_SRS15_UMS_MASK; + reg |= EMMC_SD_SRS15_UMS_SDR25; + EMMC_SD_SRS15 = reg; + } + } + + if (status == 0) { + mmc_set_clock(EMMC_SD_CLK_50MHZ); + +#ifdef ENABLE_MMC_SD_TUNING + /* PHY training for SDR25 at 50MHz */ + status = mmc_tune(EMMC_SD_PHY_ADDR_UHSI_SDR25, EMMC_SD_CLK_50MHZ); + if (status != 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("sdcard_init: tuning failed, continuing\n"); + #endif + status = 0; /* Don't fail init on tuning failure */ + } +#endif + } + + EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ + + return status; +} +#endif /* !USE_EMMC */ + +#ifdef USE_EMMC +/* ========================================================================== + * eMMC-specific Initialization Functions + * ========================================================================== */ + +/* Forward declaration - defined later in the file */ +static uint32_t get_srs_bits(int from, int count); + +/* Send CMD1 (SEND_OP_COND) for eMMC and wait for device ready + * Returns 0 on success, negative on error */ +static int emmc_send_op_cond(uint32_t ocr_arg, uint32_t *ocr_reg) +{ + int status; + uint32_t timeout = 1000; /* retry count */ + uint32_t response; + + /* First CMD1 to query supported voltages */ + status = mmc_send_cmd(MMC_CMD1_SEND_OP_COND, 0, EMMC_SD_RESP_R3); + if (status != 0) { + wolfBoot_printf("eMMC: CMD1 query failed\n"); + return status; + } + + /* Get OCR from response */ + response = EMMC_SD_SRS04; +#ifdef DEBUG_MMC + wolfBoot_printf("eMMC: Initial OCR: 0x%08X\n", response); +#endif + + /* Loop sending CMD1 with operating conditions until device is ready */ + do { + status = mmc_send_cmd(MMC_CMD1_SEND_OP_COND, ocr_arg, EMMC_SD_RESP_R3); + if (status != 0) { + wolfBoot_printf("eMMC: CMD1 failed\n"); + return status; + } + + response = EMMC_SD_SRS04; + + /* Check if device is ready (busy bit cleared = ready) */ + if (response & MMC_OCR_BUSY_BIT) { + /* Device is ready */ + if (ocr_reg != NULL) { + *ocr_reg = response; + } +#ifdef DEBUG_MMC + wolfBoot_printf("eMMC: Device ready, OCR: 0x%08X\n", response); +#endif + return 0; + } + + /* Small delay between retries */ + for (volatile int i = 0; i < 1000; i++); + + } while (--timeout > 0); + + wolfBoot_printf("eMMC: Timeout waiting for device ready\n"); + return -1; +} + +/* Set eMMC bus width using CMD6 SWITCH command + * width: MMC_EXT_CSD_WIDTH_1BIT, MMC_EXT_CSD_WIDTH_4BIT, or MMC_EXT_CSD_WIDTH_8BIT + * Returns 0 on success */ +static int emmc_set_bus_width(uint32_t width) +{ + int status; + uint32_t cmd_arg; + + /* Build CMD6 argument: Access=Write Byte, Index=183 (BUS_WIDTH), Value=width */ + cmd_arg = MMC_DW_CSD | (width << 8); + +#ifdef DEBUG_MMC + wolfBoot_printf("eMMC: Setting bus width to %d (CMD6 arg: 0x%08X)\n", + (width == MMC_EXT_CSD_WIDTH_4BIT) ? 4 : + (width == MMC_EXT_CSD_WIDTH_8BIT) ? 8 : 1, cmd_arg); +#endif + + /* Send CMD6 SWITCH */ + status = mmc_send_cmd(MMC_CMD6_SWITCH, cmd_arg, EMMC_SD_RESP_R1B); + if (status == DEVICE_BUSY) { + status = mmc_wait_busy(1); + } + + if (status != 0) { + wolfBoot_printf("eMMC: Set bus width failed\n"); + return status; + } + + /* Update host controller bus width */ + if (width == MMC_EXT_CSD_WIDTH_4BIT || width == MMC_EXT_CSD_WIDTH_4BIT_DDR) { + EMMC_SD_SRS10 |= EMMC_SD_SRS10_DTW; + EMMC_SD_SRS10 &= ~EMMC_SD_SRS10_EDTW; + g_bus_width = 4; + } + else if (width == MMC_EXT_CSD_WIDTH_8BIT || width == MMC_EXT_CSD_WIDTH_8BIT_DDR) { + EMMC_SD_SRS10 |= EMMC_SD_SRS10_EDTW; + g_bus_width = 8; + } + else { + EMMC_SD_SRS10 &= ~(EMMC_SD_SRS10_DTW | EMMC_SD_SRS10_EDTW); + g_bus_width = 1; + } + + return 0; +} + +/* Full eMMC card initialization sequence + * Returns 0 on success */ +static int emmc_card_full_init(void) +{ + int status; + uint32_t ocr_reg; + + /* Send CMD0 (GO_IDLE) to reset eMMC */ + status = mmc_send_cmd(MMC_CMD0_GO_IDLE, 0, EMMC_SD_RESP_NONE); + if (status != 0) { + wolfBoot_printf("eMMC: CMD0 failed\n"); + return status; + } + + /* Small delay after reset */ + for (volatile int i = 0; i < 10000; i++); + + /* Send CMD1 with operating conditions (3.3V, sector mode) */ + status = emmc_send_op_cond(MMC_DEVICE_3_3V_VOLT_SET, &ocr_reg); + if (status != 0) { + return status; + } + + /* CMD2 - Get CID (card identification) */ + status = mmc_send_cmd(MMC_CMD2_ALL_SEND_CID, 0, EMMC_SD_RESP_R2); + if (status != 0) { + wolfBoot_printf("eMMC: CMD2 failed\n"); + return status; + } + + /* CMD3 - Set relative address (host assigns RCA for eMMC) */ + g_rca = MMC_EMMC_RCA_DEFAULT; + status = mmc_send_cmd(MMC_CMD3_SET_REL_ADDR, g_rca << SD_RCA_SHIFT, + EMMC_SD_RESP_R1); + if (status != 0) { + wolfBoot_printf("eMMC: CMD3 failed\n"); + return status; + } + +#ifdef DEBUG_MMC + wolfBoot_printf("eMMC: RCA set to %d\n", g_rca); +#endif + + /* CMD9 - Get CSD (card-specific data) */ + status = mmc_send_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, + EMMC_SD_RESP_R2); + if (status != 0) { + wolfBoot_printf("eMMC: CMD9 failed\n"); + return status; + } + + /* Parse CSD to get sector size/count */ + { + uint32_t csd_struct, c_size; + uint32_t bl_len = get_srs_bits(22, 4); + g_sector_size = (1U << bl_len); + + csd_struct = get_srs_bits(126, 2); + /* eMMC typically uses CSD version 3 (EXT_CSD) with fixed 512-byte sectors */ + if (csd_struct >= 2) { + /* For eMMC, actual capacity is in EXT_CSD, use default for now */ + g_sector_size = 512; + g_sector_count = 0; /* Will be read from EXT_CSD if needed */ + } + else { + /* Legacy CSD parsing */ + c_size = get_srs_bits(48, 22); + g_sector_count = (c_size + 1) << 10; + } + +#ifdef DEBUG_MMC + wolfBoot_printf("eMMC: CSD version %d, sector size %d\n", + csd_struct, g_sector_size); +#endif + } + + /* CMD7 - Select card */ + status = mmc_send_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, + EMMC_SD_RESP_R1B); + if (status == DEVICE_BUSY) { + status = mmc_wait_busy(1); + } + if (status != 0) { + wolfBoot_printf("eMMC: CMD7 failed\n"); + return status; + } + + /* Set bus width to 4-bit */ + status = emmc_set_bus_width(MMC_EXT_CSD_WIDTH_4BIT); + if (status != 0) { + wolfBoot_printf("eMMC: Set bus width failed, continuing with 1-bit\n"); + /* Non-fatal, continue with 1-bit */ + } + + /* Set clock to 25MHz for legacy mode */ + mmc_set_clock(EMMC_SD_CLK_25MHZ); + + /* Enable high speed if desired (optional for legacy mode) */ + EMMC_SD_SRS10 |= EMMC_SD_SRS10_HSE; + + return 0; +} +#endif /* USE_EMMC */ + /* MMC_CMD17_READ_SINGLE, MMC_CMD18_READ_MULTIPLE */ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t sz) @@ -1330,9 +1761,6 @@ int mmc_init(void) { int status = 0; uint32_t reg, cap; - uint32_t ctrl_volts, card_volts; - uint32_t irq_restore; - int xpc, si8r; /* Reset the MMC controller */ SYSREG_SOFT_RESET_CR &= ~SYSREG_SOFT_RESET_CR_MMC; @@ -1347,10 +1775,14 @@ int mmc_init(void) EMMC_SD_HRS01 = ((EMMC_SD_DEBOUNCE_TIME << EMMC_SD_HRS01_DP_SHIFT) & EMMC_SD_HRS01_DP_MASK); - /* Select SDCard Mode */ + /* Select card mode */ reg = EMMC_SD_HRS06; reg &= ~EMMC_SD_HRS06_EMM_MASK; - reg |= EMMC_SD_HRS06_MODE_SD; +#ifdef USE_EMMC + reg |= EMMC_SD_HRS06_MODE_LEGACY; /* eMMC Legacy mode */ +#else + reg |= EMMC_SD_HRS06_MODE_SD; /* SD card mode */ +#endif EMMC_SD_HRS06 = reg; /* Clear error/interrupt status */ @@ -1397,11 +1829,14 @@ int mmc_init(void) /* card not inserted or not stable */ return -1; } - /* NOTE: if using eMMC mode skip this check */ +#ifndef USE_EMMC + /* For SD card: check if card is inserted + * (eMMC is soldered on board, skip this check) */ if ((reg & EMMC_SD_SRS09_CI) == 0) { /* card not inserted */ return -1; } +#endif /* Start in 1-bit bus mode */ EMMC_SD_SRS10 &= ~(EMMC_SD_SRS10_EDTW | EMMC_SD_SRS10_DTW); @@ -1409,185 +1844,40 @@ int mmc_init(void) /* Setup 400khz starting clock */ mmc_set_clock(EMMC_SD_CLK_400KHZ); - /* Set power to 3.3v and send init commands */ - ctrl_volts = EMMC_SD_SRS10_BVS_3_3V; /* default to 3.3v */ - status = mmc_power_init_seq(ctrl_volts); - if (status == 0) { - uint32_t max_ma_3_3v, max_ma_1_8v; - /* determine host controller capabilities */ - reg = EMMC_SD_SRS18; - max_ma_3_3v = ((reg & EMMC_SD_SRS18_MC33_MASK) >> EMMC_SD_SRS18_MC33_SHIFT) * 4; - max_ma_1_8v = ((reg & EMMC_SD_SRS18_MC18_MASK) >> EMMC_SD_SRS18_MC18_SHIFT) * 4; - /* does controller support eXtended Power Control (XPC)? */ - xpc = (max_ma_1_8v >= 150) && (max_ma_3_3v >= 150) ? 1 : 0; - /* does controller support UHS-I (Ultra High Speed Interface) v1.8 signaling? */ - si8r =((EMMC_SD_SRS16 & EMMC_SD_SRS16_VS18) && /* 1.8v supported */ - (EMMC_SD_SRS17 & (EMMC_SD_SRS17_DDR50 | /* DDR50, SDR104 or SDR50 supported */ - EMMC_SD_SRS17_SDR104 | - EMMC_SD_SRS17_SDR50))) ? 1: 0; - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: xpc:%d, si8r:%d, max_ma (3.3v:%d 1.8v:%d)\n", - xpc, si8r, max_ma_3_3v, max_ma_1_8v); - #endif - } - if (status == 0) { - reg = 0; - /* get operating conditions */ - status = mmc_card_init(0, ®); - if (status == 0) { - /* pick host and card operating voltages */ - if (reg & SDCARD_REG_OCR_3_3_3_4) { /* 3.3v - 3.4v */ - card_volts = SDCARD_REG_OCR_3_3_3_4; - } - else if (reg & SDCARD_REG_OCR_3_2_3_3) { /* 3.2v - 3.3v */ - card_volts = SDCARD_REG_OCR_3_2_3_3; - } - else if (reg & SDCARD_REG_OCR_3_1_3_2) { /* 3.1v - 3.2v */ - card_volts = SDCARD_REG_OCR_3_1_3_2; - } - else if (reg & SDCARD_REG_OCR_3_0_3_1) { /* 3.0v - 3.1v */ - card_volts = SDCARD_REG_OCR_3_0_3_1; - ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; - } - else if (reg & SDCARD_REG_OCR_2_9_3_0) { /* 2.9v - 3.0v */ - card_volts = SDCARD_REG_OCR_2_9_3_0; - ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; - } - else { /* default to v3.3 */ - card_volts = SDCARD_REG_OCR_3_3_3_4; - } - /* if needed change operating volage and re-init */ - if (ctrl_volts != EMMC_SD_SRS10_BVS_3_3V) { - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: changing operating voltage to 3.0v\n"); - #endif - status = mmc_power_init_seq(ctrl_volts); - } - } - } - if (status == 0) { - /* configure operating conditions */ - uint32_t cmd_arg = SDCARD_ACMD41_HCS; - cmd_arg |= card_volts; - if (si8r) { - cmd_arg |= SDCARD_REG_OCR_S18RA; - } - if (xpc) { - cmd_arg |= SDCARD_REG_OCR_XPC; - } - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: sending OCR arg: 0x%08X\n", cmd_arg); - #endif +#ifdef USE_EMMC + /* ========================================================================= + * eMMC Initialization Path + * ========================================================================= */ - /* retry until OCR ready */ - do { - status = mmc_card_init(cmd_arg, ®); - } while (status == 0 && (reg & SDCARD_REG_OCR_READY) == 0); - } - if (status == 0) { - /* Get card identification */ - status = mmc_send_cmd(MMC_CMD2_ALL_SEND_CID, 0, EMMC_SD_RESP_R2); - } - if (status == 0) { - /* Set relative address */ - status = mmc_send_cmd(MMC_CMD3_SET_REL_ADDR, 0, EMMC_SD_RESP_R6); - } - if (status == 0) { - g_rca = ((EMMC_SD_SRS04 >> SD_RCA_SHIFT) & 0xFFFF); - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: rca: %d\n", g_rca); - #endif - } - if (status == 0) { - /* read CSD register from device */ - status = mmc_send_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R2); - } - if (status == 0) { - /* Get sector size and count */ - uint32_t csd_struct; - uint32_t bl_len, c_size, c_size_mult; - bl_len = get_srs_bits(22, 4); - g_sector_size = (1U << bl_len); - - csd_struct = get_srs_bits(126, 2); - switch (csd_struct) { - case 0: - c_size = get_srs_bits(62, 12); - c_size_mult = get_srs_bits(47, 3); - g_sector_count = (c_size + 1) << (c_size_mult + 2); - break; - case 1: - c_size = get_srs_bits(48, 22); - g_sector_count = (c_size + 1) << 10; - break; - default: - /* invalid CSD structure */ - status = -1; - break; - } - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: csd_version: %d, sector: size %d count %d\n", - csd_struct, g_sector_size, g_sector_count); - #endif - } - if (status == 0) { - /* select card */ - status = mmc_send_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R1B); - if (status == DEVICE_BUSY) { - status = mmc_wait_busy(1); - } + /* Set power to 3.3v */ + status = mmc_set_power(EMMC_SD_SRS10_BVS_3_3V); + if (status != 0) { + wolfBoot_printf("eMMC: Failed to set power\n"); + return status; } - irq_restore = EMMC_SD_SRS13; - if (status == 0) { - /* disable card insert interrupt while changing bus width to avoid false triggers */ - EMMC_SD_SRS13 = (irq_restore & ~EMMC_SD_SRS13_CINT_SE); - status = mmc_set_bus_width(4); - } - if (status == 0) { - /* Get SCR registers - 8 bytes */ - uint32_t scr_reg[SCR_REG_DATA_SIZE/sizeof(uint32_t)]; - status = mmc_read(SD_ACMD51_SEND_SCR, 0, scr_reg, - sizeof(scr_reg)); + /* Run full eMMC card initialization */ + status = emmc_card_full_init(); + if (status != 0) { + wolfBoot_printf("eMMC: Card initialization failed\n"); + return status; } - if (status == 0) { - /* set UHS mode to SDR25 and driver strength to Type B */ - uint32_t card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR25; - status = mmc_set_function(card_access_mode, 1); - if (status == 0) { - /* set driver strength */ - reg = EMMC_SD_SRS15; - reg &= ~EMMC_SD_SRS15_DSS_MASK; - reg |= EMMC_SD_SRS15_DSS_TYPE_B; /* default */ - EMMC_SD_SRS15 = reg; - /* enable high speed */ - EMMC_SD_SRS10 |= EMMC_SD_SRS10_HSE; +#else /* USE_SDCARD */ + /* ========================================================================= + * SD Card Initialization Path + * ========================================================================= */ - /* set UHS mode */ - reg = EMMC_SD_SRS15; - reg &= ~EMMC_SD_SRS15_UMS_MASK; - reg |= EMMC_SD_SRS15_UMS_SDR25; - EMMC_SD_SRS15 = reg; - } + /* Run full SD card initialization */ + status = sdcard_card_full_init(); + if (status != 0) { + wolfBoot_printf("SD Card: Card initialization failed\n"); + return status; } - if (status == 0) { - mmc_set_clock(EMMC_SD_CLK_50MHZ); -#ifdef ENABLE_MMC_SD_TUNING - /* PHY training for SDR25 at 50MHz */ - status = mmc_tune(EMMC_SD_PHY_ADDR_UHSI_SDR25, EMMC_SD_CLK_50MHZ); - if (status != 0) { - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_init: tuning failed, continuing\n"); - #endif - status = 0; /* Don't fail init on tuning failure */ - } -#endif - } - EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ +#endif /* USE_EMMC */ + + /* Common finalization for both eMMC and SD */ if (status == 0) { /* Set data timeout to 3000ms */ status = mmc_set_timeout(EMMC_SD_DATA_TIMEOUT_US); diff --git a/hal/mpfs250.h b/hal/mpfs250.h index 6bf9ec9eef..4a0ccba848 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -820,13 +820,53 @@ #define EMMC_SD_INIT_TIMEOUT_US (500U * 1000U) /* 500ms init timeout */ #define EMMC_SD_DATA_TIMEOUT_US (3000U * 1000U) /* 3000ms data timeout */ +/* Card type definitions */ #define WOLFBOOT_CARDTYPE_SD 1 #define WOLFBOOT_CARDTYPE_EMMC 2 +/* Build-time card type selection + * Define USE_EMMC in your config to use eMMC instead of SD card (default) + * Example: CFLAGS += -DUSE_EMMC + */ +#ifdef USE_EMMC +#define WOLFBOOT_CARDTYPE WOLFBOOT_CARDTYPE_EMMC +#else #define WOLFBOOT_CARDTYPE WOLFBOOT_CARDTYPE_SD +#endif #define MAX_CURRENT_MA 150 /* mA */ +/* ---------------------------------------------------------------------------- + * eMMC-specific Constants (for CMD1 and CMD6 SWITCH) + * ---------------------------------------------------------------------------- */ + +/* CMD1 SEND_OP_COND argument values */ +#define MMC_DEVICE_3_3V_VOLT_SET 0x40300000U /* 3.3V, sector addressing mode */ +#define MMC_DEVICE_1_8V_VOLT_SET 0x40000080U /* 1.8V, sector addressing mode */ +#define MMC_OCR_BUSY_BIT 0x80000000U /* Device ready/busy bit */ +#define MMC_OCR_SECTOR_MODE 0x40000000U /* Sector addressing mode bit */ + +/* CMD6 SWITCH command - EXT_CSD access for bus width */ +#define MMC_CMD6_SWITCH 6 +#define MMC_DW_CSD 0x03B70000U /* Access byte 183 (BUS_WIDTH) in EXT_CSD */ +#define MMC_HS_TIMING 0x03B90000U /* Access byte 185 (HS_TIMING) in EXT_CSD */ + +/* eMMC data bus width values for CMD6 SWITCH (byte value << 8) */ +#define MMC_EXT_CSD_WIDTH_1BIT 0x00U +#define MMC_EXT_CSD_WIDTH_4BIT 0x01U +#define MMC_EXT_CSD_WIDTH_8BIT 0x02U +#define MMC_EXT_CSD_WIDTH_4BIT_DDR 0x05U +#define MMC_EXT_CSD_WIDTH_8BIT_DDR 0x06U + +/* eMMC HS_TIMING values */ +#define MMC_HS_TIMING_LEGACY 0x00U +#define MMC_HS_TIMING_HS 0x01U +#define MMC_HS_TIMING_HS200 0x02U +#define MMC_HS_TIMING_HS400 0x03U + +/* eMMC default RCA (host-assigned, typically 1) */ +#define MMC_EMMC_RCA_DEFAULT 0x0001U + #define SD_RCA_SHIFT 16 /* relative card address */ #define SD_RCA_MASK (0xFFFFU << SD_RCA_SHIFT) /* relative card address mask */ From 879e7ed1e561dce2e9293d59a613fa8482b2a64b Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 31 Dec 2025 10:53:37 -0800 Subject: [PATCH 4/6] Add support for eMMC (tested) --- .gitignore | 3 +++ hal/mpfs250.c | 44 ++++++++++++++++++++++++++++++++++++++------ hal/mpfs250.h | 2 +- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 6e4b4dc3b3..61451464e0 100644 --- a/.gitignore +++ b/.gitignore @@ -297,3 +297,6 @@ language.settings.xml .cproject .project .settings/ + +# PolarFire SoC Device Tree Binary +hal/mpfs.dtb diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 30e8cc505f..b93b99ad42 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -1273,9 +1273,24 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, if ((reg & EMMC_SD_SRS12_ERR_STAT) == 0) { /* no errors */ /* if multi-block read, send CMD12 to stop transfer */ if (cmd_index == MMC_CMD18_READ_MULTIPLE) { - (void)mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, - MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1); + /* Clear transfer complete before CMD12 */ + EMMC_SD_SRS12 = EMMC_SD_SRS12_TC; + + /* CMD12 argument: SD uses RCA, eMMC uses stuff bits */ +#ifdef USE_EMMC + status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, + MMC_CMD12_STOP_TRANS, 0, EMMC_SD_RESP_R1B); +#else + status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, + MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), EMMC_SD_RESP_R1B); +#endif + if (status != 0) { + wolfBoot_printf("mmc_read: CMD12 stop transfer error\n"); + /* Reset data/cmd lines to recover from error */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); + return -1; + } } /* wait for idle */ @@ -1283,6 +1298,9 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, } else { wolfBoot_printf("mmc_read: error SRS12: 0x%08X\n", reg); + /* Reset data/cmd lines to recover from error */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); status = -1; /* error */ } @@ -1425,12 +1443,23 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, if ((reg & EMMC_SD_SRS12_ERR_STAT) == 0) { /* no errors */ /* if multi-block write, send CMD12 to stop transfer */ if (cmd_index == MMC_CMD25_WRITE_MULTIPLE) { - /* CMD12 requires CMD_ABORT type per SD spec */ + /* Clear transfer complete before CMD12 */ + EMMC_SD_SRS12 = EMMC_SD_SRS12_TC; + + /* CMD12 argument: SD uses RCA, eMMC uses stuff bits */ +#ifdef USE_EMMC status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, - MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1B); + MMC_CMD12_STOP_TRANS, 0, EMMC_SD_RESP_R1B); +#else + status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_ABORT, + MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), EMMC_SD_RESP_R1B); +#endif if (status != 0) { wolfBoot_printf("mmc_write: CMD12 stop transfer error\n"); + /* Reset data/cmd lines to recover from error */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); + return -1; } } @@ -1439,6 +1468,9 @@ int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, } else { wolfBoot_printf("mmc_write: error SRS12: 0x%08X\n", reg); + /* Reset data/cmd lines to recover from error */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); status = -1; /* error */ } diff --git a/hal/mpfs250.h b/hal/mpfs250.h index 4a0ccba848..fb93f5c678 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -826,7 +826,7 @@ /* Build-time card type selection * Define USE_EMMC in your config to use eMMC instead of SD card (default) - * Example: CFLAGS += -DUSE_EMMC + * Example: CFLAGS_EXTRA += -DUSE_EMMC */ #ifdef USE_EMMC #define WOLFBOOT_CARDTYPE WOLFBOOT_CARDTYPE_EMMC From ca0528488acbdb15bc802f8bd5613010bbfad944 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 31 Dec 2025 13:23:13 -0800 Subject: [PATCH 5/6] Refactor eMMC/SD code to reduce duplicate code. Moved SDHCI driver into generic module that can be used by other platforms. --- config/examples/polarfire_mpfs250.config | 6 +- docs/Targets.md | 2 - hal/mpfs250.c | 1982 +--------------------- hal/mpfs250.h | 824 +-------- hal/riscv.h | 109 ++ include/sdhci.h | 462 +++++ options.mk | 15 + src/boot_riscv.c | 98 +- src/sdhci.c | 1667 ++++++++++++++++++ 9 files changed, 2398 insertions(+), 2767 deletions(-) create mode 100644 include/sdhci.h create mode 100644 src/sdhci.c diff --git a/config/examples/polarfire_mpfs250.config b/config/examples/polarfire_mpfs250.config index bc86fe7875..448191d789 100644 --- a/config/examples/polarfire_mpfs250.config +++ b/config/examples/polarfire_mpfs250.config @@ -31,9 +31,9 @@ NO_ARM_ASM?=0 # Optional: Use smaller SHA512 #CFLAGS_EXTRA+=-DUSE_SLOW_SHA512 -# SDCard (default) -# Optionally use eMMC -#CFLAGS+=-DUSE_EMMC +# SDCard or eMMC support via SDHCI driver +DISK_SDCARD?=1 +DISK_EMMC?=0 # DDR Address for wolfBoot to start from WOLFBOOT_ORIGIN?=0x80000000 diff --git a/docs/Targets.md b/docs/Targets.md index 0149a14b0a..32f1ee846f 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1193,8 +1193,6 @@ Benchmark complete ### PolarFire TODO -* Add eMMC/SD features: - - eMMC support (not just SD) * 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 diff --git a/hal/mpfs250.c b/hal/mpfs250.c index b93b99ad42..4d24f630eb 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -34,6 +34,7 @@ #include "target.h" #include "mpfs250.h" +#include "riscv.h" #include "image.h" #ifndef ARCH_RISCV64 # error "wolfBoot mpfs250 HAL: wrong architecture selected. Please compile with ARCH=RISCV64." @@ -42,12 +43,11 @@ #include "printf.h" #include "loader.h" #include "hal.h" -#include "disk.h" #include "gpt.h" #include "fdt.h" -#ifdef DISK_TEST -static int disk_test(int drv); +#if defined(DISK_SDCARD) || defined(DISK_EMMC) +#include "sdhci.h" #endif void hal_init(void) @@ -179,1966 +179,102 @@ void* hal_get_dts_address(void) } #endif -static uint32_t g_sector_count; -static uint32_t g_sector_size; -static uint32_t g_bus_width = 1; -static uint32_t g_rca = 0; /* SD Card Relative Address */ - -/* MMC Interrupt state - volatile for interrupt handler access */ -static volatile uint32_t g_mmc_irq_status = 0; -static volatile int g_mmc_irq_pending = 0; - -/* ========================================================================== - * PHY Register Access Functions - * ========================================================================== */ - -/* Write to SD/eMMC PHY register via HRS04 */ -static void mmc_phy_write(uint8_t phy_addr, uint8_t delay_val) -{ - uint32_t phycfg; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_phy_write: phyaddr: 0x%08x, delay_value: %d\n", - phy_addr, delay_val); -#endif - - /* Wait for ACK to clear */ - while ((EMMC_SD_HRS04 & EMMC_SD_HRS04_UIS_ACK) == 0); - - /* Set address and delay value */ - phycfg = ((uint32_t)phy_addr & EMMC_SD_HRS04_UIS_ADDR_MASK) | - ((uint32_t)delay_val << EMMC_SD_HRS04_UIS_WDATA_SHIFT); - EMMC_SD_HRS04 = phycfg; - - /* Send write request */ - EMMC_SD_HRS04 = phycfg | EMMC_SD_HRS04_UIS_WR; - /* Wait for ACK */ - while ((EMMC_SD_HRS04 & EMMC_SD_HRS04_UIS_ACK) == 0); - - /* Clear write request */ - EMMC_SD_HRS04 = phycfg; - EMMC_SD_HRS04 = 0; -} - +#if defined(DISK_SDCARD) || defined(DISK_EMMC) /* ============================================================================ - * PLIC - Platform-Level Interrupt Controller Functions + * SDHCI Platform HAL Implementation * ============================================================================ */ -/* Get the PLIC context for the current hart in S-mode */ -extern unsigned long get_boot_hartid(void); -static inline uint32_t plic_get_context(void) -{ - uint32_t hart_id = get_boot_hartid(); - return PLIC_HART_TO_SMODE_CTX(hart_id); -} - -/* Set priority for an interrupt source */ -void plic_set_priority(uint32_t irq, uint32_t priority) -{ - if (irq > 0 && irq < PLIC_NUM_SOURCES && priority <= PLIC_PRIORITY_MAX) { - PLIC_PRIORITY(irq) = priority; - } -} - -/* Enable an interrupt for the current hart's context */ -void plic_enable_interrupt(uint32_t irq) -{ - uint32_t ctx = plic_get_context(); - if (irq > 0 && irq < PLIC_NUM_SOURCES) { - PLIC_ENABLE(ctx, irq) |= PLIC_ENABLE_BIT(irq); - } -} - -/* Disable an interrupt for the current hart's context */ -void plic_disable_interrupt(uint32_t irq) -{ - uint32_t ctx = plic_get_context(); - if (irq > 0 && irq < PLIC_NUM_SOURCES) { - PLIC_ENABLE(ctx, irq) &= ~PLIC_ENABLE_BIT(irq); - } -} - -/* Set the priority threshold for the current hart's context */ -void plic_set_threshold(uint32_t threshold) +/* Register access functions for generic SDHCI driver */ +uint32_t sdhci_reg_read(uint32_t offset) { - uint32_t ctx = plic_get_context(); - if (threshold <= PLIC_PRIORITY_MAX) { - PLIC_THRESHOLD(ctx) = threshold; - } -} - -/* Claim the highest priority pending interrupt (returns IRQ number, 0 if none) */ -uint32_t plic_claim(void) -{ - uint32_t ctx = plic_get_context(); - return PLIC_CLAIM(ctx); + return *((volatile uint32_t*)(EMMC_SD_BASE + offset)); } -/* Signal completion of interrupt handling */ -void plic_complete(uint32_t irq) +void sdhci_reg_write(uint32_t offset, uint32_t val) { - uint32_t ctx = plic_get_context(); - PLIC_COMPLETE(ctx) = irq; -} - -/* Initialize PLIC for MMC interrupt handling */ -void plic_init_mmc(void) -{ - /* Set priority for MMC main interrupt */ - plic_set_priority(PLIC_INT_MMC_MAIN, PLIC_PRIORITY_DEFAULT); - - /* Set threshold to 0 (allow all priorities > 0) */ - plic_set_threshold(0); - - /* Enable MMC interrupt for this hart */ - plic_enable_interrupt(PLIC_INT_MMC_MAIN); - -#ifdef DEBUG_MMC - wolfBoot_printf("plic_init_mmc: hart %d, context %d, irq %d enabled\n", - get_boot_hartid(), plic_get_context(), PLIC_INT_MMC_MAIN); -#endif + *((volatile uint32_t*)(EMMC_SD_BASE + offset)) = val; } +#endif /* DISK_SDCARD || DISK_EMMC */ /* ============================================================================ - * MMC Interrupt Handler + * PLIC - Platform-Level Interrupt Controller (MPFS250-specific) + * + * Generic PLIC functions are in src/boot_riscv.c + * Platform must provide: + * - plic_get_context(): Map current hart to PLIC context + * - plic_dispatch_irq(): Dispatch IRQ to appropriate handler * ============================================================================ */ -/* MMC interrupt handler - called from PLIC dispatch */ -void mmc_irq_handler(void) -{ - uint32_t status = EMMC_SD_SRS12; - - /* Check for DMA interrupt */ - if (status & EMMC_SD_SRS12_DMAINT) { - /* Read updated DMA address - engine will increment block */ - uint32_t* addr = (uint32_t*)(uintptr_t)((((uint64_t)EMMC_SD_SRS23) << 32) | - EMMC_SD_SRS22); - /* Set new DMA address for next boundary */ - EMMC_SD_SRS22 = (uint32_t)(uintptr_t)addr; - EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)addr) >> 32); - /* triggers next DMA block on write of top bit */ - - g_mmc_irq_status |= MMC_IRQ_FLAG_DMAINT; - EMMC_SD_SRS12 = EMMC_SD_SRS12_DMAINT; /* Clear interrupt */ - } - - /* Check for transfer complete */ - if (status & EMMC_SD_SRS12_TC) { - g_mmc_irq_status |= MMC_IRQ_FLAG_TC; - EMMC_SD_SRS12 = EMMC_SD_SRS12_TC; /* Clear interrupt */ - } - - /* Check for command complete */ - if (status & EMMC_SD_SRS12_CC) { - g_mmc_irq_status |= MMC_IRQ_FLAG_CC; - EMMC_SD_SRS12 = EMMC_SD_SRS12_CC; /* Clear interrupt */ - } - - /* Check for data timeout error */ - if (status & EMMC_SD_SRS12_EDT) { - g_mmc_irq_status |= MMC_IRQ_FLAG_ERROR; - EMMC_SD_SRS12 = EMMC_SD_SRS12_EDT; /* Clear interrupt */ - } - - /* Check for any other errors */ - if (status & EMMC_SD_SRS12_EINT) { - g_mmc_irq_status |= MMC_IRQ_FLAG_ERROR; - /* Clear all error status bits */ - EMMC_SD_SRS12 = (status & EMMC_SD_SRS12_ERR_STAT); - } - - /* Signal that interrupt was handled */ - g_mmc_irq_pending = 1; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_irq_handler: status=0x%08X, flags=0x%02X\n", - status, g_mmc_irq_status); -#endif -} - -/* Enable MMC interrupts for SDMA transfer */ -static void mmc_enable_sdma_interrupts(void) -{ - /* Enable signal interrupts for: DMA, Transfer Complete, Command Complete, - * Data Timeout Error */ - uint32_t sig_enable = EMMC_SD_SRS14_DMAINT_IE | - EMMC_SD_SRS14_TC_IE | - EMMC_SD_SRS14_CC_IE | - EMMC_SD_SRS14_EDT_IE; - EMMC_SD_SRS14 |= sig_enable; - - /* Clear any pending interrupt state */ - g_mmc_irq_status = 0; - g_mmc_irq_pending = 0; -} - -/* Disable MMC signal interrupts (status enables remain for polling) */ -static void mmc_disable_sdma_interrupts(void) -{ - EMMC_SD_SRS14 &= ~(EMMC_SD_SRS14_DMAINT_IE | - EMMC_SD_SRS14_TC_IE | - EMMC_SD_SRS14_CC_IE | - EMMC_SD_SRS14_EDT_IE); -} - -/* Wait for MMC interrupt with timeout */ -static int mmc_wait_irq(uint32_t expected_flags, uint32_t timeout) +/* Get the PLIC context for the current hart in S-mode */ +extern unsigned long get_boot_hartid(void); +uint32_t plic_get_context(void) { - while (timeout-- > 0) { - if (g_mmc_irq_pending) { - g_mmc_irq_pending = 0; - - /* Check for error */ - if (g_mmc_irq_status & MMC_IRQ_FLAG_ERROR) { - return -1; - } - - /* Check for expected flags */ - if (g_mmc_irq_status & expected_flags) { - return 0; - } - } - asm volatile("nop"); - } - return -1; /* Timeout */ + uint32_t hart_id = get_boot_hartid(); + /* Get S-mode context for a given hart (1-4 for U54 cores) */ + return hart_id * 2; } -static int mmc_set_timeout(uint32_t timeout_us) -{ - uint32_t reg, i, tcfclk, tcfclk_mhz, tcfclk_khz, timeout_val, dtcv; - - /* read capabilities to determine timeout clock frequency and unit (MHz or kHz) */ - reg = EMMC_SD_SRS16; - tcfclk_khz = (reg & EMMC_SD_SRS16_TCF_MASK) >> EMMC_SD_SRS16_TCF_SHIFT; - /* Default timeout clock frequency should be 50MHz */ - - if (((reg & EMMC_SD_SRS16_TCU) == 0) && (timeout_us < 1000)) { - /* invalid timeout_us value */ - return -1; - } - if (tcfclk_khz == 0) { - /* reported timeout clock frequency is 0 */ - return -1; - } - - if ((reg & EMMC_SD_SRS16_TCU) != 0) { - tcfclk_khz *= 1000; /* MHz to kHz */ - } - tcfclk_mhz = tcfclk_khz / 1000; - if (tcfclk_mhz == 0) { - tcfclk = tcfclk_khz; - timeout_val = timeout_us / 1000; - } - else { - tcfclk = tcfclk_mhz; - timeout_val = timeout_us; - } - - /* calculate the data timeout counter value */ - dtcv = 8192; /* 2*13 */ - for (i=0; i<15; i++) { - if (timeout_val < (dtcv / tcfclk)) { - break; - } - dtcv *= 2; - } - dtcv = i; - - /* set the data timeout counter value */ - reg = EMMC_SD_SRS11; - reg &= ~EMMC_SD_SRS11_DTCV_MASK; - reg |= (dtcv << EMMC_SD_SRS11_DTCV_SHIFT) & EMMC_SD_SRS11_DTCV_MASK; - EMMC_SD_SRS11 = reg; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_set_timeout: timeout_val %d (%d)\n", timeout_val, dtcv); +/* Forward declaration of SDHCI IRQ handler */ +#if defined(DISK_SDCARD) || defined(DISK_EMMC) +extern void sdhci_irq_handler(void); #endif - return 0; -} - -/* voltage values: - * 0 = off - * EMMC_SD_SRS10_BVS_1_8V - * EMMC_SD_SRS10_BVS_3_0V - * EMMC_SD_SRS10_BVS_3_3V - */ -static int mmc_set_power(uint32_t voltage) -{ - uint32_t reg; - - /* disable bus power */ - reg = EMMC_SD_SRS10; - reg &= ~EMMC_SD_SRS10_BP; - EMMC_SD_SRS10 = reg; - - if (voltage != 0) { - /* read voltage capabilities */ - uint32_t cap2 = EMMC_SD_SRS16; - - /* select voltage (if capable) */ - reg &= ~EMMC_SD_SRS10_BVS_MASK; - if (voltage == EMMC_SD_SRS10_BVS_1_8V && (cap2 & EMMC_SD_SRS16_VS18)) { - reg |= EMMC_SD_SRS10_BP | EMMC_SD_SRS10_BVS_1_8V; - } - else if (voltage == EMMC_SD_SRS10_BVS_3_0V && (cap2 & EMMC_SD_SRS16_VS30)) { - reg |= EMMC_SD_SRS10_BP | EMMC_SD_SRS10_BVS_3_0V; - } - else if (voltage == EMMC_SD_SRS10_BVS_3_3V && (cap2 & EMMC_SD_SRS16_VS33)) { - reg |= EMMC_SD_SRS10_BP | EMMC_SD_SRS10_BVS_3_3V; - } - else { - /* voltage not supported */ - return -1; - } - /* should be - 0xf06 */ - EMMC_SD_SRS10 = reg; - } - return 0; -} - -/* returns actual frequency in kHz */ -static uint32_t mmc_set_clock(uint32_t clock_khz) +/* Dispatch IRQ to appropriate platform handler */ +void plic_dispatch_irq(uint32_t irq) { - static uint32_t last_clock_khz = 0; - uint32_t reg, base_clk_khz, i, mclk, freq_khz; - - if (last_clock_khz != 0 && last_clock_khz == clock_khz) { - /* clock already set */ - return 0; - } - - /* disable clock */ - EMMC_SD_SRS11 &= ~EMMC_SD_SRS11_SDCE; - - /* get base clock */ - reg = EMMC_SD_SRS16; - base_clk_khz = (reg & EMMC_SD_SRS16_BCSDCLK_MASK) >> EMMC_SD_SRS16_BCSDCLK_SHIFT; - if (base_clk_khz == 0) { - /* error getting base clock */ - return -1; - } - base_clk_khz *= 1000; /* convert MHz to kHz */ - - /* calculate divider */ - for (i=1; i<2046; i++) { - if (((base_clk_khz / i) < clock_khz) || - (((base_clk_khz / i) == clock_khz) && (base_clk_khz % i) == 0)) { + switch (irq) { +#if defined(DISK_SDCARD) || defined(DISK_EMMC) + case PLIC_INT_MMC_MAIN: + sdhci_irq_handler(); break; - } - } - mclk = (i / 2); - - /* select clock frequency */ - reg = EMMC_SD_SRS11; - reg &= ~(EMMC_SD_SRS11_SDCFSL_MASK | EMMC_SD_SRS11_SDCFSH_MASK); - reg |= (((mclk & 0x0FF) << EMMC_SD_SRS11_SDCFSL_SHIFT) & EMMC_SD_SRS11_SDCFSL_MASK); /* lower 8 bits */ - reg |= (((mclk & 0x300) << EMMC_SD_SRS11_SDCFSH_SHIFT) & EMMC_SD_SRS11_SDCFSH_SHIFT); /* upper 2 bits */ - reg |= EMMC_SD_SRS11_ICE; /* clock enable */ - reg &= ~EMMC_SD_SRS11_CGS; /* select clock */ - EMMC_SD_SRS11 = reg; - freq_khz = base_clk_khz / i; - - /* wait for clock to stabilize */ - while ((EMMC_SD_SRS11 & EMMC_SD_SRS11_ICS) == 0); - - /* enable clock */ - EMMC_SD_SRS11 |= EMMC_SD_SRS11_SDCE; - last_clock_khz = clock_khz; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_set_clock: requested khz: %d, actual khz: %d\n", - clock_khz, freq_khz); #endif - - return freq_khz; -} - -/* eMMC/SD Response Type */ -typedef enum { - EMMC_SD_RESP_NONE, - EMMC_SD_RESP_R1, - EMMC_SD_RESP_R1B, - EMMC_SD_RESP_R2, - EMMC_SD_RESP_R3, - EMMC_SD_RESP_R4, - EMMC_SD_RESP_R5, - EMMC_SD_RESP_R5B, - EMMC_SD_RESP_R6, - EMMC_SD_RESP_R7, - EMMC_SD_RESP_R1A -} EMMC_SD_Resp_t; - -static uint32_t mmc_get_response_type(uint8_t resp_type) -{ - uint32_t cmd_reg; - switch (resp_type) { - case EMMC_SD_RESP_R2: - cmd_reg = (EMMC_SD_SRS03_RESP_136 | EMMC_SD_SRS03_CRCCE); - break; - case EMMC_SD_RESP_R3: - case EMMC_SD_RESP_R4: - cmd_reg = EMMC_SD_SRS03_RESP_48; - break; - case EMMC_SD_RESP_R1: - case EMMC_SD_RESP_R5: - case EMMC_SD_RESP_R6: - case EMMC_SD_RESP_R7: - cmd_reg = (EMMC_SD_SRS03_RESP_48 | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE); - break; - case EMMC_SD_RESP_R1B: - case EMMC_SD_RESP_R5B: - cmd_reg = (EMMC_SD_SRS03_RESP_48B | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE); - break; - case EMMC_SD_RESP_NONE: default: - cmd_reg = EMMC_SD_SRS03_RESP_NONE; + /* Unknown interrupt - ignore */ break; } - return cmd_reg; -} - -#define DEVICE_BUSY 1 -static int mmc_send_cmd_internal(uint32_t cmd_type, - uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) -{ - int status = 0; - uint32_t cmd_reg; - uint32_t timeout = 0x000FFFFF; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_send_cmd: cmd_index: %d, cmd_arg: %08X, resp_type: %d\n", - cmd_index, cmd_arg, resp_type); -#endif - - /* wait for command line to be idle */ - while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_CICMD) != 0); - - /* set command argument and command transfer registers */ - EMMC_SD_SRS02 = cmd_arg; - cmd_reg = - ((cmd_index << EMMC_SD_SRS03_CIDX_SHIFT) & EMMC_SD_SRS03_CIDX_MASK) | - ((cmd_type << EMMC_SD_SRS03_CT_SHIFT) & EMMC_SD_SRS03_CT_MASK) | - mmc_get_response_type(resp_type); - - EMMC_SD_SRS03 = cmd_reg; - - /* wait for command complete or error */ - while ((EMMC_SD_SRS12 & (EMMC_SD_SRS12_CC | EMMC_SD_SRS12_TC | - EMMC_SD_SRS12_EINT)) == 0 && --timeout > 0); - - if (timeout == 0) { - wolfBoot_printf("mmc_send_cmd: timeout waiting for command complete\n"); - status = -1; /* error */ - } - else if (EMMC_SD_SRS12 & EMMC_SD_SRS12_EINT) { - wolfBoot_printf("mmc_send_cmd: error SRS12: 0x%08X\n", EMMC_SD_SRS12); - status = -1; /* error */ - } - - EMMC_SD_SRS12 = EMMC_SD_SRS12_CC; /* clear command complete */ - while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_CICMD) != 0); - - if (status == 0) { - /* check for device busy */ - if (resp_type == EMMC_SD_RESP_R1 || resp_type == EMMC_SD_RESP_R1B) { - uint32_t resp = EMMC_SD_SRS04; - #define CARD_STATUS_READY_FOR_DATA (1U << 8) - if ((resp & CARD_STATUS_READY_FOR_DATA) == 0) { - status = DEVICE_BUSY; /* card is busy */ - } - } - } - - return status; -} - -int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) -{ - /* send command */ - int status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_NORMAL, cmd_index, - cmd_arg, resp_type); - - /* clear all status interrupts - * (except current limit, card interrupt/removal/insert) */ - EMMC_SD_SRS12 = ~(EMMC_SD_SRS12_ECL | - EMMC_SD_SRS12_CINT | - EMMC_SD_SRS12_CR | - EMMC_SD_SRS12_CIN); - - return status; -} - -/* TODO: Add timeout */ -static int mmc_wait_busy(int check_dat0) -{ - uint32_t status; - if (check_dat0) { - /* wait for DATA0 not busy */ - while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_DAT0_LVL) == 0); - } - /* wait for CMD13 */ - while ((status = mmc_send_cmd(MMC_CMD13_SEND_STATUS, - (g_rca << SD_RCA_SHIFT), EMMC_SD_RESP_R1)) == DEVICE_BUSY); - return status; -} - -/* Set power and send initialization commands */ -/* voltage: 0=off or EMMC_SD_SRS10_BVS_[X_X]V */ -int mmc_power_init_seq(uint32_t voltage) -{ - /* Set power to specified voltage */ - int status = mmc_set_power(voltage); - if (status == 0) { - /* send CMD0 (go idle) to reset card */ - status = mmc_send_cmd(MMC_CMD0_GO_IDLE, 0, EMMC_SD_RESP_NONE); - } - if (status == 0) { - /* send the operating conditions command */ - status = mmc_send_cmd(SD_CMD8_SEND_IF_COND, IF_COND_27V_33V, - EMMC_SD_RESP_R7); - } - return status; -} - -int mmc_card_init(uint32_t acmd41_arg, uint32_t *ocr_reg) -{ - int status = mmc_send_cmd(SD_CMD55_APP_CMD, 0, EMMC_SD_RESP_R1); - if (status == 0) { - status = mmc_send_cmd(SD_ACMD41_SEND_OP_COND, acmd41_arg, - EMMC_SD_RESP_R3); - if (status == 0) { - *ocr_reg = EMMC_SD_SRS04; - #ifdef DEBUG_MMC - wolfBoot_printf("ocr_reg: 0x%08X\n", *ocr_reg); - #endif - } - } - return status; -} - -#ifndef USE_EMMC -/* ========================================================================== - * SD Card-specific Initialization Functions - * ========================================================================== */ - -/* Forward declarations - defined later in the file */ -static uint32_t get_srs_bits(int from, int count); -int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t sz); -int mmc_set_bus_width(uint32_t bus_width); -int mmc_set_function(uint32_t function_number, uint32_t group_number); -#ifdef ENABLE_MMC_SD_TUNING -static int mmc_tune(uint8_t phy_addr, uint32_t clk_khz); -#endif - -/* Full SD card initialization sequence - * Returns 0 on success */ -static int sdcard_card_full_init(void) -{ - int status = 0; - uint32_t reg; - uint32_t ctrl_volts, card_volts; - uint32_t irq_restore; - int xpc, si8r; - - /* Set power to 3.3v and send init commands */ - ctrl_volts = EMMC_SD_SRS10_BVS_3_3V; /* default to 3.3v */ - status = mmc_power_init_seq(ctrl_volts); - if (status == 0) { - uint32_t max_ma_3_3v, max_ma_1_8v; - /* determine host controller capabilities */ - reg = EMMC_SD_SRS18; - max_ma_3_3v = ((reg & EMMC_SD_SRS18_MC33_MASK) >> EMMC_SD_SRS18_MC33_SHIFT) * 4; - max_ma_1_8v = ((reg & EMMC_SD_SRS18_MC18_MASK) >> EMMC_SD_SRS18_MC18_SHIFT) * 4; - /* does controller support eXtended Power Control (XPC)? */ - xpc = (max_ma_1_8v >= 150) && (max_ma_3_3v >= 150) ? 1 : 0; - /* does controller support UHS-I (Ultra High Speed Interface) v1.8 signaling? */ - si8r = ((EMMC_SD_SRS16 & EMMC_SD_SRS16_VS18) && /* 1.8v supported */ - (EMMC_SD_SRS17 & (EMMC_SD_SRS17_DDR50 | /* DDR50, SDR104 or SDR50 supported */ - EMMC_SD_SRS17_SDR104 | - EMMC_SD_SRS17_SDR50))) ? 1 : 0; - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: xpc:%d, si8r:%d, max_ma (3.3v:%d 1.8v:%d)\n", - xpc, si8r, max_ma_3_3v, max_ma_1_8v); - #endif - } - - if (status == 0) { - reg = 0; - /* get operating conditions */ - status = mmc_card_init(0, ®); - if (status == 0) { - /* pick host and card operating voltages */ - if (reg & SDCARD_REG_OCR_3_3_3_4) { /* 3.3v - 3.4v */ - card_volts = SDCARD_REG_OCR_3_3_3_4; - } - else if (reg & SDCARD_REG_OCR_3_2_3_3) { /* 3.2v - 3.3v */ - card_volts = SDCARD_REG_OCR_3_2_3_3; - } - else if (reg & SDCARD_REG_OCR_3_1_3_2) { /* 3.1v - 3.2v */ - card_volts = SDCARD_REG_OCR_3_1_3_2; - } - else if (reg & SDCARD_REG_OCR_3_0_3_1) { /* 3.0v - 3.1v */ - card_volts = SDCARD_REG_OCR_3_0_3_1; - ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; - } - else if (reg & SDCARD_REG_OCR_2_9_3_0) { /* 2.9v - 3.0v */ - card_volts = SDCARD_REG_OCR_2_9_3_0; - ctrl_volts = EMMC_SD_SRS10_BVS_3_0V; - } - else { /* default to v3.3 */ - card_volts = SDCARD_REG_OCR_3_3_3_4; - } - /* if needed change operating voltage and re-init */ - if (ctrl_volts != EMMC_SD_SRS10_BVS_3_3V) { - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: changing operating voltage to 3.0v\n"); - #endif - status = mmc_power_init_seq(ctrl_volts); - } - } - } - - if (status == 0) { - /* configure operating conditions */ - uint32_t cmd_arg = SDCARD_ACMD41_HCS; - cmd_arg |= card_volts; - if (si8r) { - cmd_arg |= SDCARD_REG_OCR_S18RA; - } - if (xpc) { - cmd_arg |= SDCARD_REG_OCR_XPC; - } - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: sending OCR arg: 0x%08X\n", cmd_arg); - #endif - - /* retry until OCR ready */ - do { - status = mmc_card_init(cmd_arg, ®); - } while (status == 0 && (reg & SDCARD_REG_OCR_READY) == 0); - } - - if (status == 0) { - /* Get card identification */ - status = mmc_send_cmd(MMC_CMD2_ALL_SEND_CID, 0, EMMC_SD_RESP_R2); - } - - if (status == 0) { - /* Set relative address - SD card assigns its own RCA */ - status = mmc_send_cmd(MMC_CMD3_SET_REL_ADDR, 0, EMMC_SD_RESP_R6); - } - - if (status == 0) { - g_rca = ((EMMC_SD_SRS04 >> SD_RCA_SHIFT) & 0xFFFF); - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: rca: %d\n", g_rca); - #endif - } - - if (status == 0) { - /* read CSD register from device */ - status = mmc_send_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R2); - } - - if (status == 0) { - /* Get sector size and count */ - uint32_t csd_struct; - uint32_t bl_len, c_size, c_size_mult; - bl_len = get_srs_bits(22, 4); - g_sector_size = (1U << bl_len); - - csd_struct = get_srs_bits(126, 2); - switch (csd_struct) { - case 0: - c_size = get_srs_bits(62, 12); - c_size_mult = get_srs_bits(47, 3); - g_sector_count = (c_size + 1) << (c_size_mult + 2); - break; - case 1: - c_size = get_srs_bits(48, 22); - g_sector_count = (c_size + 1) << 10; - break; - default: - /* invalid CSD structure */ - status = -1; - break; - } - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: csd_version: %d, sector: size %d count %d\n", - csd_struct, g_sector_size, g_sector_count); - #endif - } - - if (status == 0) { - /* select card */ - status = mmc_send_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R1B); - if (status == DEVICE_BUSY) { - status = mmc_wait_busy(1); - } - } - - irq_restore = EMMC_SD_SRS13; - if (status == 0) { - /* disable card insert interrupt while changing bus width to avoid false triggers */ - EMMC_SD_SRS13 = (irq_restore & ~EMMC_SD_SRS13_CINT_SE); - - status = mmc_set_bus_width(4); - } - - if (status == 0) { - /* Get SCR registers - 8 bytes */ - uint32_t scr_reg[SCR_REG_DATA_SIZE/sizeof(uint32_t)]; - status = mmc_read(SD_ACMD51_SEND_SCR, 0, scr_reg, - sizeof(scr_reg)); - } - - if (status == 0) { - /* set UHS mode to SDR25 and driver strength to Type B */ - uint32_t card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR25; - status = mmc_set_function(card_access_mode, 1); - if (status == 0) { - /* set driver strength */ - reg = EMMC_SD_SRS15; - reg &= ~EMMC_SD_SRS15_DSS_MASK; - reg |= EMMC_SD_SRS15_DSS_TYPE_B; /* default */ - EMMC_SD_SRS15 = reg; - - /* enable high speed */ - EMMC_SD_SRS10 |= EMMC_SD_SRS10_HSE; - - /* set UHS mode */ - reg = EMMC_SD_SRS15; - reg &= ~EMMC_SD_SRS15_UMS_MASK; - reg |= EMMC_SD_SRS15_UMS_SDR25; - EMMC_SD_SRS15 = reg; - } - } - - if (status == 0) { - mmc_set_clock(EMMC_SD_CLK_50MHZ); - -#ifdef ENABLE_MMC_SD_TUNING - /* PHY training for SDR25 at 50MHz */ - status = mmc_tune(EMMC_SD_PHY_ADDR_UHSI_SDR25, EMMC_SD_CLK_50MHZ); - if (status != 0) { - #ifdef DEBUG_MMC - wolfBoot_printf("sdcard_init: tuning failed, continuing\n"); - #endif - status = 0; /* Don't fail init on tuning failure */ - } -#endif - } - - EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ - - return status; -} -#endif /* !USE_EMMC */ - -#ifdef USE_EMMC -/* ========================================================================== - * eMMC-specific Initialization Functions - * ========================================================================== */ - -/* Forward declaration - defined later in the file */ -static uint32_t get_srs_bits(int from, int count); - -/* Send CMD1 (SEND_OP_COND) for eMMC and wait for device ready - * Returns 0 on success, negative on error */ -static int emmc_send_op_cond(uint32_t ocr_arg, uint32_t *ocr_reg) -{ - int status; - uint32_t timeout = 1000; /* retry count */ - uint32_t response; - - /* First CMD1 to query supported voltages */ - status = mmc_send_cmd(MMC_CMD1_SEND_OP_COND, 0, EMMC_SD_RESP_R3); - if (status != 0) { - wolfBoot_printf("eMMC: CMD1 query failed\n"); - return status; - } - - /* Get OCR from response */ - response = EMMC_SD_SRS04; -#ifdef DEBUG_MMC - wolfBoot_printf("eMMC: Initial OCR: 0x%08X\n", response); -#endif - - /* Loop sending CMD1 with operating conditions until device is ready */ - do { - status = mmc_send_cmd(MMC_CMD1_SEND_OP_COND, ocr_arg, EMMC_SD_RESP_R3); - if (status != 0) { - wolfBoot_printf("eMMC: CMD1 failed\n"); - return status; - } - - response = EMMC_SD_SRS04; - - /* Check if device is ready (busy bit cleared = ready) */ - if (response & MMC_OCR_BUSY_BIT) { - /* Device is ready */ - if (ocr_reg != NULL) { - *ocr_reg = response; - } -#ifdef DEBUG_MMC - wolfBoot_printf("eMMC: Device ready, OCR: 0x%08X\n", response); -#endif - return 0; - } - - /* Small delay between retries */ - for (volatile int i = 0; i < 1000; i++); - - } while (--timeout > 0); - - wolfBoot_printf("eMMC: Timeout waiting for device ready\n"); - return -1; -} - -/* Set eMMC bus width using CMD6 SWITCH command - * width: MMC_EXT_CSD_WIDTH_1BIT, MMC_EXT_CSD_WIDTH_4BIT, or MMC_EXT_CSD_WIDTH_8BIT - * Returns 0 on success */ -static int emmc_set_bus_width(uint32_t width) -{ - int status; - uint32_t cmd_arg; - - /* Build CMD6 argument: Access=Write Byte, Index=183 (BUS_WIDTH), Value=width */ - cmd_arg = MMC_DW_CSD | (width << 8); - -#ifdef DEBUG_MMC - wolfBoot_printf("eMMC: Setting bus width to %d (CMD6 arg: 0x%08X)\n", - (width == MMC_EXT_CSD_WIDTH_4BIT) ? 4 : - (width == MMC_EXT_CSD_WIDTH_8BIT) ? 8 : 1, cmd_arg); -#endif - - /* Send CMD6 SWITCH */ - status = mmc_send_cmd(MMC_CMD6_SWITCH, cmd_arg, EMMC_SD_RESP_R1B); - if (status == DEVICE_BUSY) { - status = mmc_wait_busy(1); - } - - if (status != 0) { - wolfBoot_printf("eMMC: Set bus width failed\n"); - return status; - } - - /* Update host controller bus width */ - if (width == MMC_EXT_CSD_WIDTH_4BIT || width == MMC_EXT_CSD_WIDTH_4BIT_DDR) { - EMMC_SD_SRS10 |= EMMC_SD_SRS10_DTW; - EMMC_SD_SRS10 &= ~EMMC_SD_SRS10_EDTW; - g_bus_width = 4; - } - else if (width == MMC_EXT_CSD_WIDTH_8BIT || width == MMC_EXT_CSD_WIDTH_8BIT_DDR) { - EMMC_SD_SRS10 |= EMMC_SD_SRS10_EDTW; - g_bus_width = 8; - } - else { - EMMC_SD_SRS10 &= ~(EMMC_SD_SRS10_DTW | EMMC_SD_SRS10_EDTW); - g_bus_width = 1; - } - - return 0; } -/* Full eMMC card initialization sequence - * Returns 0 on success */ -static int emmc_card_full_init(void) -{ - int status; - uint32_t ocr_reg; - - /* Send CMD0 (GO_IDLE) to reset eMMC */ - status = mmc_send_cmd(MMC_CMD0_GO_IDLE, 0, EMMC_SD_RESP_NONE); - if (status != 0) { - wolfBoot_printf("eMMC: CMD0 failed\n"); - return status; - } - - /* Small delay after reset */ - for (volatile int i = 0; i < 10000; i++); - - /* Send CMD1 with operating conditions (3.3V, sector mode) */ - status = emmc_send_op_cond(MMC_DEVICE_3_3V_VOLT_SET, &ocr_reg); - if (status != 0) { - return status; - } - - /* CMD2 - Get CID (card identification) */ - status = mmc_send_cmd(MMC_CMD2_ALL_SEND_CID, 0, EMMC_SD_RESP_R2); - if (status != 0) { - wolfBoot_printf("eMMC: CMD2 failed\n"); - return status; - } - - /* CMD3 - Set relative address (host assigns RCA for eMMC) */ - g_rca = MMC_EMMC_RCA_DEFAULT; - status = mmc_send_cmd(MMC_CMD3_SET_REL_ADDR, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R1); - if (status != 0) { - wolfBoot_printf("eMMC: CMD3 failed\n"); - return status; - } - -#ifdef DEBUG_MMC - wolfBoot_printf("eMMC: RCA set to %d\n", g_rca); -#endif - - /* CMD9 - Get CSD (card-specific data) */ - status = mmc_send_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R2); - if (status != 0) { - wolfBoot_printf("eMMC: CMD9 failed\n"); - return status; - } - - /* Parse CSD to get sector size/count */ - { - uint32_t csd_struct, c_size; - uint32_t bl_len = get_srs_bits(22, 4); - g_sector_size = (1U << bl_len); - - csd_struct = get_srs_bits(126, 2); - /* eMMC typically uses CSD version 3 (EXT_CSD) with fixed 512-byte sectors */ - if (csd_struct >= 2) { - /* For eMMC, actual capacity is in EXT_CSD, use default for now */ - g_sector_size = 512; - g_sector_count = 0; /* Will be read from EXT_CSD if needed */ - } - else { - /* Legacy CSD parsing */ - c_size = get_srs_bits(48, 22); - g_sector_count = (c_size + 1) << 10; - } - -#ifdef DEBUG_MMC - wolfBoot_printf("eMMC: CSD version %d, sector size %d\n", - csd_struct, g_sector_size); -#endif - } - - /* CMD7 - Select card */ - status = mmc_send_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, - EMMC_SD_RESP_R1B); - if (status == DEVICE_BUSY) { - status = mmc_wait_busy(1); - } - if (status != 0) { - wolfBoot_printf("eMMC: CMD7 failed\n"); - return status; - } - - /* Set bus width to 4-bit */ - status = emmc_set_bus_width(MMC_EXT_CSD_WIDTH_4BIT); - if (status != 0) { - wolfBoot_printf("eMMC: Set bus width failed, continuing with 1-bit\n"); - /* Non-fatal, continue with 1-bit */ - } - - /* Set clock to 25MHz for legacy mode */ - mmc_set_clock(EMMC_SD_CLK_25MHZ); - - /* Enable high speed if desired (optional for legacy mode) */ - EMMC_SD_SRS10 |= EMMC_SD_SRS10_HSE; - - return 0; -} -#endif /* USE_EMMC */ - -/* MMC_CMD17_READ_SINGLE, MMC_CMD18_READ_MULTIPLE */ -int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, - uint32_t sz) -{ - int status; - uint32_t block_count; - uint32_t reg, cmd_reg; - - /* get block count (round up) */ - block_count = (sz + (EMMC_SD_BLOCK_SIZE - 1)) / EMMC_SD_BLOCK_SIZE; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_read: cmd_index: %d, block_addr: %08X, dst %p, sz: %d (%d blocks)\n", - cmd_index, block_addr, dst, sz, block_count); -#endif - - /* wait for idle */ - status = mmc_wait_busy(0); - if (status != 0) { - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_read: wait busy error\n"); - #endif - return status; - } - - /* reset data and command lines */ - EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; - - /* wait for command and data line busy to clear */ - while ((EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); - - /* set transfer block count and block size */ - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | sz; - - cmd_reg = ((cmd_index << EMMC_SD_SRS03_CIDX_SHIFT) | - EMMC_SD_SRS03_DPS | EMMC_SD_SRS03_DTDS | - EMMC_SD_SRS03_BCE | EMMC_SD_SRS03_RECE | EMMC_SD_SRS03_RID | - EMMC_SD_SRS03_RESP_48 | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE); - - if (cmd_index == SD_ACMD51_SEND_SCR) { - status = mmc_send_cmd(SD_CMD16, sz, EMMC_SD_RESP_R1); - if (status == 0) { - status = mmc_send_cmd(SD_CMD55_APP_CMD, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1); - } - status = 0; /* ignore error */ - } - else if (cmd_index == MMC_CMD18_READ_MULTIPLE) { - cmd_reg |= EMMC_SD_SRS03_MSBS; /* enable multi-block select */ - - if (sz >= (512 * 1024)) { /* use DMA */ - cmd_reg |= EMMC_SD_SRS03_DMAE; /* enable DMA */ - - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | - EMMC_SD_SRS01_DMA_BUFF_512KB | EMMC_SD_BLOCK_SIZE; - - /* SDMA mode */ - EMMC_SD_SRS10 |= EMMC_SD_SRS10_DMA_SDMA; - /* set SDMA destination address */ - EMMC_SD_SRS22 = (uint32_t)(uintptr_t)dst; - EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)dst) >> 32); - - /* Enable SDMA interrupts */ - mmc_enable_sdma_interrupts(); - } - else { - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | - EMMC_SD_BLOCK_SIZE; - } - } - - EMMC_SD_SRS02 = block_addr; /* cmd argument */ - EMMC_SD_SRS03 = cmd_reg; /* execute command */ - - if (cmd_reg & EMMC_SD_SRS03_DMAE) { - while (1) { /* DMA mode with interrupt support */ - /* Wait for transfer complete or error */ - status = mmc_wait_irq(MMC_IRQ_FLAG_TC, 0x00FFFFFF); - if (status != 0) { - /* Timeout or error */ - wolfBoot_printf("mmc_read: SDMA interrupt timeout/error\n"); - status = -1; /* error */ - break; - } - - /* Check for transfer complete */ - if (g_mmc_irq_status & MMC_IRQ_FLAG_TC) { - g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; - break; /* Transfer complete */ - } - } - - /* Disable SDMA interrupts after transfer */ - mmc_disable_sdma_interrupts(); - } - else { - while (sz > 0) { /* blocking mode */ - /* wait for buffer read ready (or error) */ - while (((reg = EMMC_SD_SRS12) & - (EMMC_SD_SRS12_BRR | EMMC_SD_SRS12_EINT)) == 0); - - /* read in buffer - read 4 bytes at a time */ - if (reg & EMMC_SD_SRS12_BRR) { - uint32_t i, read_sz = sz; - if (read_sz > EMMC_SD_BLOCK_SIZE) { - read_sz = EMMC_SD_BLOCK_SIZE; - } - for (i=0; i= (512 * 1024)) { /* use DMA for large transfers */ - cmd_reg |= EMMC_SD_SRS03_DMAE; /* enable DMA */ - - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | - EMMC_SD_SRS01_DMA_BUFF_512KB | EMMC_SD_BLOCK_SIZE; - - /* SDMA mode (for 32-bit transfers) */ - EMMC_SD_SRS10 |= EMMC_SD_SRS10_DMA_SDMA; - EMMC_SD_SRS15 |= EMMC_SD_SRS15_HV4E; - EMMC_SD_SRS16 &= ~EMMC_SD_SRS16_A64S; - /* set SDMA source address */ - EMMC_SD_SRS22 = (uint32_t)(uintptr_t)src; - EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)src) >> 32); - - /* Enable SDMA interrupts */ - mmc_enable_sdma_interrupts(); - } - else { - /* set transfer block count and block size */ - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | - EMMC_SD_BLOCK_SIZE; - } - } - - EMMC_SD_SRS02 = block_addr; /* cmd argument */ - EMMC_SD_SRS03 = cmd_reg; /* execute command */ - - if (cmd_reg & EMMC_SD_SRS03_DMAE) { - while (1) { /* DMA mode with interrupt support */ - /* Wait for transfer complete or error */ - status = mmc_wait_irq(MMC_IRQ_FLAG_TC, 0x00FFFFFF); - if (status != 0) { - /* Timeout or error */ - wolfBoot_printf("mmc_write: SDMA interrupt timeout/error\n"); - status = -1; /* error */ - break; - } - - /* Check for transfer complete */ - if (g_mmc_irq_status & MMC_IRQ_FLAG_TC) { - g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; - break; /* Transfer complete */ - } - } - - /* Disable SDMA interrupts after transfer */ - mmc_disable_sdma_interrupts(); - } - else { - while (sz > 0) { /* blocking mode */ - /* wait for buffer write ready (or error) */ - while (((reg = EMMC_SD_SRS12) & - (EMMC_SD_SRS12_BWR | EMMC_SD_SRS12_EINT)) == 0); - - /* write buffer - write 4 bytes at a time */ - if (reg & EMMC_SD_SRS12_BWR) { - uint32_t i, write_sz = sz; - if (write_sz > EMMC_SD_BLOCK_SIZE) { - write_sz = EMMC_SD_BLOCK_SIZE; - } - for (i=0; i> shft; - if ((from + shft) > 32) { - ret |= resp[off + 1] << ((32 - shft) % 32); - } - return ret & mask; -} - -/* check or set switch function/group: - * returns 0 if supported */ -int mmc_send_switch_function(uint32_t mode, uint32_t function_number, - uint32_t group_number) -{ - int status; - uint32_t timeout = 4; - uint32_t cmd_arg; - uint32_t func_status[64/sizeof(uint32_t)]; /* fixed 512 bits */ - uint8_t* p_func_status = (uint8_t*)func_status; - - if (group_number > 6 || function_number > 15) { - return -1; /* Invalid group or function number */ - } - - cmd_arg = (function_number << ((group_number - 1) * 4)); - do { - /* first run check to see if function is supported */ - status = mmc_read(SD_CMD6_SWITCH_FUNC, - (mode | cmd_arg), - func_status, sizeof(func_status)); - if (status == 0) { - /* check if busy */ - /* data structure version 368:375 - * (0=supported only, 1=supported and busy) */ - if (p_func_status[17] == 1) { - /* busy status: group 1 272:287 */ - if ((p_func_status[29 - - ((group_number-1)*2)] & (1 << function_number))) { - continue; /* busy */ - } - } - - /* supported: group 1 415:400 */ - if ((p_func_status[13 - - ((group_number-1)*2)] & (1 << function_number))) { - status = 0; /* supported */ - } - else { - status = -1; /* not supported */ - } - break; - } - } while (status == 0 && --timeout > 0); /* retry until function not busy */ - return status; -} - -int mmc_set_function(uint32_t function_number, uint32_t group_number) -{ - /* send check first */ - int status = mmc_send_switch_function(SDCARD_SWITCH_FUNC_MODE_CHECK, - function_number, group_number); - if (status == 0) { - /* send switch function */ - status = mmc_send_switch_function(SDCARD_SWITCH_FUNC_MODE_SWITCH, - function_number, group_number); - } - return status; -} - -#ifdef ENABLE_MMC_SD_TUNING -/* ========================================================================== - * SD Tuning Functions (CMD19-based for SDR50/SDR104) - * ========================================================================== */ - -#define EMMC_SD_TUNING_BLOCK_SIZE 64 /* SD tuning block size (bytes) */ -#define EMMC_SD_TUNING_MAX_LOOPS 40 /* Max tuning iterations per spec */ - -/* Send CMD19 tuning block and read 64 bytes. - * Based on HSS read_tune_block() for SD_CMD_19_SEND_TUNING_BLK */ -static int mmc_send_tuning_block(uint32_t *data) -{ - uint32_t cmd_reg, srs12; - int i; - - /* Wait for idle */ - while (EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)); - - /* Clear all status interrupts */ - EMMC_SD_SRS12 = (EMMC_SD_SRS12_NORM_STAT | EMMC_SD_SRS12_ERR_STAT); - - /* Block length = 64, block count = 1 */ - EMMC_SD_SRS01 = (1 << EMMC_SD_SRS01_BCCT_SHIFT) | EMMC_SD_TUNING_BLOCK_SIZE; - - /* CMD19: Data present, read direction, R1 response */ - cmd_reg = (SD_CMD19_SEND_TUNING << EMMC_SD_SRS03_CIDX_SHIFT) | - EMMC_SD_SRS03_DPS | /* Data Present */ - EMMC_SD_SRS03_DTDS | /* Data Transfer Direction: Read */ - EMMC_SD_SRS03_BCE | /* Block Count Enable */ - EMMC_SD_SRS03_RID | /* Response Interrupt Disable */ - EMMC_SD_SRS03_RECE | /* Response Error Check Enable */ - EMMC_SD_SRS03_RESP_48 | - EMMC_SD_SRS03_CRCCE | - EMMC_SD_SRS03_CICE; - - /* Command argument = 0 for CMD19 */ - EMMC_SD_SRS02 = 0; - EMMC_SD_SRS03 = cmd_reg; - - /* Wait for buffer read ready or error */ - do { - srs12 = EMMC_SD_SRS12; - } while ((srs12 & (EMMC_SD_SRS12_BRR | EMMC_SD_SRS12_EINT)) == 0); - - /* Read data if buffer ready */ - if (srs12 & EMMC_SD_SRS12_BRR) { - for (i = 0; i < (EMMC_SD_TUNING_BLOCK_SIZE / 4); i++) { - data[i] = EMMC_SD_SRS08; - } - } - - /* Check for errors */ - srs12 = EMMC_SD_SRS12; - EMMC_SD_SRS12 = (EMMC_SD_SRS12_NORM_STAT | EMMC_SD_SRS12_ERR_STAT); - - if (srs12 & EMMC_SD_SRS12_ERR_STAT) { - return -1; - } - return 0; -} - -/* Execute SD tuning procedure using CMD19 and Execute Tuning bit. - * Based on HSS sd_tuning() implementation */ -static int mmc_sd_tuning(void) -{ - uint32_t reg; - uint32_t tuning_data[EMMC_SD_TUNING_BLOCK_SIZE / 4]; - int count; - int status = 0; - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_sd_tuning: starting\n"); -#endif - - reg = EMMC_SD_SRS15; - - /* Reset tuning: clear Sampling Clock Select */ - reg &= ~EMMC_SD_SRS15_SCS; - /* Start tuning: set Execute Tuning */ - reg |= EMMC_SD_SRS15_EXTNG; - EMMC_SD_SRS15 = reg; - - /* Tuning loop - send CMD19 up to 40 times */ - for (count = EMMC_SD_TUNING_MAX_LOOPS; count > 0; count--) { - status = mmc_send_tuning_block(tuning_data); - if (status != 0) { - /* Reset data/cmd lines on failure */ - EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; - while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); - break; - } - - /* Check if Execute Tuning has cleared (hardware completed) */ - reg = EMMC_SD_SRS15; - if ((reg & EMMC_SD_SRS15_EXTNG) == 0) { - break; - } - } - - /* Check result: Sampling Clock Select should be set on success */ - reg = EMMC_SD_SRS15; - if ((reg & EMMC_SD_SRS15_SCS) == 0) { - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_sd_tuning: FAILED (SCS not set)\n"); - #endif - /* Clear Execute Tuning if still set */ - if (reg & EMMC_SD_SRS15_EXTNG) { - EMMC_SD_SRS15 = reg & ~EMMC_SD_SRS15_EXTNG; - } - return -1; - } - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_sd_tuning: SUCCESS after %d iterations\n", - EMMC_SD_TUNING_MAX_LOOPS - count + 1); -#endif - return 0; -} - -/* PHY training - find optimal delay value by testing reads - * Based on HSS phy_training_mmc() implementation */ -static int mmc_tune(uint8_t phy_addr, uint32_t clk_khz) -{ - int status; - uint8_t delay, max_delay; - uint8_t pos = 0, length = 0, curr_length = 0; - uint32_t tmp_block[EMMC_SD_BLOCK_SIZE / sizeof(uint32_t)]; - - /* Calculate max delay based on clock rate (from HSS) */ - if (clk_khz <= 12500) { - max_delay = 20; - } else { - max_delay = (uint8_t)((200000 / clk_khz) * 2); - } - if (max_delay > 40) { - max_delay = 40; - } - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_tune: phy_addr=0x%02x, clk=%d kHz, max_delay=%d\n", - phy_addr, clk_khz, max_delay); -#endif - - /* Test each delay value to find longest valid range */ - for (delay = 0; delay < max_delay; delay++) { - mmc_phy_write(phy_addr, delay); - - /* Try a single block read to test this delay setting */ - status = mmc_read(MMC_CMD17_READ_SINGLE, 0, tmp_block, - EMMC_SD_BLOCK_SIZE); - if (status == 0) { - curr_length++; - if (curr_length > length) { - pos = delay - length; - length++; - } - } else { - /* Reset data/cmd lines on failure */ - EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; - while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); - curr_length = 0; - } - } - - /* Set optimal delay (middle of longest valid range) */ - if (length > 0) { - uint8_t new_delay = pos + (length / 2); - mmc_phy_write(phy_addr, new_delay); - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_tune: PHY delay=%d (range: pos=%d, len=%d)\n", - new_delay, pos, length); - #endif - - /* For SDR50/SDR104, also run SD tuning (CMD19) if required. - * Check SRS17 bit 13 (TSDR50) - Tuning for SDR50 required */ - if (EMMC_SD_SRS17 & EMMC_SD_SRS17_TSDR50) { - status = mmc_sd_tuning(); - if (status != 0) { - #ifdef DEBUG_MMC - wolfBoot_printf("mmc_tune: SD tuning failed\n"); - #endif - return status; - } - } - - return 0; - } - -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_tune: FAILED - no valid PHY delay found\n"); -#endif - return -1; -} -#endif /* ENABLE_MMC_SD_TUNING */ +#if defined(DISK_SDCARD) || defined(DISK_EMMC) +/* ============================================================================ + * SDHCI Platform HAL Functions + * ============================================================================ */ -int mmc_init(void) +/* Platform initialization - called from sdhci_init() */ +void sdhci_platform_init(void) { - int status = 0; - uint32_t reg, cap; - - /* Reset the MMC controller */ + /* Release MMC controller from reset */ SYSREG_SOFT_RESET_CR &= ~SYSREG_SOFT_RESET_CR_MMC; - /* Disable the EMMC/SD IRQ */ - - /* Reset the host controller */ - EMMC_SD_HRS00 |= EMMC_SD_HRS00_SWR; - /* Bit will clear when reset is done */ - while ((EMMC_SD_HRS00 & EMMC_SD_HRS00_SWR) != 0); - - /* Set debounce period to ~15ms (at 200MHz) */ - EMMC_SD_HRS01 = ((EMMC_SD_DEBOUNCE_TIME << EMMC_SD_HRS01_DP_SHIFT) & - EMMC_SD_HRS01_DP_MASK); - - /* Select card mode */ - reg = EMMC_SD_HRS06; - reg &= ~EMMC_SD_HRS06_EMM_MASK; -#ifdef USE_EMMC - reg |= EMMC_SD_HRS06_MODE_LEGACY; /* eMMC Legacy mode */ -#else - reg |= EMMC_SD_HRS06_MODE_SD; /* SD card mode */ -#endif - EMMC_SD_HRS06 = reg; - - /* Clear error/interrupt status */ - EMMC_SD_SRS12 = (EMMC_SD_SRS12_NORM_STAT | EMMC_SD_SRS12_ERR_STAT); - - /* Check and enable 64-bit DMA support */ - reg = EMMC_SD_SRS15; - cap = EMMC_SD_SRS16; - if (cap & EMMC_SD_SRS16_A64S) { - reg |= EMMC_SD_SRS15_A64; - reg |= EMMC_SD_SRS15_HV4E; - EMMC_SD_SRS15 = reg; - } - /* Set all status enables - 0xbff40ff */ - EMMC_SD_SRS13 = ( - EMMC_SD_SRS13_ETUNE_SE | EMMC_SD_SRS13_EADMA_SE | EMMC_SD_SRS13_EAC_SE | - EMMC_SD_SRS13_ECL_SE | EMMC_SD_SRS13_EDEB_SE | - EMMC_SD_SRS13_EDCRC_SE | EMMC_SD_SRS13_EDT_SE | - EMMC_SD_SRS13_ECI_SE | EMMC_SD_SRS13_ECEB_SE | EMMC_SD_SRS13_ECCRC_SE | - EMMC_SD_SRS13_ECT_SE | EMMC_SD_SRS13_RTUNE_SE | - EMMC_SD_SRS13_INT_ONC | EMMC_SD_SRS13_INT_ONB | EMMC_SD_SRS13_INT_ONA | - EMMC_SD_SRS13_CR_SE | EMMC_SD_SRS13_CIN_SE | - EMMC_SD_SRS13_BRR_SE | EMMC_SD_SRS13_BWR_SE | EMMC_SD_SRS13_DMAINT_SE | - EMMC_SD_SRS13_BGE_SE | EMMC_SD_SRS13_TC_SE | EMMC_SD_SRS13_CC_SE | - EMMC_SD_SRS13_ERSP_SE | EMMC_SD_SRS13_CQINT_SE - ); - /* Clear all signal enables (will be enabled per-transfer for SDMA) */ - EMMC_SD_SRS14 = 0; - - /* Initialize PLIC for MMC interrupts */ - plic_init_mmc(); - - /* Set initial timeout to 500ms */ - status = mmc_set_timeout(EMMC_SD_INIT_TIMEOUT_US); - if (status != 0) { - return status; - } - /* Turn off host controller power */ - (void)mmc_set_power(0); - - /* check if card inserted and stable */ - reg = EMMC_SD_SRS09; - if ((reg & EMMC_SD_SRS09_CSS) == 0) { - /* card not inserted or not stable */ - return -1; - } -#ifndef USE_EMMC - /* For SD card: check if card is inserted - * (eMMC is soldered on board, skip this check) */ - if ((reg & EMMC_SD_SRS09_CI) == 0) { - /* card not inserted */ - return -1; - } -#endif - - /* Start in 1-bit bus mode */ - EMMC_SD_SRS10 &= ~(EMMC_SD_SRS10_EDTW | EMMC_SD_SRS10_DTW); - - /* Setup 400khz starting clock */ - mmc_set_clock(EMMC_SD_CLK_400KHZ); - -#ifdef USE_EMMC - /* ========================================================================= - * eMMC Initialization Path - * ========================================================================= */ - - /* Set power to 3.3v */ - status = mmc_set_power(EMMC_SD_SRS10_BVS_3_3V); - if (status != 0) { - wolfBoot_printf("eMMC: Failed to set power\n"); - return status; - } - - /* Run full eMMC card initialization */ - status = emmc_card_full_init(); - if (status != 0) { - wolfBoot_printf("eMMC: Card initialization failed\n"); - return status; - } - -#else /* USE_SDCARD */ - /* ========================================================================= - * SD Card Initialization Path - * ========================================================================= */ - - /* Run full SD card initialization */ - status = sdcard_card_full_init(); - if (status != 0) { - wolfBoot_printf("SD Card: Card initialization failed\n"); - return status; - } - -#endif /* USE_EMMC */ - - /* Common finalization for both eMMC and SD */ - if (status == 0) { - /* Set data timeout to 3000ms */ - status = mmc_set_timeout(EMMC_SD_DATA_TIMEOUT_US); - } - return status; -} - -/* returns number of bytes read on success or negative on error */ -/* start may not be block aligned and count may not be block multiple */ -int disk_read(int drv, uint64_t start, uint32_t count, uint8_t *buf) -{ - int status = 0; - uint32_t read_sz, block_addr; - uint32_t tmp_block[EMMC_SD_BLOCK_SIZE/sizeof(uint32_t)]; - uint32_t start_offset = (start % EMMC_SD_BLOCK_SIZE); - (void)drv; /* only one drive supported */ - -#ifdef DEBUG_MMC - wolfBoot_printf("disk_read: drv:%d, start:%llu, count:%d, dst:%p\n", - drv, start, count, buf); -#endif - - while (count > 0) { - block_addr = (start / EMMC_SD_BLOCK_SIZE); - read_sz = count; - if (read_sz > EMMC_SD_BLOCK_SIZE) { - read_sz = EMMC_SD_BLOCK_SIZE; - } - if (read_sz < EMMC_SD_BLOCK_SIZE || /* last partial */ - start_offset != 0 || /* start not block aligned */ - ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ - { - /* block read to temporary buffer */ - status = mmc_read(MMC_CMD17_READ_SINGLE, block_addr, - tmp_block, EMMC_SD_BLOCK_SIZE); - if (status == 0) { - uint8_t* tmp_buf = (uint8_t*)tmp_block; - memcpy(buf, tmp_buf + start_offset, read_sz); - start_offset = 0; - } - } - else { - /* direct full block(s) read */ - uint32_t blocks = (count / EMMC_SD_BLOCK_SIZE); - read_sz = (blocks * EMMC_SD_BLOCK_SIZE); - status = mmc_read(blocks > 1 ? - MMC_CMD18_READ_MULTIPLE : - MMC_CMD17_READ_SINGLE, - block_addr, (uint32_t*)buf, read_sz); - } - if (status != 0) { - break; - } - - start += read_sz; - buf += read_sz; - count -= read_sz; - } - return status; } -int disk_write(int drv, uint64_t start, uint32_t count, const uint8_t *buf) +/* Platform interrupt setup - called from sdhci_init() */ +void sdhci_platform_irq_init(void) { - int status = 0; - uint32_t write_sz, block_addr; - uint32_t tmp_block[EMMC_SD_BLOCK_SIZE/sizeof(uint32_t)]; - uint32_t start_offset = (start % EMMC_SD_BLOCK_SIZE); - (void)drv; /* only one drive supported */ - -#ifdef DEBUG_MMC - wolfBoot_printf("disk_write: drv:%d, start:%llu, count:%d, src:%p\n", - drv, start, count, buf); -#endif + /* Set priority for MMC main interrupt */ + plic_set_priority(PLIC_INT_MMC_MAIN, PLIC_PRIORITY_DEFAULT); - while (count > 0) { - block_addr = (start / EMMC_SD_BLOCK_SIZE); - write_sz = count; - if (write_sz > EMMC_SD_BLOCK_SIZE) { - write_sz = EMMC_SD_BLOCK_SIZE; - } - if (write_sz < EMMC_SD_BLOCK_SIZE || /* partial block */ - start_offset != 0 || /* start not block aligned */ - ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ - { - /* read-modify-write for partial block */ - status = mmc_read(MMC_CMD17_READ_SINGLE, block_addr, - tmp_block, EMMC_SD_BLOCK_SIZE); - if (status == 0) { - uint8_t* tmp_buf = (uint8_t*)tmp_block; - memcpy(tmp_buf + start_offset, buf, write_sz); - status = mmc_write(MMC_CMD24_WRITE_SINGLE, block_addr, - tmp_block, EMMC_SD_BLOCK_SIZE); - start_offset = 0; - } - } - else { - /* direct full block(s) write */ - uint32_t blocks = (count / EMMC_SD_BLOCK_SIZE); - write_sz = (blocks * EMMC_SD_BLOCK_SIZE); - status = mmc_write(blocks > 1 ? - MMC_CMD25_WRITE_MULTIPLE : - MMC_CMD24_WRITE_SINGLE, - block_addr, (const uint32_t*)buf, write_sz); - } - if (status != 0) { - break; - } + /* Set threshold to 0 (allow all priorities > 0) */ + plic_set_threshold(0); - start += write_sz; - buf += write_sz; - count -= write_sz; - } - return status; -} + /* Enable MMC interrupt for this hart */ + plic_enable_interrupt(PLIC_INT_MMC_MAIN); -int disk_init(int drv) -{ - int r = mmc_init(); - if (r != 0) { - wolfBoot_printf("Failed to initialize MMC\n"); - } - (void)drv; -#ifdef DISK_TEST - disk_test(drv); +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_platform_irq_init: hart %d, context %d, irq %d enabled\n", + get_boot_hartid(), plic_get_context(), PLIC_INT_MMC_MAIN); #endif - return r; } -void disk_close(int drv) +/* Platform bus mode selection - called from sdhci_init() */ +void sdhci_platform_set_bus_mode(int is_emmc) { - (void)drv; + (void)is_emmc; + /* Nothing additional needed for MPFS - mode is set in generic driver */ } +#endif /* DISK_SDCARD || DISK_EMMC */ -#ifdef DISK_TEST -/* Test block address in update partition */ -#ifndef DISK_TEST_BLOCK_ADDR -#define DISK_TEST_BLOCK_ADDR 149504 -#endif - -/* disk_test: Test read/write functionality at update partition - * Tests sizes: 128, 512, 1024, 512KB (524288), 1MB (1048576) bytes - * Uses DDR at WOLFBOOT_LOAD_ADDRESS for test buffer - * Returns 0 on success, negative on failure */ -static int disk_test(int drv) -{ - int status = 0; - int test_num = 0; - uint32_t i; - static const uint32_t test_sizes[] = { - 128, /* partial block */ - 512, /* single block */ - 1024, /* two blocks */ - 512 * 1024, /* 512KB - DMA threshold */ - 1024 * 1024 /* 1MB */ - }; - /* Use DDR memory at WOLFBOOT_LOAD_ADDRESS for test buffer */ - uint32_t* tmp_buf32 = (uint32_t*)WOLFBOOT_LOAD_ADDRESS; - uint8_t* tmp_buf = (uint8_t*)WOLFBOOT_LOAD_ADDRESS; - - wolfBoot_printf("disk_test: Starting tests at block %d (buf @ %p)\n", - DISK_TEST_BLOCK_ADDR, tmp_buf); - - for (test_num = 0; test_num < (int)(sizeof(test_sizes)/sizeof(test_sizes[0])); test_num++) { - uint32_t test_sz = test_sizes[test_num]; - uint64_t test_addr = (uint64_t)DISK_TEST_BLOCK_ADDR * EMMC_SD_BLOCK_SIZE; - uint32_t blocks_needed = (test_sz + EMMC_SD_BLOCK_SIZE - 1) / EMMC_SD_BLOCK_SIZE; - - wolfBoot_printf(" Test %d: size=%u bytes (%u blocks)... ", - test_num + 1, test_sz, blocks_needed); - - /* Fill with test pattern */ - for (i = 0; i < test_sz / sizeof(uint32_t); i++) { - tmp_buf32[i] = (test_num << 24) | i; - } - /* Handle remaining bytes for non-word-aligned sizes */ - for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { - tmp_buf[i] = (uint8_t)((test_num << 4) | (i & 0x0F)); - } - - /* Write */ - status = disk_write(drv, test_addr, test_sz, tmp_buf); - if (status != 0) { - wolfBoot_printf("FAIL (write error %d)\n", status); - continue; - } - - /* Clear buffer */ - memset(tmp_buf, 0, test_sz); - - /* Read back */ - status = disk_read(drv, test_addr, test_sz, tmp_buf); - if (status != 0) { - wolfBoot_printf("FAIL (read error %d)\n", status); - continue; - } - - /* Verify pattern */ - for (i = 0; i < test_sz / sizeof(uint32_t); i++) { - uint32_t expected = (test_num << 24) | i; - if (tmp_buf32[i] != expected) { - wolfBoot_printf("FAIL (verify @ word %u: got 0x%08X, expected 0x%08X)\n", - i, tmp_buf32[i], expected); - status = -1; - break; - } - } - /* Verify remaining bytes for non-word-aligned sizes */ - if (status == 0) { - for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { - uint8_t expected = (uint8_t)((test_num << 4) | (i & 0x0F)); - if (tmp_buf[i] != expected) { - wolfBoot_printf("FAIL (verify @ byte %u: got 0x%02X, expected 0x%02X)\n", - i, tmp_buf[i], expected); - status = -1; - break; - } - } - } - - if (status == 0) { - wolfBoot_printf("PASS\n"); - } - } - - wolfBoot_printf("disk_test: Complete\n"); - return status; -} -#endif /* DISK_TEST */ - +/* ============================================================================ + * DEBUG UART Functions + * ============================================================================ */ #ifdef DEBUG_UART diff --git a/hal/mpfs250.h b/hal/mpfs250.h index fb93f5c678..fe32444412 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -22,8 +22,8 @@ #ifndef MPFS250_DEF_INCLUDED #define MPFS250_DEF_INCLUDED -/* Include generic RISC-V definitions */ -#include "hal/riscv.h" +/* Generic RISC-V definitions are included at the end of this file + * (after PLIC_BASE is defined) to enable PLIC function declarations */ /* PolarFire SoC MPFS250T board specific configuration */ @@ -131,770 +131,17 @@ * ============================================================================ */ #define EMMC_SD_BASE 0x20008000UL -/* ---------------------------------------------------------------------------- - * HRS - Host Register Set (Cadence-specific registers) - * ---------------------------------------------------------------------------- */ - -/* HRS00 - General Information Register */ -#define EMMC_SD_HRS00 *((volatile uint32_t*)(EMMC_SD_BASE + 0x000)) -#define EMMC_SD_HRS00_SAV_SHIFT 16 /* 23:16: RO - Number of slots */ -#define EMMC_SD_HRS00_SAV_MASK (0xFFU << 16) -#define EMMC_SD_HRS00_SWR (1U << 0) /* 0: RW - Software Reset (entire core) */ - -/* HRS01 - Debounce Setting Register */ -#define EMMC_SD_HRS01 *((volatile uint32_t*)(EMMC_SD_BASE + 0x004)) -#define EMMC_SD_HRS01_DP_SHIFT 0 /* 23:0: RW - Debounce Period */ -#define EMMC_SD_HRS01_DP_MASK (0xFFFFFFU << 0) - -/* HRS02 - Bus Setting Register */ -#define EMMC_SD_HRS02 *((volatile uint32_t*)(EMMC_SD_BASE + 0x008)) -#define EMMC_SD_HRS02_OTN_SHIFT 16 /* 17:16: RW - Outstanding Transactions Number */ -#define EMMC_SD_HRS02_OTN_MASK (0x3U << 16) -#define EMMC_SD_HRS02_PBL_SHIFT 0 /* 3:0: RW - Programmable Burst Length */ -#define EMMC_SD_HRS02_PBL_MASK (0xFU << 0) - -/* HRS03 - AXI ERROR Responses Register */ -#define EMMC_SD_HRS03 *((volatile uint32_t*)(EMMC_SD_BASE + 0x00C)) -#define EMMC_SD_HRS03_AER_IEBS (1U << 19) /* 19: Int Enable Bus Status */ -#define EMMC_SD_HRS03_AER_IEBD (1U << 18) /* 18: Int Enable Bus Data */ -#define EMMC_SD_HRS03_AER_IERS (1U << 17) /* 17: Int Enable Resp Status */ -#define EMMC_SD_HRS03_AER_IERD (1U << 16) /* 16: Int Enable Resp Data */ -#define EMMC_SD_HRS03_AER_SENBS (1U << 11) /* 11: Status Enable Bus Status */ -#define EMMC_SD_HRS03_AER_SENBD (1U << 10) /* 10: Status Enable Bus Data */ -#define EMMC_SD_HRS03_AER_SENRS (1U << 9) /* 9: Status Enable Resp Status */ -#define EMMC_SD_HRS03_AER_SENRD (1U << 8) /* 8: Status Enable Resp Data */ - -/* HRS04 - PHY Registers Interface (SD/eMMC PHY access) */ -#define EMMC_SD_HRS04 *((volatile uint32_t*)(EMMC_SD_BASE + 0x010)) -#define EMMC_SD_HRS04_UIS_ACK (1U << 26) /* 26: RO - PHY Acknowledge */ -#define EMMC_SD_HRS04_UIS_RD (1U << 25) /* 25: RW - PHY Read Request */ -#define EMMC_SD_HRS04_UIS_WR (1U << 24) /* 24: RW - PHY Write Request */ -#define EMMC_SD_HRS04_UIS_RDATA_SHIFT 16 /* 23:16: RO - PHY Read Data */ -#define EMMC_SD_HRS04_UIS_RDATA_MASK (0xFFU << 16) -#define EMMC_SD_HRS04_UIS_WDATA_SHIFT 8 /* 15:8: RW - PHY Write Data */ -#define EMMC_SD_HRS04_UIS_WDATA_MASK (0xFFU << 8) -#define EMMC_SD_HRS04_UIS_ADDR_SHIFT 0 /* 5:0: RW - PHY Register Address */ -#define EMMC_SD_HRS04_UIS_ADDR_MASK (0x3FU << 0) -/* PHY register addresses */ -#define EMMC_SD_PHY_ADDR_HIGH_SPEED 0x00U -#define EMMC_SD_PHY_ADDR_DEFAULT_SPEED 0x01U -#define EMMC_SD_PHY_ADDR_UHSI_SDR12 0x02U -#define EMMC_SD_PHY_ADDR_UHSI_SDR25 0x03U -#define EMMC_SD_PHY_ADDR_UHSI_SDR50 0x04U -#define EMMC_SD_PHY_ADDR_UHSI_DDR50 0x05U -#define EMMC_SD_PHY_ADDR_MMC_LEGACY 0x06U -#define EMMC_SD_PHY_ADDR_MMC_SDR 0x07U -#define EMMC_SD_PHY_ADDR_MMC_DDR 0x08U -#define EMMC_SD_PHY_ADDR_SDCLK 0x0BU -#define EMMC_SD_PHY_ADDR_HS_SDCLK 0x0CU -#define EMMC_SD_PHY_ADDR_DAT_STROBE 0x0DU - -/* HRS06 - eMMC Control Register */ -#define EMMC_SD_HRS06 *((volatile uint32_t*)(EMMC_SD_BASE + 0x018)) -#define EMMC_SD_HRS06_ETR (1U << 15) /* 15: RW - eMMC Tune Request */ -#define EMMC_SD_HRS06_ETV_SHIFT 8 /* eMMC Tune Value */ -#define EMMC_SD_HRS06_ETV_MASK 0x3FU -#define EMMC_SD_HRS06_EMM_SHIFT 0 /* 2:0: RW - eMMC Mode Select */ -#define EMMC_SD_HRS06_EMM_MASK (0x7U << 0) -/* eMMC Mode values */ -#define EMMC_SD_HRS06_MODE_SD (0x0U << 0) /* SD card mode */ -#define EMMC_SD_HRS06_MODE_MMC_SDR (0x2U << 0) /* eMMC SDR mode */ -#define EMMC_SD_HRS06_MODE_MMC_DDR (0x3U << 0) /* eMMC DDR mode */ -#define EMMC_SD_HRS06_MODE_MMC_HS200 (0x4U << 0) /* eMMC HS200 mode */ -#define EMMC_SD_HRS06_MODE_MMC_HS400 (0x5U << 0) /* eMMC HS400 mode */ -#define EMMC_SD_HRS06_MODE_MMC_HS400ES (0x6U << 0) /* eMMC HS400 Enhanced Strobe */ -#define EMMC_SD_HRS06_MODE_LEGACY (0x7U << 0) /* Legacy mode */ - -/* HRS07 - IO Delay Information Register */ -#define EMMC_SD_HRS07 *((volatile uint32_t*)(EMMC_SD_BASE + 0x01C)) -#define EMMC_SD_HRS07_ODELAY_VAL_SHIFT 16 /* 20:16: RW - Output Delay Value */ -#define EMMC_SD_HRS07_ODELAY_VAL_MASK (0x1FU << 16) -#define EMMC_SD_HRS07_IDELAY_VAL_SHIFT 0 /* 4:0: RW - Input Delay Value */ -#define EMMC_SD_HRS07_IDELAY_VAL_MASK (0x1FU << 0) - -#define EMMC_SD_HRS30 *((volatile uint32_t*)(EMMC_SD_BASE + 0x078)) /* Host Capability Register */ -#define EMMC_SD_HRS30_HS400ESSUP (1U << 1) /* 1: RO - HS400 Enhanced Strobe Support */ -#define EMMC_SD_HRS30_CQSUP (1U << 0) /* 0: RO - Command Queuing Support */ - -#define EMMC_SD_HRS31 *((volatile uint32_t*)(EMMC_SD_BASE + 0x07C)) /* Host Controller Version */ -#define EMMC_SD_HRS31_HOSTCTRLVER_SHIFT 16 /* 27:16: RO */ -#define EMMC_SD_HRS31_HOSTCTRLVER_MASK (0xFFFU << 16) -#define EMMC_SD_HRS31_HOSTFIXVER_SHIFT 0 /* 7:0: RO */ -#define EMMC_SD_HRS31_HOSTFIXVER_MASK (0xFFU << 0) - -#define EMMC_SD_HRS32 *((volatile uint32_t*)(EMMC_SD_BASE + 0x080)) /* FSM Monitor Register */ -#define EMMC_SD_HRS32_LOAD (1U << 31) /* 31: RW */ -#define EMMC_SD_HRS32_ADDR_SHIFT 16 /* 30:16: WO */ -#define EMMC_SD_HRS32_ADDR_MASK (0x7FFFU << 16) -#define EMMC_SD_HRS32_DATA_SHIFT 0 /* 15:0: RO */ -#define EMMC_SD_HRS32_DATA_MASK (0xFFFFU << 0) - -#define EMMC_SD_HRS33 *((volatile uint32_t*)(EMMC_SD_BASE + 0x084)) /* Tune Status 0 Register */ -#define EMMC_SD_HRS33_STAT0_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_HRS33_STAT0_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_HRS34 *((volatile uint32_t*)(EMMC_SD_BASE + 0x088)) /* Tune Status 1 Register */ -#define EMMC_SD_HRS34_STAT1_SHIFT 0 /* 7:0: RO */ -#define EMMC_SD_HRS34_STAT1_MASK (0xFFU << 0) - -#define EMMC_SD_HRS35 *((volatile uint32_t*)(EMMC_SD_BASE + 0x08C)) /* Tune Debug Register */ -#define EMMC_SD_HRS35_TFR (1U << 31) /* 31: RW */ -#define EMMC_SD_HRS35_TFV_SHIFT 16 /* 21:16: RW */ -#define EMMC_SD_HRS35_TFV_MASK (0x3FU << 16) -#define EMMC_SD_HRS35_TVAL_SHIFT 0 /* 5:0: RO */ -#define EMMC_SD_HRS35_TVAL_MASK (0x3FU << 0) - -#define EMMC_SD_HRS36 *((volatile uint32_t*)(EMMC_SD_BASE + 0x090)) /* Boot Status Register */ -#define EMMC_SD_HRS36_BOOT_EDE (1U << 5) /* 5: RO - Boot Error Data End Bit */ -#define EMMC_SD_HRS36_BOOT_EDC (1U << 4) /* 4: RO - Boot Error Data CRC */ -#define EMMC_SD_HRS36_BOOT_EDT (1U << 3) /* 3: RO - Boot Error Data Timeout */ -#define EMMC_SD_HRS36_BOOT_EAI (1U << 2) /* 2: RO - Boot Error Ack Index */ -#define EMMC_SD_HRS36_BOOT_EAT (1U << 1) /* 1: RO - Boot Error Ack Timeout */ -#define EMMC_SD_HRS36_BOOT_ACT (1U << 0) /* 0: RO - Boot Active */ - -#define EMMC_SD_HRS37 *((volatile uint32_t*)(EMMC_SD_BASE + 0x094)) /* Read block gap coeff interface mode select */ -#define EMMC_SD_HRS37_RGB_COEFF_IFM_SHIFT 0 /* 5:0: RW */ -#define EMMC_SD_HRS37_RGB_COEFF_IFM_MASK (0x3FU << 0) - -#define EMMC_SD_HRS38 *((volatile uint32_t*)(EMMC_SD_BASE + 0x098)) /* Read block gap coefficient */ -#define EMMC_SD_HRS38_RGB_COEFF_SHIFT 0 /* 3:0: RW */ -#define EMMC_SD_HRS38_RGB_COEFF_MASK (0xFU << 0) - -/* CRS - Capability Register Set */ -#define EMMC_SD_CRS63 *((volatile uint32_t*)(EMMC_SD_BASE + 0x0FC)) /* Host Controller Version/Slot Interrupt Status */ -#define EMMC_SD_CRS63_SVN_SHIFT 16 /* 23:16: RO */ -#define EMMC_SD_CRS63_SVN_MASK (0xFFU << 16) -#define EMMC_SD_CRS63_ISES_SHIFT 0 /* 7:0: RO */ -#define EMMC_SD_CRS63_ISES_MASK (0xFFU << 0) - -/* ---------------------------------------------------------------------------- - * SRS - Slot Register Set (SD Host Controller Standard Registers) - * ---------------------------------------------------------------------------- */ - -/* SRS00 - SDMA System Address / Argument 2 (for Auto CMD23) */ -#define EMMC_SD_SRS00 *((volatile uint32_t*)(EMMC_SD_BASE + 0x200)) -#define EMMC_SD_SRS00_SAAR_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_SRS00_SAAR_MASK (0xFFFFFFFFU << 0) - -/* SRS01 - Block Size / Block Count Register */ -#define EMMC_SD_SRS01 *((volatile uint32_t*)(EMMC_SD_BASE + 0x204)) -#define EMMC_SD_SRS01_BCCT_SHIFT 16 /* 31:16: RW - Block Count for Current Transfer */ -#define EMMC_SD_SRS01_BCCT_MASK (0xFFFFU << 16) -#define EMMC_SD_SRS01_SDMABB_SHIFT 12 /* SDMA Buffer Boundary */ -#define EMMC_SD_SRS01_SDMABB_MASK 0x7U -#define EMMC_SD_SRS01_DMA_BUFF_4KB (0x0U << 12) /* DMA buffer 4KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_8KB (0x1U << 12) /* DMA buffer 8KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_16KB (0x2U << 12) /* DMA buffer 16KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_32KB (0x3U << 12) /* DMA buffer 32KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_64KB (0x4U << 12) /* DMA buffer 64KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_128KB (0x5U << 12) /* DMA buffer 128KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_256KB (0x6U << 12) /* DMA buffer 256KB boundary */ -#define EMMC_SD_SRS01_DMA_BUFF_512KB (0x7U << 12) /* DMA buffer 512KB boundary */ -#define EMMC_SD_SRS01_TBS_SHIFT 0 /* 11:0: RW - Transfer Block Size */ -#define EMMC_SD_SRS01_TBS_MASK (0xFFFU << 0) - -/* SRS02 - Argument 1 Register */ -#define EMMC_SD_SRS02 *((volatile uint32_t*)(EMMC_SD_BASE + 0x208)) -#define EMMC_SD_SRS02_ARG1_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_SRS02_ARG1_MASK (0xFFFFFFFFU << 0) - -/* SRS03 - Command/Transfer Mode Register */ -#define EMMC_SD_SRS03 *((volatile uint32_t*)(EMMC_SD_BASE + 0x20C)) -#define EMMC_SD_SRS03_CIDX_SHIFT 24 /* 29:24: RW - Command Index */ -#define EMMC_SD_SRS03_CIDX_MASK (0x3FU << 24) -#define EMMC_SD_SRS03_CT_SHIFT 22 /* 23:22: RW - Command Type */ -#define EMMC_SD_SRS03_CT_MASK (0x3U << 22) -#define EMMC_SD_SRS03_CMD_NORMAL (0x0U << 22) /* Normal command */ -#define EMMC_SD_SRS03_CMD_SUSPEND (0x1U << 22) /* Suspend command */ -#define EMMC_SD_SRS03_CMD_RESUME (0x2U << 22) /* Resume command */ -#define EMMC_SD_SRS03_CMD_ABORT (0x3U << 22) /* Abort command (CMD12, CMD52) */ -#define EMMC_SD_SRS03_DPS (1U << 21) /* 21: RW - Data Present Select */ -#define EMMC_SD_SRS03_CICE (1U << 20) /* 20: RW - Command Index Check Enable */ -#define EMMC_SD_SRS03_CRCCE (1U << 19) /* 19: RW - Command CRC Check Enable */ -#define EMMC_SD_SRS03_RTS_SHIFT 16 /* Response Type Select */ -#define EMMC_SD_SRS03_RTS_MASK 0x3U -#define EMMC_SD_SRS03_RESP_NONE (0x0U << 16) /* No response */ -#define EMMC_SD_SRS03_RESP_136 (0x1U << 16) /* Response length 136 bits */ -#define EMMC_SD_SRS03_RESP_48 (0x2U << 16) /* Response length 48 bits */ -#define EMMC_SD_SRS03_RESP_48B (0x3U << 16) /* Response length 48 bits + busy */ -#define EMMC_SD_SRS03_RID (1U << 8) /* 8: RW - Response Interrupt Disable */ -#define EMMC_SD_SRS03_RECE (1U << 7) /* 7: RW - Response Error Check Enable */ -#define EMMC_SD_SRS03_RECT (1U << 6) /* 6: RW - Response Check Type (R1/R5) */ -#define EMMC_SD_SRS03_MSBS (1U << 5) /* 5: RW - Multi/Single Block Select */ -#define EMMC_SD_SRS03_DTDS (1U << 4) /* 4: RW - Data Transfer Direction (1=read) */ -#define EMMC_SD_SRS03_ACE_SHIFT 2 /* 3:2: RW - Auto CMD Enable */ -#define EMMC_SD_SRS03_ACE_MASK (0x3U << 2) -#define EMMC_SD_SRS03_ACMD_DISABLE (0x0U << 2) /* Auto CMD disabled */ -#define EMMC_SD_SRS03_ACMD12 (0x1U << 2) /* Auto CMD12 enable */ -#define EMMC_SD_SRS03_ACMD23 (0x2U << 2) /* Auto CMD23 enable */ -#define EMMC_SD_SRS03_BCE (1U << 1) /* 1: RW - Block Count Enable */ -#define EMMC_SD_SRS03_DMAE (1U << 0) /* 0: RW - DMA Enable */ - -#define EMMC_SD_SRS04 *((volatile uint32_t*)(EMMC_SD_BASE + 0x210)) /* Response Register 1 */ -#define EMMC_SD_SRS04_RESP1_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_SRS04_RESP1_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS05 *((volatile uint32_t*)(EMMC_SD_BASE + 0x214)) /* Response Register 2 */ -#define EMMC_SD_SRS05_RESP2_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_SRS05_RESP2_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS06 *((volatile uint32_t*)(EMMC_SD_BASE + 0x218)) /* Response Register 3 */ -#define EMMC_SD_SRS06_RESP3_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_SRS06_RESP3_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS07 *((volatile uint32_t*)(EMMC_SD_BASE + 0x21C)) /* Response Register 4 */ -#define EMMC_SD_SRS07_RESP4_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_SRS07_RESP4_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS08 *((volatile uint32_t*)(EMMC_SD_BASE + 0x220)) /* Data Buffer */ -#define EMMC_SD_SRS08_BDP_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_SRS08_BDP_MASK (0xFFFFFFFFU << 0) - -/* SRS09 - Present State Register */ -#define EMMC_SD_SRS09 *((volatile uint32_t*)(EMMC_SD_BASE + 0x224)) -#define EMMC_SD_SRS09_CMDSL (1U << 24) /* 24: RO - CMD Line Signal Level */ -#define EMMC_SD_SRS09_DATSL1_SHIFT 20 /* 23:20: RO - DAT[3:0] Line Signal Level */ -#define EMMC_SD_SRS09_DATSL1_MASK (0xFU << 20) -#define EMMC_SD_SRS09_DAT3_LVL (1U << 23) /* 23: RO - DAT3 signal level */ -#define EMMC_SD_SRS09_DAT2_LVL (1U << 22) /* 22: RO - DAT2 signal level */ -#define EMMC_SD_SRS09_DAT1_LVL (1U << 21) /* 21: RO - DAT1 signal level */ -#define EMMC_SD_SRS09_DAT0_LVL (1U << 20) /* 20: RO - DAT0 signal level */ -#define EMMC_SD_SRS09_DATS_LVL (EMMC_SD_SRS09_DAT0_LVL | EMMC_SD_SRS09_DAT1_LVL | EMMC_SD_SRS09_DAT2_LVL | EMMC_SD_SRS09_DAT3_LVL) -#define EMMC_SD_SRS09_WPSL (1U << 19) /* 19: RO - Write Protect Switch Level */ -#define EMMC_SD_SRS09_CDSL (1U << 18) /* 18: RO - Card Detect Pin Level */ -#define EMMC_SD_SRS09_CSS (1U << 17) /* 17: RO - Card State Stable */ -#define EMMC_SD_SRS09_CI (1U << 16) /* 16: RO - Card Inserted */ -#define EMMC_SD_SRS09_BRE (1U << 11) /* 11: RO - Buffer Read Enable */ -#define EMMC_SD_SRS09_BWE (1U << 10) /* 10: RO - Buffer Write Enable */ -#define EMMC_SD_SRS09_RTA (1U << 9) /* 9: RO - Read Transfer Active */ -#define EMMC_SD_SRS09_WTA (1U << 8) /* 8: RO - Write Transfer Active */ -#define EMMC_SD_SRS09_DATSL2_SHIFT 4 /* 7:4: RO - DAT[7:4] Line Signal Level */ -#define EMMC_SD_SRS09_DATSL2_MASK (0xFU << 4) -#define EMMC_SD_SRS09_DLA (1U << 2) /* 2: RO - DAT Line Active */ -#define EMMC_SD_SRS09_CIDAT (1U << 1) /* 1: RO - Command Inhibit (DAT) */ -#define EMMC_SD_SRS09_CICMD (1U << 0) /* 0: RO - Command Inhibit (CMD) */ - -/* SRS10 - Host Control 1 Register (Power/Block-Gap/Wake-Up) */ -#define EMMC_SD_SRS10 *((volatile uint32_t*)(EMMC_SD_BASE + 0x228)) -#define EMMC_SD_SRS10_WORM (1U << 26) /* 26: RW - Wakeup on Card Removal */ -#define EMMC_SD_SRS10_WOIS (1U << 25) /* 25: RW - Wakeup on Card Insertion */ -#define EMMC_SD_SRS10_WOIQ (1U << 24) /* 24: RW - Wakeup on Card Interrupt */ -#define EMMC_SD_SRS10_IBG (1U << 19) /* 19: RW - Interrupt at Block Gap */ -#define EMMC_SD_SRS10_RWC (1U << 18) /* 18: RW - Read Wait Control */ -#define EMMC_SD_SRS10_CREQ (1U << 17) /* 17: RW - Continue Request */ -#define EMMC_SD_SRS10_SBGR (1U << 16) /* 16: RW - Stop at Block Gap Request */ -#define EMMC_SD_SRS10_BVS2_SHIFT 13 /* 15:13: RW - SD Bus Voltage Select (VDD2) */ -#define EMMC_SD_SRS10_BVS2_MASK (0x7U << 13) -#define EMMC_SD_SRS10_BP2 (1U << 12) /* 12: RW - Bus Power (VDD2) */ -#define EMMC_SD_SRS10_BVS_SHIFT 9 /* 11:9: RW - SD Bus Voltage Select */ -#define EMMC_SD_SRS10_BVS_MASK (0x7U << 9) -#define EMMC_SD_SRS10_BVS_3_3V (0x7U << 9) /* SD bus voltage 3.3V */ -#define EMMC_SD_SRS10_BVS_3_0V (0x6U << 9) /* SD bus voltage 3.0V */ -#define EMMC_SD_SRS10_BVS_1_8V (0x5U << 9) /* SD bus voltage 1.8V */ -#define EMMC_SD_SRS10_BVS_CLR (0x7U << 9) /* Clear voltage field mask */ -#define EMMC_SD_SRS10_BP (1U << 8) /* 8: RW - SD Bus Power */ -/* Power-on sequences: combine voltage selection with bus power enable */ -#define EMMC_SD_SRS10_PWR_3_3V (EMMC_SD_SRS10_BVS_3_3V | EMMC_SD_SRS10_BP) -#define EMMC_SD_SRS10_PWR_3_0V (EMMC_SD_SRS10_BVS_3_0V | EMMC_SD_SRS10_BP) -#define EMMC_SD_SRS10_PWR_1_8V (EMMC_SD_SRS10_BVS_1_8V | EMMC_SD_SRS10_BP) -#define EMMC_SD_SRS10_CDSS (1U << 7) /* 7: RW - Card Detect Signal Selection */ -#define EMMC_SD_SRS10_CDTL (1U << 6) /* 6: RW - Card Detect Test Level */ -#define EMMC_SD_SRS10_EDTW (1U << 5) /* 5: RW - Extended Data Transfer Width (8-bit) */ -#define EMMC_SD_SRS10_DMASEL_SHIFT 3 /* 4:3: RW - DMA Select */ -#define EMMC_SD_SRS10_DMASEL_MASK (0x3U << 3) -#define EMMC_SD_SRS10_DMA_SDMA (0x0U << 3) /* SDMA mode */ -#define EMMC_SD_SRS10_DMA_ADMA1 (0x1U << 3) /* ADMA1 mode */ -#define EMMC_SD_SRS10_DMA_ADMA2 (0x2U << 3) /* ADMA2 mode */ -#define EMMC_SD_SRS10_HSE (1U << 2) /* 2: RW - High Speed Enable */ -#define EMMC_SD_SRS10_DTW (1U << 1) /* 1: RW - Data Transfer Width (1=4-bit) */ -#define EMMC_SD_SRS10_LEDC (1U << 0) /* 0: RW - LED Control */ - -/* SRS11 - Host Control 2 Register (Clock/Timeout/Reset) */ -#define EMMC_SD_SRS11 *((volatile uint32_t*)(EMMC_SD_BASE + 0x22C)) -#define EMMC_SD_SRS11_SRDA (1U << 26) /* 26: RW - Software Reset for DAT Line */ -#define EMMC_SD_SRS11_SRCD (1U << 25) /* 25: RW - Software Reset for CMD Line */ -#define EMMC_SD_SRS11_SRFA (1U << 24) /* 24: RW - Software Reset for All */ -#define EMMC_SD_SRS11_RESET_DAT_CMD (EMMC_SD_SRS11_SRDA | EMMC_SD_SRS11_SRCD) /* Reset DAT+CMD lines */ -#define EMMC_SD_SRS11_DTCV_SHIFT 16 /* 19:16: RW - Data Timeout Counter Value */ -#define EMMC_SD_SRS11_DTCV_MASK (0xFU << 16) -#define EMMC_SD_SRS11_SDCFSL_SHIFT 8 /* 15:8: RW - SDCLK Freq Select (lower 8 bits) */ -#define EMMC_SD_SRS11_SDCFSL_MASK (0xFFU << 8) -#define EMMC_SD_SRS11_SDCFSH_SHIFT 6 /* 7:6: RW - SDCLK Freq Select (upper 2 bits) */ -#define EMMC_SD_SRS11_SDCFSH_MASK (0x3U << 6) -#define EMMC_SD_SRS11_CGS (1U << 5) /* 5: RW - Clock Generator Select */ -#define EMMC_SD_SRS11_SDCE (1U << 2) /* 2: RW - SD Clock Enable */ -#define EMMC_SD_SRS11_ICS (1U << 1) /* 1: RO - Internal Clock Stable */ -#define EMMC_SD_SRS11_ICE (1U << 0) /* 0: RW - Internal Clock Enable */ - -/* SRS12 - Error/Normal Interrupt Status Register */ -#define EMMC_SD_SRS12 *((volatile uint32_t*)(EMMC_SD_BASE + 0x230)) -#define EMMC_SD_SRS12_ERSP (1U << 27) /* 27: RO - Response Error */ -#define EMMC_SD_SRS12_ETUNE (1U << 26) /* 26: RO - Tuning Error */ -#define EMMC_SD_SRS12_EADMA (1U << 25) /* 25: RO - ADMA Error */ -#define EMMC_SD_SRS12_EAC (1U << 24) /* 24: RO - Auto CMD Error */ -#define EMMC_SD_SRS12_ECL (1U << 23) /* 23: RO - Current Limit Error */ -#define EMMC_SD_SRS12_EDEB (1U << 22) /* 22: RO - Data End Bit Error */ -#define EMMC_SD_SRS12_EDCRC (1U << 21) /* 21: RO - Data CRC Error */ -#define EMMC_SD_SRS12_EDT (1U << 20) /* 20: RO - Data Timeout Error */ -#define EMMC_SD_SRS12_ECI (1U << 19) /* 19: RO - Command Index Error */ -#define EMMC_SD_SRS12_ECEB (1U << 18) /* 18: RO - Command End Bit Error */ -#define EMMC_SD_SRS12_ECCRC (1U << 17) /* 17: RO - Command CRC Error */ -#define EMMC_SD_SRS12_ECT (1U << 16) /* 16: RO - Command Timeout Error */ -#define EMMC_SD_SRS12_EINT (1U << 15) /* 15: RO - Error Interrupt */ -#define EMMC_SD_SRS12_CQI (1U << 14) /* 14: RO - Command Queuing Interrupt */ -#define EMMC_SD_SRS12_CINT (1U << 8) /* 8: RO - Card Interrupt */ -#define EMMC_SD_SRS12_CR (1U << 7) /* 7: RW - Card Removal */ -#define EMMC_SD_SRS12_CIN (1U << 6) /* 6: RW - Card Insertion */ -#define EMMC_SD_SRS12_BRR (1U << 5) /* 5: RO - Buffer Read Ready */ -#define EMMC_SD_SRS12_BWR (1U << 4) /* 4: RO - Buffer Write Ready */ -#define EMMC_SD_SRS12_DMAINT (1U << 3) /* 3: RW - DMA Interrupt */ -#define EMMC_SD_SRS12_BGE (1U << 2) /* 2: RW - Block Gap Event */ -#define EMMC_SD_SRS12_TC (1U << 1) /* 1: RW - Transfer Complete */ -#define EMMC_SD_SRS12_CC (1U << 0) /* 0: RW - Command Complete */ -/* Interrupt status masks */ -#define EMMC_SD_SRS12_NORM_STAT 0x00007FFFU /* Normal interrupt status mask */ -#define EMMC_SD_SRS12_ERR_STAT 0xFFFF8000U /* Error interrupt status mask */ -#define EMMC_SD_SRS12_CMD_ERR (EMMC_SD_SRS12_ECT | EMMC_SD_SRS12_ECCRC | \ - EMMC_SD_SRS12_ECEB | EMMC_SD_SRS12_ECI) - -#define EMMC_SD_SRS13 *((volatile uint32_t*)(EMMC_SD_BASE + 0x234)) /* Error/Normal Status Enable */ -#define EMMC_SD_SRS13_ERSP_SE (1U << 27) /* 27: RW - Response Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ETUNE_SE (1U << 26) /* 26: RW - Tuning Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_EADMA_SE (1U << 25) /* 25: RW - ADMA Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_EAC_SE (1U << 24) /* 24: RW - Auto CMD Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ECL_SE (1U << 23) /* 23: RW - Current Limit Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_EDEB_SE (1U << 22) /* 22: RW - Data End Bit Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_EDCRC_SE (1U << 21) /* 21: RW - Data CRC Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_EDT_SE (1U << 20) /* 20: RW - Data Timeout Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ECI_SE (1U << 19) /* 19: RW - Command Index Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ECEB_SE (1U << 18) /* 18: RW - Command End Bit Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ECCRC_SE (1U << 17) /* 17: RW - Command CRC Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_ECT_SE (1U << 16) /* 16: RW - Command Timeout Error Status Enable (SD mode only) */ -#define EMMC_SD_SRS13_CQINT_SE (1U << 14) /* 14: RW - Command Queuing Status Enable */ -#define EMMC_SD_SRS13_RTUNE_SE (1U << 12) /* 12: RW - Retuning event status enable */ -#define EMMC_SD_SRS13_INT_ONC (1U << 11) /* 11: RW - Interrupt On Line C status enable */ -#define EMMC_SD_SRS13_INT_ONB (1U << 10) /* 10: RW - Interrupt On Line B status enable */ -#define EMMC_SD_SRS13_INT_ONA (1U << 9) /* 9: RW - Interrupt On Line A status enable */ -#define EMMC_SD_SRS13_CINT_SE (1U << 8) /* 8: RW - Card Interrupt Status Enable */ -#define EMMC_SD_SRS13_CR_SE (1U << 7) /* 7: RW - Card Removal Status Enable */ -#define EMMC_SD_SRS13_CIN_SE (1U << 6) /* 6: RW - Card Insertion Status Enable */ -#define EMMC_SD_SRS13_BRR_SE (1U << 5) /* 5: RW - Buffer Read Ready Status Enable */ -#define EMMC_SD_SRS13_BWR_SE (1U << 4) /* 4: RW - Buffer Write Ready Status Enable */ -#define EMMC_SD_SRS13_DMAINT_SE (1U << 3) /* 3: RW - DMA Interrupt Status Enable */ -#define EMMC_SD_SRS13_BGE_SE (1U << 2) /* 2: RW - Block Gap Event Status Enable */ -#define EMMC_SD_SRS13_TC_SE (1U << 1) /* 1: RW - Transfer Complete Status Enable */ -#define EMMC_SD_SRS13_CC_SE (1U << 0) /* 0: RW - Command Complete Status Enable */ - -#define EMMC_SD_SRS14 *((volatile uint32_t*)(EMMC_SD_BASE + 0x238)) /* Error/Normal Signal Enable */ -#define EMMC_SD_SRS14_ERSP_IE (1U << 27) /* 27: RW - Response Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_EADMA_IE (1U << 25) /* 25: RW - ADMA Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_EAC_IE (1U << 24) /* 24: RW - Auto CMD Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_ECL_IE (1U << 23) /* 23: RW - Current Limit Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_EDEB_IE (1U << 22) /* 22: RW - Data End Bit Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_EDCRC_IE (1U << 21) /* 21: RW - Data CRC Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_EDT_IE (1U << 20) /* 20: RW - Data Timeout Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_ECI_IE (1U << 19) /* 19: RW - Command Index Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_ECEB_IE (1U << 18) /* 18: RW - Command End Bit Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_ECCRC_IE (1U << 17) /* 17: RW - Command CRC Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_ECT_IE (1U << 16) /* 16: RW - Command Timeout Error Interrupt Enable (SD mode only) */ -#define EMMC_SD_SRS14_CQINT_IE (1U << 14) /* 14: RW - Command Queuing Interrupt Enable */ -#define EMMC_SD_SRS14_CINT_IE (1U << 8) /* 8: RW - Card Interrupt Interrupt Enable */ -#define EMMC_SD_SRS14_CR_IE (1U << 7) /* 7: RW - Card Removal Interrupt Enable */ -#define EMMC_SD_SRS14_CIN_IE (1U << 6) /* 6: RW - Card Insertion Interrupt Enable */ -#define EMMC_SD_SRS14_BRR_IE (1U << 5) /* 5: RW - Buffer Read Ready Interrupt Enable */ -#define EMMC_SD_SRS14_BWR_IE (1U << 4) /* 4: RW - Buffer Write Ready Interrupt Enable */ -#define EMMC_SD_SRS14_DMAINT_IE (1U << 3) /* 3: RW - DMA Interrupt Interrupt Enable */ -#define EMMC_SD_SRS14_BGE_IE (1U << 2) /* 2: RW - Block Gap Event Interrupt Enable */ -#define EMMC_SD_SRS14_TC_IE (1U << 1) /* 1: RW - Transfer Complete Interrupt Enable */ -#define EMMC_SD_SRS14_CC_IE (1U << 0) /* 0: RW - Command Complete Interrupt Enable */ - -/* SRS15 - Host Control #2 / Auto CMD Error Status Register */ -#define EMMC_SD_SRS15 *((volatile uint32_t*)(EMMC_SD_BASE + 0x23C)) -#define EMMC_SD_SRS15_PVE (1U << 31) /* 31: RW - Preset Value Enable */ -#define EMMC_SD_SRS15_AIE (1U << 30) /* 30: RW - Async Interrupt Enable */ -#define EMMC_SD_SRS15_A64 (1U << 29) /* 29: RW - 64-bit Addressing */ -#define EMMC_SD_SRS15_HV4E (1U << 28) /* 28: RW - Host Version 4 Enable */ -#define EMMC_SD_SRS15_UHSII (1U << 24) /* 24: RW - UHS-II Interface Enable */ -#define EMMC_SD_SRS15_SCS (1U << 23) /* 23: RW - Sampling Clock Select */ -#define EMMC_SD_SRS15_EXTNG (1U << 22) /* 22: RW - Execute Tuning */ -#define EMMC_SD_SRS15_DSS_SHIFT 20 /* 21:20: RW - Driver Strength Select */ -#define EMMC_SD_SRS15_DSS_MASK (0x3U << 20) -#define EMMC_SD_SRS15_DSS_TYPE_B (0x0U << 20) /* Driver Type B (default) */ -#define EMMC_SD_SRS15_DSS_TYPE_A (0x1U << 20) /* Driver Type A */ -#define EMMC_SD_SRS15_DSS_TYPE_C (0x2U << 20) /* Driver Type C */ -#define EMMC_SD_SRS15_DSS_TYPE_D (0x3U << 20) /* Driver Type D */ -#define EMMC_SD_SRS15_V18SE (1U << 19) /* 19: RW - 1.8V Signaling Enable */ -#define EMMC_SD_SRS15_UMS_SHIFT 16 /* 18:16: RW - UHS Mode Select */ -#define EMMC_SD_SRS15_UMS_MASK (0x7U << 16) -#define EMMC_SD_SRS15_UMS_SDR12 (0x0U << 16) /* SDR12 mode */ -#define EMMC_SD_SRS15_UMS_SDR25 (0x1U << 16) /* SDR25 mode (High Speed) */ -#define EMMC_SD_SRS15_UMS_SDR50 (0x2U << 16) /* SDR50 mode */ -#define EMMC_SD_SRS15_UMS_SDR104 (0x3U << 16) /* SDR104 mode */ -#define EMMC_SD_SRS15_UMS_DDR50 (0x4U << 16) /* DDR50 mode */ -#define EMMC_SD_SRS15_UMS_UHSII (0x7U << 16) /* UHS-II mode */ -/* Auto CMD Error Status bits (lower byte) */ -#define EMMC_SD_SRS15_CNIACE (1U << 7) /* 7: RO - CMD Not Issued by Auto CMD12 */ -#define EMMC_SD_SRS15_ACIE (1U << 4) /* 4: RO - Auto CMD12 Index Error */ -#define EMMC_SD_SRS15_ACEBE (1U << 3) /* 3: RO - Auto CMD12 End Bit Error */ -#define EMMC_SD_SRS15_ACCE (1U << 2) /* 2: RO - Auto CMD12 CRC Error */ -#define EMMC_SD_SRS15_ACTE (1U << 1) /* 1: RO - Auto CMD12 Timeout Error */ -#define EMMC_SD_SRS15_ACNE (1U << 0) /* 0: RO - Auto CMD12 Not Executed */ - -/* SRS16 - Capabilities Register #1 */ -#define EMMC_SD_SRS16 *((volatile uint32_t*)(EMMC_SD_BASE + 0x240)) -#define EMMC_SD_SRS16_SLT_SHIFT 30 /* 31:30: RO - Slot Type */ -#define EMMC_SD_SRS16_SLT_MASK (0x3U << 30) -#define EMMC_SD_SRS16_AIS (1U << 29) /* 29: RO - Async Interrupt Support */ -#define EMMC_SD_SRS16_A64S (1U << 28) /* 28: RO - 64-bit System Bus Support */ -#define EMMC_SD_SRS16_VS18 (1U << 26) /* 26: RO - Voltage Support 1.8V */ -#define EMMC_SD_SRS16_VS30 (1U << 25) /* 25: RO - Voltage Support 3.0V */ -#define EMMC_SD_SRS16_VS33 (1U << 24) /* 24: RO - Voltage Support 3.3V */ -#define EMMC_SD_SRS16_SRS (1U << 23) /* 23: RO - Suspend/Resume Support */ -#define EMMC_SD_SRS16_DMAS (1U << 22) /* 22: RO - SDMA Support */ -#define EMMC_SD_SRS16_HSS (1U << 21) /* 21: RO - High Speed Support */ -#define EMMC_SD_SRS16_ADMA1S (1U << 20) /* 20: RO - ADMA1 Support */ -#define EMMC_SD_SRS16_ADMA2S (1U << 19) /* 19: RO - ADMA2 Support */ -#define EMMC_SD_SRS16_EDS8 (1U << 18) /* 18: RO - 8-bit Data Support */ -#define EMMC_SD_SRS16_MBL_SHIFT 16 /* 17:16: RO - Max Block Length */ -#define EMMC_SD_SRS16_MBL_MASK (0x3U << 16) -#define EMMC_SD_SRS16_MBL_512 (0x0U << 16) /* Max 512 bytes */ -#define EMMC_SD_SRS16_MBL_1024 (0x1U << 16) /* Max 1024 bytes */ -#define EMMC_SD_SRS16_MBL_2048 (0x2U << 16) /* Max 2048 bytes */ -#define EMMC_SD_SRS16_BCSDCLK_SHIFT 8 /* 15:8: RO - Base Clock for SD Clock (in MHz) */ -#define EMMC_SD_SRS16_BCSDCLK_MASK (0xFFU << 8) -#define EMMC_SD_SRS16_TCU (1U << 7) /* 7: RO - Timeout Clock Unit (1=MHz) */ -#define EMMC_SD_SRS16_TCF_SHIFT 0 /* 5:0: RO - Timeout Clock Frequency */ -#define EMMC_SD_SRS16_TCF_MASK (0x3FU << 0) - -/* SRS17 - Capabilities Register #2 */ -#define EMMC_SD_SRS17 *((volatile uint32_t*)(EMMC_SD_BASE + 0x244)) -#define EMMC_SD_SRS17_VDD2S (1U << 28) /* 28: RO - VDD2 Support */ -#define EMMC_SD_SRS17_CLKMPR_SHIFT 16 /* 23:16: RO - Clock Multiplier */ -#define EMMC_SD_SRS17_CLKMPR_MASK (0xFFU << 16) -#define EMMC_SD_SRS17_RTNGM_SHIFT 14 /* 15:14: RO - Re-Tuning Modes */ -#define EMMC_SD_SRS17_RTNGM_MASK (0x3U << 14) -#define EMMC_SD_SRS17_RTNGM_MODE1 (0x0U << 14) /* Re-tuning mode 1 */ -#define EMMC_SD_SRS17_RTNGM_MODE2 (0x1U << 14) /* Re-tuning mode 2 */ -#define EMMC_SD_SRS17_RTNGM_MODE3 (0x2U << 14) /* Re-tuning mode 3 */ -#define EMMC_SD_SRS17_TSDR50 (1U << 13) /* 13: RO - Tuning for SDR50 */ -#define EMMC_SD_SRS17_TCRT_SHIFT 8 /* 11:8: RO - Timer Count for Re-Tuning */ -#define EMMC_SD_SRS17_TCRT_MASK (0xFU << 8) -#define EMMC_SD_SRS17_UHSII (1U << 8) /* 8: RO - UHS-II Support */ -#define EMMC_SD_SRS17_DRVD (1U << 6) /* 6: RO - Driver Type D Support */ -#define EMMC_SD_SRS17_DRVC (1U << 5) /* 5: RO - Driver Type C Support */ -#define EMMC_SD_SRS17_DRVA (1U << 4) /* 4: RO - Driver Type A Support */ -#define EMMC_SD_SRS17_DDR50 (1U << 2) /* 2: RO - DDR50 Support */ -#define EMMC_SD_SRS17_SDR104 (1U << 1) /* 1: RO - SDR104 Support */ -#define EMMC_SD_SRS17_SDR50 (1U << 0) /* 0: RO - SDR50 Support */ - -#define EMMC_SD_SRS18 *((volatile uint32_t*)(EMMC_SD_BASE + 0x248)) /* Capabilities #3 */ -#define EMMC_SD_SRS18_MC18_SHIFT 16 /* 23:16: RO - Maximym current for 1.8v */ -#define EMMC_SD_SRS18_MC18_MASK (0xFFU << 16) -#define EMMC_SD_SRS18_MC30_SHIFT 8 /* 15:8: RO - Maximym current for 3.0v */ -#define EMMC_SD_SRS18_MC30_MASK (0xFFU << 8) -#define EMMC_SD_SRS18_MC33_SHIFT 0 /* 7:0: RO - Maximym current for 3.3v */ -#define EMMC_SD_SRS18_MC33_MASK (0xFFU << 0) - -#define EMMC_SD_SRS19 *((volatile uint32_t*)(EMMC_SD_BASE + 0x24C)) /* Capabilities #4 */ -#define EMMC_SD_SRS19_MC18V2_SHIFT 0 /* 7:0: RO */ -#define EMMC_SD_SRS19_MC18V2_MASK (0xFFU << 0) - -#define EMMC_SD_SRS20 *((volatile uint32_t*)(EMMC_SD_BASE + 0x250)) /* Force Event */ -#define EMMC_SD_SRS20_ERESP_FE (1U << 27) /* 27: WO - Force Response Error */ -#define EMMC_SD_SRS20_ETUNE_FE (1U << 26) /* 26: WO - Force Tuning Error */ -#define EMMC_SD_SRS20_EADMA_FE (1U << 25) /* 25: WO - Force ADMA Error */ -#define EMMC_SD_SRS20_EAC_FE (1U << 24) /* 24: WO - Force Auto CMD Error */ -#define EMMC_SD_SRS20_ECL_FE (1U << 23) /* 23: WO - Force Current Limit Error */ -#define EMMC_SD_SRS20_EDEB_FE (1U << 22) /* 22: WO - Force Data End Bit Error */ -#define EMMC_SD_SRS20_EDCRC_FE (1U << 21) /* 21: WO - Force Data CRC Error */ -#define EMMC_SD_SRS20_EDT_FE (1U << 20) /* 20: WO - Force Data Timeout Error */ -#define EMMC_SD_SRS20_ECI_FE (1U << 19) /* 19: WO - Force Command Index Error */ -#define EMMC_SD_SRS20_ECEB_FE (1U << 18) /* 18: WO - Force Command End Bit Error */ -#define EMMC_SD_SRS20_ECCRC_FE (1U << 17) /* 17: WO - Force Command CRC Error */ -#define EMMC_SD_SRS20_ECT_FE (1U << 16) /* 16: WO - Force Command Timeout Error */ - -#define EMMC_SD_SRS21 *((volatile uint32_t*)(EMMC_SD_BASE + 0x254)) /* ADMA Error Status */ -#define EMMC_SD_SRS21_EADMAL (1U << 2) /* 2: RO - ADMA Length Mismatch Error */ -#define EMMC_SD_SRS21_EADMAS_SHIFT 0 /* 1:0: RO */ -#define EMMC_SD_SRS21_EADMAS_MASK (0x3U << 0) - -#define EMMC_SD_SRS22 *((volatile uint32_t*)(EMMC_SD_BASE + 0x258)) /* ADMA System Address 1 */ -#define EMMC_SD_SRS22_DMASA1_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_SRS22_DMASA1_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS23 *((volatile uint32_t*)(EMMC_SD_BASE + 0x25C)) /* ADMA System Address 2 */ -#define EMMC_SD_SRS23_DMASA2_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_SRS23_DMASA2_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_SRS24 *((volatile uint32_t*)(EMMC_SD_BASE + 0x260)) /* Preset Value (Default Speed) */ -#define EMMC_SD_SRS25 *((volatile uint32_t*)(EMMC_SD_BASE + 0x264)) /* Preset Value (High Speed/SDR12) */ -#define EMMC_SD_SRS26 *((volatile uint32_t*)(EMMC_SD_BASE + 0x268)) /* Preset Value (SDR25/SDR50) */ -#define EMMC_SD_SRS27 *((volatile uint32_t*)(EMMC_SD_BASE + 0x26C)) /* Preset Value (SDR104/DDR50) */ -#define EMMC_SD_SRS29 *((volatile uint32_t*)(EMMC_SD_BASE + 0x274)) /* Preset Value for UHS-II */ - -/* ---------------------------------------------------------------------------- - * CQRS - Command Queuing Register Set (eMMC 5.1 Command Queuing) - * ---------------------------------------------------------------------------- */ - -/* CQRS00 - Command Queuing Version Register */ -#define EMMC_SD_CQRS00 *((volatile uint32_t*)(EMMC_SD_BASE + 0x400)) -#define EMMC_SD_CQRS00_CQVN1_SHIFT 8 /* 11:8: RO - CQ Version (major) */ -#define EMMC_SD_CQRS00_CQVN1_MASK (0xFU << 8) -#define EMMC_SD_CQRS00_CQVN2_SHIFT 4 /* 7:4: RO - CQ Version (minor) */ -#define EMMC_SD_CQRS00_CQVN2_MASK (0xFU << 4) -#define EMMC_SD_CQRS00_CQVN3_SHIFT 0 /* 3:0: RO - CQ Version (suffix) */ -#define EMMC_SD_CQRS00_CQVN3_MASK (0xFU << 0) - -/* CQRS01 - Command Queuing Capabilities Register */ -#define EMMC_SD_CQRS01 *((volatile uint32_t*)(EMMC_SD_BASE + 0x404)) -#define EMMC_SD_CQRS01_ITCFMUL_SHIFT 12 /* 15:12: RO - Internal Timer Clock Freq Multiplier */ -#define EMMC_SD_CQRS01_ITCFMUL_MASK (0xFU << 12) -#define EMMC_SD_CQRS01_ITCFVAL_SHIFT 0 /* 9:0: RO - Internal Timer Clock Freq Value */ -#define EMMC_SD_CQRS01_ITCFVAL_MASK (0x3FFU << 0) - -/* CQRS02 - Command Queuing Configuration Register */ -#define EMMC_SD_CQRS02 *((volatile uint32_t*)(EMMC_SD_BASE + 0x408)) -#define EMMC_SD_CQRS02_CQDCE (1U << 12) /* 12: RW - Direct Command (DCMD) Enable */ -#define EMMC_SD_CQRS02_CQTDS (1U << 8) /* 8: RW - Task Desc Size (0=64bit, 1=128bit) */ -#define EMMC_SD_CQRS02_CQTDS_64 (0x0U << 8) /* Task descriptor 64 bits */ -#define EMMC_SD_CQRS02_CQTDS_128 (0x1U << 8) /* Task descriptor 128 bits */ -#define EMMC_SD_CQRS02_CQE (1U << 0) /* 0: RW - Command Queuing Enable */ - -/* CQRS03 - Command Queuing Control Register */ -#define EMMC_SD_CQRS03 *((volatile uint32_t*)(EMMC_SD_BASE + 0x40C)) -#define EMMC_SD_CQRS03_CQHLT (1U << 0) /* 0: RW - Halt CQ Engine */ - -/* CQRS04 - Command Queuing Interrupt Status Register */ -#define EMMC_SD_CQRS04 *((volatile uint32_t*)(EMMC_SD_BASE + 0x410)) -#define EMMC_SD_CQRS04_CQTCL (1U << 3) /* 3: RW - Task Cleared Interrupt */ -#define EMMC_SD_CQRS04_CQRED (1U << 2) /* 2: RW - Response Error Detected */ -#define EMMC_SD_CQRS04_CQTCC (1U << 1) /* 1: RW - Task Complete Interrupt */ -#define EMMC_SD_CQRS04_CQHAC (1U << 0) /* 0: RW - Halt Complete Interrupt */ - -/* CQRS05 - Command Queuing Interrupt Status Enable Register */ -#define EMMC_SD_CQRS05 *((volatile uint32_t*)(EMMC_SD_BASE + 0x414)) -#define EMMC_SD_CQRS05_CQTCLST (1U << 3) /* 3: RW - Task Cleared Status Enable */ -#define EMMC_SD_CQRS05_CQREDST (1U << 2) /* 2: RW - Response Error Status Enable */ -#define EMMC_SD_CQRS05_CQTCCST (1U << 1) /* 1: RW - Task Complete Status Enable */ -#define EMMC_SD_CQRS05_CQHACST (1U << 0) /* 0: RW - Halt Complete Status Enable */ - -/* CQRS06 - Command Queuing Interrupt Signal Enable Register */ -#define EMMC_SD_CQRS06 *((volatile uint32_t*)(EMMC_SD_BASE + 0x418)) -#define EMMC_SD_CQRS06_CQTCLSI (1U << 3) /* 3: RW - Task Cleared Signal Enable */ -#define EMMC_SD_CQRS06_CQREDSI (1U << 2) /* 2: RW - Response Error Signal Enable */ -#define EMMC_SD_CQRS06_CQTCCSI (1U << 1) /* 1: RW - Task Complete Signal Enable */ -#define EMMC_SD_CQRS06_CQHACSI (1U << 0) /* 0: RW - Halt Complete Signal Enable */ - -/* CQRS07 - Interrupt Coalescing Register */ -#define EMMC_SD_CQRS07 *((volatile uint32_t*)(EMMC_SD_BASE + 0x41C)) -#define EMMC_SD_CQRS07_CQICED (1U << 31) /* 31: RW - Int Coalescing Enable/Disable */ -#define EMMC_SD_CQRS07_CQICSB (1U << 20) /* 20: RO - Int Coalescing Status Bit */ -#define EMMC_SD_CQRS07_CQICCTR (1U << 16) /* 16: WO - Counter and Timer Reset */ -#define EMMC_SD_CQRS07_CQICCTHWEN (1U << 15) /* 15: WO - Counter Threshold Write Enable */ -#define EMMC_SD_CQRS07_CQICCTH_SHIFT 8 /* 12:8: RW - Int Coalescing Counter Threshold */ -#define EMMC_SD_CQRS07_CQICCTH_MASK (0x1FU << 8) -#define EMMC_SD_CQRS07_CQICTOVALEN (1U << 7) /* 7: WO - Timeout Value Write Enable */ -#define EMMC_SD_CQRS07_CQICTOVAL_SHIFT 0 /* 6:0: RW - Int Coalescing Timeout Value */ -#define EMMC_SD_CQRS07_CQICTOVAL_MASK (0x7FU << 0) - -#define EMMC_SD_CQRS08 *((volatile uint32_t*)(EMMC_SD_BASE + 0x420)) /* Task Descriptor List Base Address */ -#define EMMC_SD_CQRS08_CQTDLBA_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_CQRS08_CQTDLBA_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_CQRS09 *((volatile uint32_t*)(EMMC_SD_BASE + 0x424)) /* Task Descriptor List Base Address Upper */ -#define EMMC_SD_CQRS09_CQTDLBAU_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_CQRS09_CQTDLBAU_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_CQRS10 *((volatile uint32_t*)(EMMC_SD_BASE + 0x428)) /* Command Queuing Task Doorbell */ -#define EMMC_SD_CQRS11 *((volatile uint32_t*)(EMMC_SD_BASE + 0x42C)) /* Task Complete Notification */ -#define EMMC_SD_CQRS12 *((volatile uint32_t*)(EMMC_SD_BASE + 0x430)) /* Device Queue Status */ -#define EMMC_SD_CQRS12_CQDQS_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_CQRS12_CQDQS_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_CQRS13 *((volatile uint32_t*)(EMMC_SD_BASE + 0x434)) /* Device Pending Tasks */ -#define EMMC_SD_CQRS14 *((volatile uint32_t*)(EMMC_SD_BASE + 0x438)) /* Task Clear */ - -#define EMMC_SD_CQRS16 *((volatile uint32_t*)(EMMC_SD_BASE + 0x440)) /* Send Status Configuration 1 */ -#define EMMC_SD_CQRS16_CQSSCBC_SHIFT 16 /* 19:16: RW */ -#define EMMC_SD_CQRS16_CQSSCBC_MASK (0xFU << 16) -#define EMMC_SD_CQRS16_CQSSCIT_SHIFT 0 /* 15:0: RW */ -#define EMMC_SD_CQRS16_CQSSCIT_MASK (0xFFFFU << 0) - -#define EMMC_SD_CQRS17 *((volatile uint32_t*)(EMMC_SD_BASE + 0x444)) /* Send Status Configuration 2 */ -#define EMMC_SD_CQRS17_CQSQSR_SHIFT 0 /* 15:0: RW */ -#define EMMC_SD_CQRS17_CQSQSR_MASK (0xFFFFU << 0) - -#define EMMC_SD_CQRS18 *((volatile uint32_t*)(EMMC_SD_BASE + 0x448)) /* Command Response for Direct-Command */ -#define EMMC_SD_CQRS18_CQDCLR_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_CQRS18_CQDCLR_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_CQRS20 *((volatile uint32_t*)(EMMC_SD_BASE + 0x450)) /* Response Mode Error Mask */ -#define EMMC_SD_CQRS20_CQRMEM_SHIFT 0 /* 31:0: RW */ -#define EMMC_SD_CQRS20_CQRMEM_MASK (0xFFFFFFFFU << 0) - -#define EMMC_SD_CQRS21 *((volatile uint32_t*)(EMMC_SD_BASE + 0x454)) /* Task Error Information */ -#define EMMC_SD_CQRS21_CQDTEFV (1U << 31) /* 31: RO */ -#define EMMC_SD_CQRS21_CQDTETID_SHIFT 24 /* 28:24: RO */ -#define EMMC_SD_CQRS21_CQDTETID_MASK (0x1FU << 24) -#define EMMC_SD_CQRS21_CQDTECI_SHIFT 16 /* 21:16: RO */ -#define EMMC_SD_CQRS21_CQDTECI_MASK (0x3FU << 16) -#define EMMC_SD_CQRS21_CQRMEFV (1U << 15) /* 15: RO */ -#define EMMC_SD_CQRS21_CQRMETID_SHIFT 8 /* 12:8: RO */ -#define EMMC_SD_CQRS21_CQRMETID_MASK (0x1FU << 8) -#define EMMC_SD_CQRS21_CQRMECI_SHIFT 0 /* 5:0: RO */ -#define EMMC_SD_CQRS21_CQRMECI_MASK (0x3FU << 0) - -#define EMMC_SD_CQRS22 *((volatile uint32_t*)(EMMC_SD_BASE + 0x458)) /* Command Response Index */ -#define EMMC_SD_CQRS22_CQLCRI_SHIFT 0 /* 5:0: RO */ -#define EMMC_SD_CQRS22_CQLCRI_MASK (0x3FU << 0) - -#define EMMC_SD_CQRS23 *((volatile uint32_t*)(EMMC_SD_BASE + 0x45C)) /* Command Response Argument */ -#define EMMC_SD_CQRS23_CQLCRA_SHIFT 0 /* 31:0: RO */ -#define EMMC_SD_CQRS23_CQLCRA_MASK (0xFFFFFFFFU << 0) - -/* ---------------------------------------------------------------------------- - * EMMC/SD - Common Constants and Helper Macros - * ---------------------------------------------------------------------------- */ - -/* Clock Frequencies (in KHz) */ -#define EMMC_SD_CLK_400KHZ 400U /* Initial identification clock */ -#define EMMC_SD_CLK_25MHZ 25000U /* Default Speed / SDR12 */ -#define EMMC_SD_CLK_50MHZ 50000U /* High Speed / SDR25 */ -#define EMMC_SD_CLK_100MHZ 100000U /* SDR50 */ -#define EMMC_SD_CLK_200MHZ 200000U /* SDR104 / HS200 / HS400 */ - -/* Block Size */ -#define EMMC_SD_BLOCK_SIZE 512U /* Standard block size */ - -/* SD Interface Conditions */ -#define IF_COND_27V_33V (1U << 8) - -/* SD OCR register bits definitions */ -#define SDCARD_REG_OCR_2_7_2_8 (1U << 15) -#define SDCARD_REG_OCR_2_8_2_9 (1U << 16) -#define SDCARD_REG_OCR_2_9_3_0 (1U << 17) -#define SDCARD_REG_OCR_3_0_3_1 (1U << 18) -#define SDCARD_REG_OCR_3_1_3_2 (1U << 19) -#define SDCARD_REG_OCR_3_2_3_3 (1U << 20) -#define SDCARD_REG_OCR_3_3_3_4 (1U << 21) -#define SDCARD_REG_OCR_3_4_3_5 (1U << 22) -#define SDCARD_REG_OCR_3_5_3_6 (1U << 23) -#define SDCARD_REG_OCR_S18RA (1U << 24) /* Switching to 1.8V request/accept bit */ -#define SDCARD_REG_OCR_XPC (1U << 28) /* eXtended Power Control (XPC) bit */ -#define SDCARD_REG_OCR_CCS (1U << 30) /* Card Capacity Status bit */ -#define SDCARD_REG_OCR_READY (1U << 31) /* OCR ready bit */ - -#define SDCARD_ACMD41_HCS (1U << 30) /* High Capacity Support bit */ - -/* Common MMC/SD Commands (for use with SRS03) */ -#define MMC_CMD0_GO_IDLE 0 /* Reset card to idle state */ -#define MMC_CMD1_SEND_OP_COND 1 /* MMC: Send operating conditions */ -#define MMC_CMD2_ALL_SEND_CID 2 /* Get card identification */ -#define MMC_CMD3_SET_REL_ADDR 3 /* Set relative address */ -#define MMC_CMD4_SET_DSR 4 -#define SD_CMD6_SWITCH_FUNC 6 /* SD: Switch function */ -#define MMC_CMD7_SELECT_CARD 7 /* Select/deselect card */ -#define MMC_CMD8_SEND_EXT_CSD 8 /* MMC: Get EXT_CSD */ -#define SD_CMD8_SEND_IF_COND 8 /* SD: Send interface condition */ -#define MMC_CMD9_SEND_CSD 9 /* Get card-specific data */ -#define SD_CMD11_VOLAGE_SWITCH 11 /* R1 Rsp */ -#define MMC_CMD12_STOP_TRANS 12 /* Stop transmission */ -#define MMC_CMD13_SEND_STATUS 13 /* Get card status */ -#define MMC_CMD15_GOTO_INACT_ST 15 -#define SD_CMD16 16 /* R1 Rsp */ -#define MMC_CMD17_READ_SINGLE 17 /* Read single block */ -#define MMC_CMD18_READ_MULTIPLE 18 /* Read multiple blocks */ -#define SD_CMD19_SEND_TUNING 19 /* SD: Send 64-byte tuning block */ -#define MMC_CMD24_WRITE_SINGLE 24 /* Write single block */ -#define MMC_CMD25_WRITE_MULTIPLE 25 /* Write multiple blocks */ - -#define SD_CMD55_APP_CMD 55 /* Prefix for ACMD */ -#define SD_ACMD6_SET_BUS_WIDTH 6 /* SD: Set bus width */ -#define SD_ACMD41_SEND_OP_COND 41 /* SD: Send operating conditions */ -#define SD_ACMD51_SEND_SCR 51 /* SD: Get SCR register */ - -/* Debouncing time for card detect */ -#define EMMC_SD_DEBOUNCE_TIME 0x300000U - -/* Timeout values */ -#define EMMC_SD_INIT_TIMEOUT_US (500U * 1000U) /* 500ms init timeout */ -#define EMMC_SD_DATA_TIMEOUT_US (3000U * 1000U) /* 3000ms data timeout */ - -/* Card type definitions */ -#define WOLFBOOT_CARDTYPE_SD 1 -#define WOLFBOOT_CARDTYPE_EMMC 2 - -/* Build-time card type selection - * Define USE_EMMC in your config to use eMMC instead of SD card (default) - * Example: CFLAGS_EXTRA += -DUSE_EMMC - */ -#ifdef USE_EMMC -#define WOLFBOOT_CARDTYPE WOLFBOOT_CARDTYPE_EMMC -#else -#define WOLFBOOT_CARDTYPE WOLFBOOT_CARDTYPE_SD -#endif - -#define MAX_CURRENT_MA 150 /* mA */ - -/* ---------------------------------------------------------------------------- - * eMMC-specific Constants (for CMD1 and CMD6 SWITCH) - * ---------------------------------------------------------------------------- */ - -/* CMD1 SEND_OP_COND argument values */ -#define MMC_DEVICE_3_3V_VOLT_SET 0x40300000U /* 3.3V, sector addressing mode */ -#define MMC_DEVICE_1_8V_VOLT_SET 0x40000080U /* 1.8V, sector addressing mode */ -#define MMC_OCR_BUSY_BIT 0x80000000U /* Device ready/busy bit */ -#define MMC_OCR_SECTOR_MODE 0x40000000U /* Sector addressing mode bit */ - -/* CMD6 SWITCH command - EXT_CSD access for bus width */ -#define MMC_CMD6_SWITCH 6 -#define MMC_DW_CSD 0x03B70000U /* Access byte 183 (BUS_WIDTH) in EXT_CSD */ -#define MMC_HS_TIMING 0x03B90000U /* Access byte 185 (HS_TIMING) in EXT_CSD */ - -/* eMMC data bus width values for CMD6 SWITCH (byte value << 8) */ -#define MMC_EXT_CSD_WIDTH_1BIT 0x00U -#define MMC_EXT_CSD_WIDTH_4BIT 0x01U -#define MMC_EXT_CSD_WIDTH_8BIT 0x02U -#define MMC_EXT_CSD_WIDTH_4BIT_DDR 0x05U -#define MMC_EXT_CSD_WIDTH_8BIT_DDR 0x06U - -/* eMMC HS_TIMING values */ -#define MMC_HS_TIMING_LEGACY 0x00U -#define MMC_HS_TIMING_HS 0x01U -#define MMC_HS_TIMING_HS200 0x02U -#define MMC_HS_TIMING_HS400 0x03U - -/* eMMC default RCA (host-assigned, typically 1) */ -#define MMC_EMMC_RCA_DEFAULT 0x0001U - -#define SD_RCA_SHIFT 16 /* relative card address */ -#define SD_RCA_MASK (0xFFFFU << SD_RCA_SHIFT) /* relative card address mask */ - -#define SCR_REG_DATA_SIZE 8 - -/* Switch Function Command Arguments */ -#define SDCARD_SWITCH_FUNC_MODE_SWITCH (0x1u << 31) /* Set function mode */ -#define SDCARD_SWITCH_FUNC_MODE_CHECK (0x0u << 31) /* Check mode */ -/* group 1 - function 1 */ -#define SDCARD_SWITCH_ACCESS_MODE_SDR12 0x0U /* Card access mode - SDR12 default */ -#define SDCARD_SWITCH_ACCESS_MODE_SDR25 0x1U /* Card access mode - SDR25 high speed */ -#define SDCARD_SWITCH_ACCESS_MODE_SDR50 0x2U /* Card access mode - SDR50 */ -#define SDCARD_SWITCH_ACCESS_MODE_SDR104 0x3U /* Card access mode - SDR104 */ -#define SDCARD_SWITCH_ACCESS_MODE_DDR50 0x4U /* Card access mode - DDR50 */ - -#define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_B 0x0U /* Card driver strength - Type B default */ -#define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_A 0x1U /* Card driver strength - Type A */ -#define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_C 0x2U /* Card driver strength - Type C */ -#define SDCARD_SWITCH_DRIVER_STRENGTH_TYPE_D 0x3U /* Card driver strength - Type D */ - /* Crypto Engine: Athena F5200 TeraFire Crypto Processor (1x), 200 MHz */ #define ATHENA_BASE (SYSREG_BASE + 0x125000) + /* ============================================================================ - * PLIC - Platform-Level Interrupt Controller (SiFive compatible) + * PLIC - Platform-Level Interrupt Controller (MPFS250-specific configuration) * Base Address: 0x0c000000, Size: 64MB + * + * Generic PLIC register access is provided by hal/riscv.h * ============================================================================ */ #define PLIC_BASE 0x0C000000UL #define PLIC_SIZE 0x04000000UL /* 64MB */ @@ -911,49 +158,6 @@ #define PLIC_INT_MMC_MAIN 88 /* MMC/SD controller main interrupt */ #define PLIC_INT_MMC_WAKEUP 89 /* MMC/SD controller wakeup interrupt */ -/* PLIC Register Layout: - * 0x000000: Reserved - * 0x000004: Priority for interrupt 1 - * ... - * 0x000FFC: Priority for interrupt 1023 - * 0x001000: Pending bits for interrupts 0-31 - * ... - * 0x002000: Enable bits for context 0, interrupts 0-31 - * ... - * 0x200000: Priority threshold for context 0 - * 0x200004: Claim/complete for context 0 - * 0x201000: Priority threshold for context 1 - * 0x201004: Claim/complete for context 1 - * ... - */ - -/* Priority registers: one 32-bit word per interrupt source */ -#define PLIC_PRIORITY_BASE (PLIC_BASE + 0x000000UL) -#define PLIC_PRIORITY(irq) (*((volatile uint32_t*)(PLIC_PRIORITY_BASE + ((irq) * 4)))) - -/* Pending bits: 32 interrupts per 32-bit word */ -#define PLIC_PENDING_BASE (PLIC_BASE + 0x001000UL) -#define PLIC_PENDING(irq) (*((volatile uint32_t*)(PLIC_PENDING_BASE + (((irq) / 32) * 4)))) -#define PLIC_PENDING_BIT(irq) (1U << ((irq) % 32)) - -/* Enable bits: 32 interrupts per 32-bit word, per context - * Each context has 0x80 bytes (32 words) for enable bits - */ -#define PLIC_ENABLE_BASE (PLIC_BASE + 0x002000UL) -#define PLIC_ENABLE_STRIDE 0x80UL -#define PLIC_ENABLE(ctx, irq) (*((volatile uint32_t*)(PLIC_ENABLE_BASE + \ - ((ctx) * PLIC_ENABLE_STRIDE) + (((irq) / 32) * 4)))) -#define PLIC_ENABLE_BIT(irq) (1U << ((irq) % 32)) - -/* Context registers: threshold and claim/complete, 0x1000 bytes per context */ -#define PLIC_CONTEXT_BASE (PLIC_BASE + 0x200000UL) -#define PLIC_CONTEXT_STRIDE 0x1000UL -#define PLIC_THRESHOLD(ctx) (*((volatile uint32_t*)(PLIC_CONTEXT_BASE + \ - ((ctx) * PLIC_CONTEXT_STRIDE) + 0x00))) -#define PLIC_CLAIM(ctx) (*((volatile uint32_t*)(PLIC_CONTEXT_BASE + \ - ((ctx) * PLIC_CONTEXT_STRIDE) + 0x04))) -#define PLIC_COMPLETE(ctx) PLIC_CLAIM(ctx) /* Same register for claim and complete */ - /* PLIC Context IDs for each hart * Hart 0 (E51): Context 0 = M-mode (no S-mode on E51) * Hart 1 (U54): Context 1 = M-mode, Context 2 = S-mode @@ -971,22 +175,6 @@ #define PLIC_CONTEXT_U54_4_M 7 #define PLIC_CONTEXT_U54_4_S 8 -/* Helper macro to get S-mode context for a given hart (1-4 for U54 cores) */ -#define PLIC_HART_TO_SMODE_CTX(hart) (((hart) * 2)) - -/* PLIC Priority levels (0 = disabled, 1-7 = priority, 7 = highest) */ -#define PLIC_PRIORITY_DISABLED 0 -#define PLIC_PRIORITY_MIN 1 -#define PLIC_PRIORITY_MAX 7 -#define PLIC_PRIORITY_DEFAULT 4 - -/* MMC Interrupt flags for handler state */ -#define MMC_IRQ_FLAG_NONE 0x00 -#define MMC_IRQ_FLAG_CC 0x01 /* Command Complete */ -#define MMC_IRQ_FLAG_TC 0x02 /* Transfer Complete */ -#define MMC_IRQ_FLAG_DMAINT 0x04 /* DMA Interrupt */ -#define MMC_IRQ_FLAG_ERROR 0x80 /* Error occurred */ - #endif /* MPFS250_DEF_INCLUDED */ diff --git a/hal/riscv.h b/hal/riscv.h index 04d4e07e0a..4195645ce5 100644 --- a/hal/riscv.h +++ b/hal/riscv.h @@ -160,5 +160,114 @@ #define MCAUSE32_INT 0x80000000UL #define MCAUSE32_CAUSE 0x7FFFFFFFUL +/* ============================================================================ + * PLIC - Platform-Level Interrupt Controller (Generic) + * Reference: RISC-V Platform-Level Interrupt Controller Specification v1.0 + * ============================================================================ + * + * The PLIC is the standard external interrupt controller for RISC-V systems. + * It aggregates external interrupt sources and presents them to harts. + * + * PLIC Memory Map (standard offsets from PLIC_BASE): + * 0x000000-0x000FFF: Priority registers (1 word per source, source 0 reserved) + * 0x001000-0x001FFF: Pending bits (1 bit per source, packed in 32-bit words) + * 0x002000-0x1FFFFF: Enable bits (per context, 1 bit per source, packed) + * 0x200000-0x3FFFFF: Context registers (threshold + claim/complete per context) + * + * Each hart typically has 2 contexts: M-mode and S-mode. + * + * Platform must define before using PLIC functions: + * PLIC_BASE - Base address of PLIC registers + * PLIC_NUM_SOURCES - Number of interrupt sources (optional, for bounds check) + * ============================================================================ */ + +/* PLIC Register Offsets (usable in both C and assembly) */ +#define PLIC_PRIORITY_OFFSET 0x000000UL +#define PLIC_PENDING_OFFSET 0x001000UL +#define PLIC_ENABLE_OFFSET 0x002000UL +#define PLIC_ENABLE_STRIDE 0x80UL +#define PLIC_CONTEXT_OFFSET 0x200000UL +#define PLIC_CONTEXT_STRIDE 0x1000UL + +/* PLIC Priority Levels (standard values) */ +#define PLIC_PRIORITY_DISABLED 0 /* Priority 0 = interrupt disabled */ +#define PLIC_PRIORITY_MIN 1 /* Minimum active priority */ +#define PLIC_PRIORITY_MAX 7 /* Maximum priority (7 levels typical) */ +#define PLIC_PRIORITY_DEFAULT 4 /* Default/medium priority */ + +/* ============================================================================ + * PLIC Register Access Macros (C code only) + * ============================================================================ */ +#ifndef __ASSEMBLER__ + +/* Priority registers: one 32-bit word per interrupt source (source 0 reserved) */ +#define PLIC_PRIORITY_REG(base, irq) \ + (*((volatile uint32_t*)((base) + PLIC_PRIORITY_OFFSET + ((irq) * 4)))) + +/* Pending bits: 32 interrupts per 32-bit word */ +#define PLIC_PENDING_REG(base, irq) \ + (*((volatile uint32_t*)((base) + PLIC_PENDING_OFFSET + (((irq) / 32) * 4)))) +#define PLIC_PENDING_BIT(irq) (1U << ((irq) % 32)) + +/* Enable bits: per context, 32 interrupts per 32-bit word + * Each context has 0x80 bytes (32 words * 32 bits = 1024 sources max) */ +#define PLIC_ENABLE_REG(base, ctx, irq) \ + (*((volatile uint32_t*)((base) + PLIC_ENABLE_OFFSET + \ + ((ctx) * PLIC_ENABLE_STRIDE) + (((irq) / 32) * 4)))) +#define PLIC_ENABLE_BIT(irq) (1U << ((irq) % 32)) + +/* Context registers: threshold and claim/complete + * Each context has 0x1000 bytes, with threshold at offset 0 and claim at offset 4 */ +#define PLIC_THRESHOLD_REG(base, ctx) \ + (*((volatile uint32_t*)((base) + PLIC_CONTEXT_OFFSET + \ + ((ctx) * PLIC_CONTEXT_STRIDE) + 0x00))) +#define PLIC_CLAIM_REG(base, ctx) \ + (*((volatile uint32_t*)((base) + PLIC_CONTEXT_OFFSET + \ + ((ctx) * PLIC_CONTEXT_STRIDE) + 0x04))) +/* Complete uses the same register as claim (write IRQ number to complete) */ +#define PLIC_COMPLETE_REG(base, ctx) PLIC_CLAIM_REG(base, ctx) + +#endif /* !__ASSEMBLER__ */ + +/* ============================================================================ + * PLIC Function Declarations (C code only, when PLIC_BASE is defined) + * + * These functions are implemented in boot_riscv.c when PLIC_BASE is defined. + * Platform must provide plic_get_context() to map current hart to PLIC context. + * ============================================================================ */ +#if defined(PLIC_BASE) && !defined(__ASSEMBLER__) + +#include + +/* Platform-provided: Get PLIC context ID for current hart + * Returns the context number (e.g., hart 1 S-mode = context 2) */ +extern uint32_t plic_get_context(void); + +/* Set priority for an interrupt source (0 = disabled, 1-7 = priority levels) */ +void plic_set_priority(uint32_t irq, uint32_t priority); + +/* Enable an interrupt for the current hart's context */ +void plic_enable_interrupt(uint32_t irq); + +/* Disable an interrupt for the current hart's context */ +void plic_disable_interrupt(uint32_t irq); + +/* Set the priority threshold for the current hart's context + * Interrupts with priority <= threshold are masked */ +void plic_set_threshold(uint32_t threshold); + +/* Claim the highest priority pending interrupt + * Returns IRQ number, or 0 if no interrupt pending */ +uint32_t plic_claim(void); + +/* Signal completion of interrupt handling */ +void plic_complete(uint32_t irq); + +/* Platform-provided: Dispatch IRQ to appropriate handler + * Called by generic external interrupt handler for each claimed IRQ */ +extern void plic_dispatch_irq(uint32_t irq); + +#endif /* PLIC_BASE && !__ASSEMBLER__ */ + #endif /* RISCV_H */ diff --git a/include/sdhci.h b/include/sdhci.h new file mode 100644 index 0000000000..b88169100a --- /dev/null +++ b/include/sdhci.h @@ -0,0 +1,462 @@ +/* sdhci.h + * + * Cadence SD Host Controller Interface (SDHCI) Driver + * Generic implementation supporting SD cards and eMMC. + * + * Compile with DISK_SDCARD=1 or DISK_EMMC=1 + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot 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 3 of the License, or + * (at your option) any later version. + * + * wolfBoot 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-1335, USA + */ + +#ifndef SDHCI_H +#define SDHCI_H + +#if defined(DISK_SDCARD) || defined(DISK_EMMC) + +#include + +/* ============================================================================ + * Configuration (override in target .config or platform header) + * ============================================================================ */ + +/* Block size */ +#ifndef SDHCI_BLOCK_SIZE +#define SDHCI_BLOCK_SIZE 512 +#endif + +/* DMA threshold - minimum transfer size to use DMA mode (default: 512KB) */ +#ifndef SDHCI_DMA_THRESHOLD +#define SDHCI_DMA_THRESHOLD (512U * 1024U) +#endif + +/* Disk test block address (platform should override) */ +#ifndef DISK_TEST_BLOCK_ADDR +#define DISK_TEST_BLOCK_ADDR 149504 /* ~76MB offset */ +#endif + +/* Auto-select DMA buffer boundary based on threshold */ +#if (SDHCI_DMA_THRESHOLD > (256U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_512KB + #if (SDHCI_DMA_THRESHOLD != (512U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 512KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (128U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_256KB + #if (SDHCI_DMA_THRESHOLD != (256U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 256KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (64U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_128KB + #if (SDHCI_DMA_THRESHOLD != (128U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 128KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (32U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_64KB + #if (SDHCI_DMA_THRESHOLD != (64U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 64KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (16U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_32KB + #if (SDHCI_DMA_THRESHOLD != (32U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 32KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (8U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_16KB + #if (SDHCI_DMA_THRESHOLD != (16U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 16KB" + #endif +#elif (SDHCI_DMA_THRESHOLD > (4U * 1024U)) + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_8KB + #if (SDHCI_DMA_THRESHOLD != (8U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 8KB" + #endif +#else + #define SDHCI_DMA_BUFF_BOUNDARY SDHCI_SRS01_DMA_BUFF_4KB + #if (SDHCI_DMA_THRESHOLD != (4U * 1024U)) + #warning "SDHCI_DMA_THRESHOLD rounded up to 4KB (minimum)" + #endif +#endif + +/* Timeouts */ +#ifndef SDHCI_INIT_TIMEOUT_US +#define SDHCI_INIT_TIMEOUT_US 500000 /* 500ms for initialization */ +#endif +#ifndef SDHCI_DATA_TIMEOUT_US +#define SDHCI_DATA_TIMEOUT_US 3000000 /* 3000ms for data operations */ +#endif + +/* Clock frequencies (kHz) */ +#ifndef SDHCI_CLK_400KHZ +#define SDHCI_CLK_400KHZ 400 +#endif +#ifndef SDHCI_CLK_25MHZ +#define SDHCI_CLK_25MHZ 25000 +#endif +#ifndef SDHCI_CLK_50MHZ +#define SDHCI_CLK_50MHZ 50000 +#endif + +/* ============================================================================ + * Cadence SDHCI Register Offsets (SD4HC Standard) + * ============================================================================ */ + +/* Host Register Set (HRS) */ +#define SDHCI_HRS00 0x000 /* General information */ +#define SDHCI_HRS01 0x004 /* Debounce setting */ +#define SDHCI_HRS02 0x008 /* Bus setting */ +#define SDHCI_HRS04 0x010 /* PHY access port */ +#define SDHCI_HRS06 0x018 /* eMMC control */ + +/* Slot Register Set (SRS) - SD Host Controller standard registers */ +#define SDHCI_SRS00 0x200 /* SDMA System Address / Argument 2 */ +#define SDHCI_SRS01 0x204 /* Block Size / Block Count */ +#define SDHCI_SRS02 0x208 /* Argument 1 */ +#define SDHCI_SRS03 0x20C /* Command / Transfer Mode */ +#define SDHCI_SRS04 0x210 /* Response 0 */ +#define SDHCI_SRS05 0x214 /* Response 1 */ +#define SDHCI_SRS06 0x218 /* Response 2 */ +#define SDHCI_SRS07 0x21C /* Response 3 */ +#define SDHCI_SRS08 0x220 /* Data Port */ +#define SDHCI_SRS09 0x224 /* Present State */ +#define SDHCI_SRS10 0x228 /* Host Control 1 / Power / Block Gap / Wakeup */ +#define SDHCI_SRS11 0x22C /* Clock Control / Timeout / Software Reset */ +#define SDHCI_SRS12 0x230 /* Normal Interrupt Status */ +#define SDHCI_SRS13 0x234 /* Normal Interrupt Status Enable */ +#define SDHCI_SRS14 0x238 /* Normal Interrupt Signal Enable */ +#define SDHCI_SRS15 0x23C /* Auto CMD Error Status / Host Control 2 */ +#define SDHCI_SRS16 0x240 /* Capabilities 1 */ +#define SDHCI_SRS17 0x244 /* Capabilities 2 */ +#define SDHCI_SRS18 0x248 /* Maximum Current */ +#define SDHCI_SRS22 0x258 /* ADMA2/SDMA Address (low) */ +#define SDHCI_SRS23 0x25C /* ADMA2/SDMA Address (high) */ + +/* ============================================================================ + * Register Bit Definitions + * ============================================================================ */ + +/* HRS00 - General Information Register */ +#define SDHCI_HRS00_SWR (1U << 0) /* Software reset */ + +/* HRS01 - Debounce Setting Register */ +#define SDHCI_HRS01_DP_SHIFT 16 +#define SDHCI_HRS01_DP_MASK (0xFFFFU << 16) + +/* HRS04 - PHY Access Port */ +#define SDHCI_HRS04_UIS_ACK (1U << 26) +#define SDHCI_HRS04_UIS_WR (1U << 24) +#define SDHCI_HRS04_UIS_ADDR_MASK 0x3F +#define SDHCI_HRS04_UIS_WDATA_SHIFT 8 + +/* HRS06 - eMMC Control Register */ +#define SDHCI_HRS06_EMM_MASK 0x07 +#define SDHCI_HRS06_MODE_SD 0x00 /* SD mode */ +#define SDHCI_HRS06_MODE_LEGACY 0x02 /* eMMC legacy mode */ + +/* SRS01 - Block Size / Block Count Register */ +#define SDHCI_SRS01_BCCT_SHIFT 16 /* Block count shift */ +#define SDHCI_SRS01_DMA_BUFF_4KB (0x0U << 12) +#define SDHCI_SRS01_DMA_BUFF_8KB (0x1U << 12) +#define SDHCI_SRS01_DMA_BUFF_16KB (0x2U << 12) +#define SDHCI_SRS01_DMA_BUFF_32KB (0x3U << 12) +#define SDHCI_SRS01_DMA_BUFF_64KB (0x4U << 12) +#define SDHCI_SRS01_DMA_BUFF_128KB (0x5U << 12) +#define SDHCI_SRS01_DMA_BUFF_256KB (0x6U << 12) +#define SDHCI_SRS01_DMA_BUFF_512KB (0x7U << 12) + +/* SRS03 - Command / Transfer Mode Register */ +#define SDHCI_SRS03_CIDX_SHIFT 24 +#define SDHCI_SRS03_CIDX_MASK (0x3FU << 24) +#define SDHCI_SRS03_CT_SHIFT 22 +#define SDHCI_SRS03_CT_MASK (0x03U << 22) +#define SDHCI_SRS03_CMD_NORMAL 0x00 +#define SDHCI_SRS03_CMD_SUSPEND 0x01 +#define SDHCI_SRS03_CMD_RESUME 0x02 +#define SDHCI_SRS03_CMD_ABORT 0x03 +#define SDHCI_SRS03_DPS (1U << 21) /* Data present */ +#define SDHCI_SRS03_CICE (1U << 20) /* Command index check enable */ +#define SDHCI_SRS03_CRCCE (1U << 19) /* Command CRC check enable */ +#define SDHCI_SRS03_RID (1U << 17) /* Response interrupt disable */ +#define SDHCI_SRS03_RECE (1U << 16) /* Response error check enable */ +#define SDHCI_SRS03_RESP_NONE (0x0U << 16) +#define SDHCI_SRS03_RESP_136 (0x1U << 16) +#define SDHCI_SRS03_RESP_48 (0x2U << 16) +#define SDHCI_SRS03_RESP_48B (0x3U << 16) +#define SDHCI_SRS03_MSBS (1U << 5) /* Multi/single block select */ +#define SDHCI_SRS03_DTDS (1U << 4) /* Data transfer direction (1=read) */ +#define SDHCI_SRS03_BCE (1U << 1) /* Block count enable */ +#define SDHCI_SRS03_DMAE (1U << 0) /* DMA enable */ + +/* SRS09 - Present State Register */ +#define SDHCI_SRS09_CI (1U << 16) /* Card inserted */ +#define SDHCI_SRS09_CSS (1U << 17) /* Card state stable */ +#define SDHCI_SRS09_CICMD (1U << 0) /* Command inhibit (CMD) */ +#define SDHCI_SRS09_CIDAT (1U << 1) /* Command inhibit (DAT) */ +#define SDHCI_SRS09_DAT0_LVL (1U << 20) /* DAT0 signal level */ + +/* SRS10 - Host Control 1 / Power / Block Gap / Wakeup */ +#define SDHCI_SRS10_DTW (1U << 1) /* Data transfer width (4-bit) */ +#define SDHCI_SRS10_EDTW (1U << 5) /* Extended data transfer width (8-bit) */ +#define SDHCI_SRS10_HSE (1U << 2) /* High speed enable */ +#define SDHCI_SRS10_BP (1U << 8) /* Bus power */ +#define SDHCI_SRS10_BVS_MASK (0x7U << 9) +#define SDHCI_SRS10_BVS_1_8V (0x5U << 9) +#define SDHCI_SRS10_BVS_3_0V (0x6U << 9) +#define SDHCI_SRS10_BVS_3_3V (0x7U << 9) +#define SDHCI_SRS10_DMA_SDMA (0x0U << 3) + +/* SRS11 - Clock Control / Timeout / Software Reset */ +#define SDHCI_SRS11_ICE (1U << 0) /* Internal clock enable */ +#define SDHCI_SRS11_ICS (1U << 1) /* Internal clock stable */ +#define SDHCI_SRS11_SDCE (1U << 2) /* SD clock enable */ +#define SDHCI_SRS11_CGS (1U << 5) /* Clock generator select */ +#define SDHCI_SRS11_SDCFSL_SHIFT 8 +#define SDHCI_SRS11_SDCFSL_MASK (0xFFU << 8) +#define SDHCI_SRS11_SDCFSH_SHIFT 6 +#define SDHCI_SRS11_SDCFSH_MASK (0x03U << 6) +#define SDHCI_SRS11_DTCV_SHIFT 16 +#define SDHCI_SRS11_DTCV_MASK (0x0FU << 16) +#define SDHCI_SRS11_RESET_DAT_CMD ((1U << 25) | (1U << 26)) + +/* SRS12 - Normal Interrupt Status */ +#define SDHCI_SRS12_CC (1U << 0) /* Command complete */ +#define SDHCI_SRS12_TC (1U << 1) /* Transfer complete */ +#define SDHCI_SRS12_BGE (1U << 2) /* Block gap event */ +#define SDHCI_SRS12_DMAINT (1U << 3) /* DMA interrupt */ +#define SDHCI_SRS12_BWR (1U << 4) /* Buffer write ready */ +#define SDHCI_SRS12_BRR (1U << 5) /* Buffer read ready */ +#define SDHCI_SRS12_CIN (1U << 6) /* Card insertion */ +#define SDHCI_SRS12_CR (1U << 7) /* Card removal */ +#define SDHCI_SRS12_CINT (1U << 8) /* Card interrupt */ +#define SDHCI_SRS12_EINT (1U << 15) /* Error interrupt */ +#define SDHCI_SRS12_ECT (1U << 16) /* Command timeout error */ +#define SDHCI_SRS12_ECCRC (1U << 17) /* Command CRC error */ +#define SDHCI_SRS12_ECEB (1U << 18) /* Command end bit error */ +#define SDHCI_SRS12_ECI (1U << 19) /* Command index error */ +#define SDHCI_SRS12_EDT (1U << 20) /* Data timeout error */ +#define SDHCI_SRS12_EDCRC (1U << 21) /* Data CRC error */ +#define SDHCI_SRS12_EDEB (1U << 22) /* Data end bit error */ +#define SDHCI_SRS12_ECL (1U << 23) /* Current limit error */ +#define SDHCI_SRS12_EAC (1U << 24) /* Auto CMD error */ +#define SDHCI_SRS12_EADMA (1U << 25) /* ADMA error */ +#define SDHCI_SRS12_NORM_STAT 0x0000FFFFU +#define SDHCI_SRS12_ERR_STAT 0xFFFF0000U + +/* SRS13 - Normal Interrupt Status Enable */ +#define SDHCI_SRS13_CC_SE (1U << 0) +#define SDHCI_SRS13_TC_SE (1U << 1) +#define SDHCI_SRS13_BGE_SE (1U << 2) +#define SDHCI_SRS13_DMAINT_SE (1U << 3) +#define SDHCI_SRS13_BWR_SE (1U << 4) +#define SDHCI_SRS13_BRR_SE (1U << 5) +#define SDHCI_SRS13_CIN_SE (1U << 6) +#define SDHCI_SRS13_CR_SE (1U << 7) +#define SDHCI_SRS13_CINT_SE (1U << 8) +#define SDHCI_SRS13_INT_ONA (1U << 9) +#define SDHCI_SRS13_INT_ONB (1U << 10) +#define SDHCI_SRS13_INT_ONC (1U << 11) +#define SDHCI_SRS13_RTUNE_SE (1U << 12) +#define SDHCI_SRS13_ECT_SE (1U << 16) +#define SDHCI_SRS13_ECCRC_SE (1U << 17) +#define SDHCI_SRS13_ECEB_SE (1U << 18) +#define SDHCI_SRS13_ECI_SE (1U << 19) +#define SDHCI_SRS13_EDT_SE (1U << 20) +#define SDHCI_SRS13_EDCRC_SE (1U << 21) +#define SDHCI_SRS13_EDEB_SE (1U << 22) +#define SDHCI_SRS13_ECL_SE (1U << 23) +#define SDHCI_SRS13_EAC_SE (1U << 24) +#define SDHCI_SRS13_EADMA_SE (1U << 25) +#define SDHCI_SRS13_ETUNE_SE (1U << 26) +#define SDHCI_SRS13_ERSP_SE (1U << 27) +#define SDHCI_SRS13_CQINT_SE (1U << 30) + +/* SRS14 - Normal Interrupt Signal Enable */ +#define SDHCI_SRS14_CC_IE (1U << 0) +#define SDHCI_SRS14_TC_IE (1U << 1) +#define SDHCI_SRS14_DMAINT_IE (1U << 3) +#define SDHCI_SRS14_EDT_IE (1U << 20) + +/* SRS15 - Auto CMD Error Status / Host Control 2 */ +#define SDHCI_SRS15_A64 (1U << 29) /* 64-bit addressing */ +#define SDHCI_SRS15_HV4E (1U << 28) /* Host version 4 enable */ +#define SDHCI_SRS15_UMS_MASK (0x7U << 16) +#define SDHCI_SRS15_UMS_SDR25 (0x1U << 16) +#define SDHCI_SRS15_DSS_MASK (0x3U << 20) +#define SDHCI_SRS15_DSS_TYPE_B (0x0U << 20) +#define SDHCI_SRS15_EXTNG (1U << 22) /* Execute tuning */ +#define SDHCI_SRS15_SCS (1U << 23) /* Sampling clock select */ + +/* SRS16 - Capabilities 1 */ +#define SDHCI_SRS16_TCF_SHIFT 0 +#define SDHCI_SRS16_TCF_MASK (0x3FU << 0) +#define SDHCI_SRS16_TCU (1U << 7) /* Timeout clock unit (1=MHz) */ +#define SDHCI_SRS16_BCSDCLK_SHIFT 8 +#define SDHCI_SRS16_BCSDCLK_MASK (0xFFU << 8) +#define SDHCI_SRS16_VS33 (1U << 24) /* 3.3V supported */ +#define SDHCI_SRS16_VS30 (1U << 25) /* 3.0V supported */ +#define SDHCI_SRS16_VS18 (1U << 26) /* 1.8V supported */ +#define SDHCI_SRS16_A64S (1U << 28) /* 64-bit system bus support */ + +/* SRS17 - Capabilities 2 */ +#define SDHCI_SRS17_SDR50 (1U << 0) +#define SDHCI_SRS17_SDR104 (1U << 1) +#define SDHCI_SRS17_DDR50 (1U << 2) +#define SDHCI_SRS17_TSDR50 (1U << 13) /* Tuning for SDR50 required */ + +/* SRS18 - Maximum Current */ +#define SDHCI_SRS18_MC33_SHIFT 0 +#define SDHCI_SRS18_MC33_MASK (0xFFU << 0) +#define SDHCI_SRS18_MC18_SHIFT 16 +#define SDHCI_SRS18_MC18_MASK (0xFFU << 16) + +/* ============================================================================ + * MMC/SD Command Definitions + * ============================================================================ */ + +/* Common MMC/SD commands */ +#define MMC_CMD0_GO_IDLE 0 +#define MMC_CMD2_ALL_SEND_CID 2 +#define MMC_CMD3_SET_REL_ADDR 3 +#define MMC_CMD7_SELECT_CARD 7 +#define MMC_CMD9_SEND_CSD 9 +#define MMC_CMD12_STOP_TRANS 12 +#define MMC_CMD13_SEND_STATUS 13 +#define MMC_CMD17_READ_SINGLE 17 +#define MMC_CMD18_READ_MULTIPLE 18 +#define MMC_CMD24_WRITE_SINGLE 24 +#define MMC_CMD25_WRITE_MULTIPLE 25 + +/* SD card-specific commands */ +#define SD_CMD6_SWITCH_FUNC 6 +#define SD_CMD8_SEND_IF_COND 8 +#define SD_CMD16 16 +#define SD_CMD19_SEND_TUNING 19 +#define SD_CMD55_APP_CMD 55 +#define SD_ACMD6_SET_BUS_WIDTH 6 +#define SD_ACMD41_SEND_OP_COND 41 +#define SD_ACMD51_SEND_SCR 51 + +/* eMMC-specific commands */ +#define MMC_CMD1_SEND_OP_COND 1 +#define MMC_CMD6_SWITCH 6 + +/* SD voltage check */ +#define SD_IF_COND_27V_33V 0x1AA + +/* SD RCA shift */ +#define SD_RCA_SHIFT 16 + +/* SD/MMC OCR register bits */ +#define SDCARD_ACMD41_HCS (1U << 30) +#define SDCARD_REG_OCR_READY (1U << 31) +#define SDCARD_REG_OCR_S18RA (1U << 24) +#define SDCARD_REG_OCR_XPC (1U << 28) +#define SDCARD_REG_OCR_2_9_3_0 (1U << 17) +#define SDCARD_REG_OCR_3_0_3_1 (1U << 18) +#define SDCARD_REG_OCR_3_1_3_2 (1U << 19) +#define SDCARD_REG_OCR_3_2_3_3 (1U << 20) +#define SDCARD_REG_OCR_3_3_3_4 (1U << 21) + +/* SD switch function */ +#define SDCARD_SWITCH_FUNC_MODE_CHECK (0U << 31) +#define SDCARD_SWITCH_FUNC_MODE_SWITCH (1U << 31) +#define SDCARD_SWITCH_ACCESS_MODE_SDR25 0x01 + +/* SCR register */ +#define SCR_REG_DATA_SIZE 8 + +/* eMMC-specific constants */ +#define MMC_DW_CSD 0x03B70000U +#define MMC_DEVICE_3_3V_VOLT_SET 0x40300000U +#define MMC_OCR_BUSY_BIT 0x80000000U +#define MMC_EMMC_RCA_DEFAULT 1 +#define MMC_EXT_CSD_WIDTH_1BIT 0x00U +#define MMC_EXT_CSD_WIDTH_4BIT 0x01U +#define MMC_EXT_CSD_WIDTH_8BIT 0x02U +#define MMC_EXT_CSD_WIDTH_4BIT_DDR 0x05U +#define MMC_EXT_CSD_WIDTH_8BIT_DDR 0x06U + +/* IRQ status flags */ +#define SDHCI_IRQ_FLAG_CC 0x01 +#define SDHCI_IRQ_FLAG_TC 0x02 +#define SDHCI_IRQ_FLAG_DMAINT 0x04 +#define SDHCI_IRQ_FLAG_ERROR 0x80 + +/* Response types */ +typedef enum { + SDHCI_RESP_NONE, + SDHCI_RESP_R1, + SDHCI_RESP_R1B, + SDHCI_RESP_R2, + SDHCI_RESP_R3, + SDHCI_RESP_R4, + SDHCI_RESP_R5, + SDHCI_RESP_R5B, + SDHCI_RESP_R6, + SDHCI_RESP_R7, + SDHCI_RESP_R1A +} sdhci_resp_t; + +/* ============================================================================ + * Public API (implemented in src/sdhci.c) + * ============================================================================ */ + +/* Initialize controller and card */ +int sdhci_init(void); + +/* Block read/write */ +int sdhci_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t sz); +int sdhci_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, uint32_t sz); + +/* Send command */ +int sdhci_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type); + +/* IRQ handler (call from platform IRQ) */ +void sdhci_irq_handler(void); + +/* ============================================================================ + * HAL Interface (platform must implement in target HAL file) + * ============================================================================ */ + +/* Register access - platform provides base address and implementation */ +uint32_t sdhci_reg_read(uint32_t offset); +void sdhci_reg_write(uint32_t offset, uint32_t val); + +/* Direct buffer data port access (for tight transfer loops) + * Default implementation uses sdhci_reg_read/write, but platform may + * override with direct volatile access for better performance */ +#ifndef SDHCI_BUF_READ +#define SDHCI_BUF_READ() sdhci_reg_read(SDHCI_SRS08) +#endif +#ifndef SDHCI_BUF_WRITE +#define SDHCI_BUF_WRITE(v) sdhci_reg_write(SDHCI_SRS08, v) +#endif + +/* Platform initialization (clocks, resets, pin mux, debounce) */ +void sdhci_platform_init(void); + +/* Platform interrupt setup (PLIC/NVIC/GIC/etc.) */ +void sdhci_platform_irq_init(void); + +/* Platform bus mode selection (SD vs eMMC) */ +void sdhci_platform_set_bus_mode(int is_emmc); + +#endif /* DISK_SDCARD || DISK_EMMC */ + +#endif /* SDHCI_H */ + diff --git a/options.mk b/options.mk index 9cd1b84a73..4190bc9f4e 100644 --- a/options.mk +++ b/options.mk @@ -524,6 +524,21 @@ ifeq ($(QSPI_FLASH),1) endif endif +# SD Card support (Cadence SDHCI controller) +ifeq ($(DISK_SDCARD),1) + CFLAGS+=-D"DISK_SDCARD=1" +endif + +# eMMC support (Cadence SDHCI controller) +ifeq ($(DISK_EMMC),1) + CFLAGS+=-D"DISK_EMMC=1" +endif + +# Add SDHCI driver if SD card or eMMC is enabled (only add once) +ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),) + OBJS+= src/sdhci.o +endif + ifeq ($(UART_FLASH),1) EXT_FLASH=1 endif diff --git a/src/boot_riscv.c b/src/boot_riscv.c index 2a7fc4d305..a25e7aefbf 100644 --- a/src/boot_riscv.c +++ b/src/boot_riscv.c @@ -28,12 +28,17 @@ #ifdef DEBUG_BOOT #include "printf.h" #endif -#include "hal/riscv.h" +/* Include platform-specific headers (may define PLIC_BASE) */ #ifdef TARGET_mpfs250 #include "hal/mpfs250.h" #endif +#include "hal/riscv.h" + +/* Generic PLIC support is enabled when platform defines PLIC_BASE. + * The PLIC header is included by the platform header after defining PLIC_BASE. */ + extern void trap_entry(void); extern void trap_exit(void); @@ -67,13 +72,6 @@ extern void main(void); /* reloc_trap_vector is implemented in boot_riscv_start.S */ extern void reloc_trap_vector(const uint32_t *address); -#ifdef TARGET_mpfs250 -/* PLIC functions from mpfs250.c */ -extern uint32_t plic_claim(void); -extern void plic_complete(uint32_t irq); -extern void mmc_irq_handler(void); -#endif - /* ============================================================================ * Trap Handling * ============================================================================ */ @@ -88,29 +86,87 @@ static uint32_t last_epc = 0; static uint32_t last_tval = 0; #endif -#ifdef TARGET_mpfs250 +#ifdef PLIC_BASE +/* ============================================================================ + * PLIC - Platform-Level Interrupt Controller (Generic Implementation) + * ============================================================================ */ + +/* Set priority for an interrupt source */ +void plic_set_priority(uint32_t irq, uint32_t priority) +{ + if (irq > 0 && priority <= PLIC_PRIORITY_MAX) { +#ifdef PLIC_NUM_SOURCES + if (irq >= PLIC_NUM_SOURCES) + return; +#endif + PLIC_PRIORITY_REG(PLIC_BASE, irq) = priority; + } +} + +/* Enable an interrupt for the current hart's context */ +void plic_enable_interrupt(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + if (irq > 0) { +#ifdef PLIC_NUM_SOURCES + if (irq >= PLIC_NUM_SOURCES) + return; +#endif + PLIC_ENABLE_REG(PLIC_BASE, ctx, irq) |= PLIC_ENABLE_BIT(irq); + } +} + +/* Disable an interrupt for the current hart's context */ +void plic_disable_interrupt(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + if (irq > 0) { +#ifdef PLIC_NUM_SOURCES + if (irq >= PLIC_NUM_SOURCES) + return; +#endif + PLIC_ENABLE_REG(PLIC_BASE, ctx, irq) &= ~PLIC_ENABLE_BIT(irq); + } +} + +/* Set the priority threshold for the current hart's context */ +void plic_set_threshold(uint32_t threshold) +{ + uint32_t ctx = plic_get_context(); + if (threshold <= PLIC_PRIORITY_MAX) { + PLIC_THRESHOLD_REG(PLIC_BASE, ctx) = threshold; + } +} + +/* Claim the highest priority pending interrupt */ +uint32_t plic_claim(void) +{ + uint32_t ctx = plic_get_context(); + return PLIC_CLAIM_REG(PLIC_BASE, ctx); +} + +/* Signal completion of interrupt handling */ +void plic_complete(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + PLIC_COMPLETE_REG(PLIC_BASE, ctx) = irq; +} + /* Handle external interrupts via PLIC */ static void handle_external_interrupt(void) { uint32_t irq; - /* Claim the interrupt from PLIC */ + /* Claim and dispatch interrupts until none pending */ while ((irq = plic_claim()) != 0) { - /* Dispatch to appropriate handler based on IRQ number */ - switch (irq) { - case PLIC_INT_MMC_MAIN: - mmc_irq_handler(); - break; - default: - /* Unknown interrupt - just complete it */ - break; - } + /* Platform-provided dispatch function */ + plic_dispatch_irq(irq); /* Signal completion to PLIC */ plic_complete(irq); } } -#endif +#endif /* PLIC_BASE */ unsigned long WEAKFUNCTION handle_trap(unsigned long cause, unsigned long epc, unsigned long tval) @@ -119,7 +175,7 @@ unsigned long WEAKFUNCTION handle_trap(unsigned long cause, unsigned long epc, last_epc = epc; last_tval = tval; -#ifdef TARGET_mpfs250 +#ifdef PLIC_BASE /* Check if this is an interrupt (MSB set) */ if (cause & MCAUSE_INT) { unsigned long exception_code = cause & MCAUSE_CAUSE; diff --git a/src/sdhci.c b/src/sdhci.c new file mode 100644 index 0000000000..3c38617b11 --- /dev/null +++ b/src/sdhci.c @@ -0,0 +1,1667 @@ +/* sdhci.c + * + * Cadence SD Host Controller Interface (SDHCI) Driver + * Generic implementation supporting SD cards and eMMC. + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot 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 3 of the License, or + * (at your option) any later version. + * + * wolfBoot 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-1335, USA + */ + +#include "sdhci.h" + +#if defined(DISK_SDCARD) || defined(DISK_EMMC) + +#include +#include +#include + +#include "printf.h" +#include "hal.h" +#include "disk.h" + +/* ============================================================================ + * Internal state + * ============================================================================ */ + +static uint32_t g_sector_count; +static uint32_t g_sector_size; +static uint32_t g_bus_width = 1; +static uint32_t g_rca = 0; /* SD Card Relative Address */ + +/* MMC Interrupt state - volatile for interrupt handler access */ +static volatile uint32_t g_mmc_irq_status = 0; +static volatile int g_mmc_irq_pending = 0; + +/* ============================================================================ + * Register Access Helpers + * ============================================================================ */ + +/* Read 32-bit register at offset */ +#define SDHCI_REG(offset) sdhci_reg_read(offset) + +/* Write 32-bit register at offset */ +#define SDHCI_REG_SET(offset, val) sdhci_reg_write(offset, val) + +/* Read-modify-write helper */ +static inline void sdhci_reg_or(uint32_t offset, uint32_t val) +{ + sdhci_reg_write(offset, sdhci_reg_read(offset) | val); +} + +static inline void sdhci_reg_and(uint32_t offset, uint32_t val) +{ + sdhci_reg_write(offset, sdhci_reg_read(offset) & val); +} + +/* ============================================================================ + * PHY Register Access + * ============================================================================ */ + +/* Write to SD/eMMC PHY register via HRS04 */ +static void sdhci_phy_write(uint8_t phy_addr, uint8_t delay_val) +{ + uint32_t phycfg; + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_phy_write: phyaddr: 0x%08x, delay_value: %d\n", + phy_addr, delay_val); +#endif + + /* Wait for ACK to clear */ + while ((SDHCI_REG(SDHCI_HRS04) & SDHCI_HRS04_UIS_ACK) == 0); + + /* Set address and delay value */ + phycfg = ((uint32_t)phy_addr & SDHCI_HRS04_UIS_ADDR_MASK) | + ((uint32_t)delay_val << SDHCI_HRS04_UIS_WDATA_SHIFT); + SDHCI_REG_SET(SDHCI_HRS04, phycfg); + + /* Send write request */ + SDHCI_REG_SET(SDHCI_HRS04, phycfg | SDHCI_HRS04_UIS_WR); + /* Wait for ACK */ + while ((SDHCI_REG(SDHCI_HRS04) & SDHCI_HRS04_UIS_ACK) == 0); + + /* Clear write request */ + SDHCI_REG_SET(SDHCI_HRS04, phycfg); + SDHCI_REG_SET(SDHCI_HRS04, 0); +} + +/* ============================================================================ + * Interrupt Handler + * ============================================================================ */ + +void sdhci_irq_handler(void) +{ + uint32_t status = SDHCI_REG(SDHCI_SRS12); + + /* Check for DMA interrupt */ + if (status & SDHCI_SRS12_DMAINT) { + /* Read updated DMA address - engine will increment block */ + uint32_t* addr = (uint32_t*)(uintptr_t)((((uint64_t)SDHCI_REG(SDHCI_SRS23)) << 32) | + SDHCI_REG(SDHCI_SRS22)); + /* Set new DMA address for next boundary */ + SDHCI_REG_SET(SDHCI_SRS22, (uint32_t)(uintptr_t)addr); + SDHCI_REG_SET(SDHCI_SRS23, (uint32_t)(((uint64_t)(uintptr_t)addr) >> 32)); + /* triggers next DMA block on write of top bit */ + + g_mmc_irq_status |= SDHCI_IRQ_FLAG_DMAINT; + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_DMAINT); /* Clear interrupt */ + } + + /* Check for transfer complete */ + if (status & SDHCI_SRS12_TC) { + g_mmc_irq_status |= SDHCI_IRQ_FLAG_TC; + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_TC); /* Clear interrupt */ + } + + /* Check for command complete */ + if (status & SDHCI_SRS12_CC) { + g_mmc_irq_status |= SDHCI_IRQ_FLAG_CC; + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_CC); /* Clear interrupt */ + } + + /* Check for data timeout error */ + if (status & SDHCI_SRS12_EDT) { + g_mmc_irq_status |= SDHCI_IRQ_FLAG_ERROR; + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_EDT); /* Clear interrupt */ + } + + /* Check for any other errors */ + if (status & SDHCI_SRS12_EINT) { + g_mmc_irq_status |= SDHCI_IRQ_FLAG_ERROR; + /* Clear all error status bits */ + SDHCI_REG_SET(SDHCI_SRS12, (status & SDHCI_SRS12_ERR_STAT)); + } + + /* Signal that interrupt was handled */ + g_mmc_irq_pending = 1; + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_irq_handler: status=0x%08X, flags=0x%02X\n", + status, g_mmc_irq_status); +#endif +} + +/* Enable SDHCI interrupts for SDMA transfer */ +static void sdhci_enable_sdma_interrupts(void) +{ + /* Enable signal interrupts for: DMA, Transfer Complete, Command Complete, + * Data Timeout Error */ + uint32_t sig_enable = SDHCI_SRS14_DMAINT_IE | + SDHCI_SRS14_TC_IE | + SDHCI_SRS14_CC_IE | + SDHCI_SRS14_EDT_IE; + sdhci_reg_or(SDHCI_SRS14, sig_enable); + + /* Clear any pending interrupt state */ + g_mmc_irq_status = 0; + g_mmc_irq_pending = 0; +} + +/* Disable SDHCI signal interrupts (status enables remain for polling) */ +static void sdhci_disable_sdma_interrupts(void) +{ + uint32_t reg = SDHCI_REG(SDHCI_SRS14); + reg &= ~(SDHCI_SRS14_DMAINT_IE | + SDHCI_SRS14_TC_IE | + SDHCI_SRS14_CC_IE | + SDHCI_SRS14_EDT_IE); + SDHCI_REG_SET(SDHCI_SRS14, reg); +} + +/* Wait for SDHCI interrupt with timeout */ +static int sdhci_wait_irq(uint32_t expected_flags, uint32_t timeout) +{ + while (timeout-- > 0) { + if (g_mmc_irq_pending) { + g_mmc_irq_pending = 0; + + /* Check for error */ + if (g_mmc_irq_status & SDHCI_IRQ_FLAG_ERROR) { + return -1; + } + + /* Check for expected flags */ + if (g_mmc_irq_status & expected_flags) { + return 0; + } + } + asm volatile("nop"); + } + return -1; /* Timeout */ +} + +/* ============================================================================ + * Timeout Configuration + * ============================================================================ */ + +static int sdhci_set_timeout(uint32_t timeout_us) +{ + uint32_t reg, i, tcfclk, tcfclk_mhz, tcfclk_khz, timeout_val, dtcv; + + /* read capabilities to determine timeout clock frequency and unit (MHz or kHz) */ + reg = SDHCI_REG(SDHCI_SRS16); + tcfclk_khz = (reg & SDHCI_SRS16_TCF_MASK) >> SDHCI_SRS16_TCF_SHIFT; + /* Default timeout clock frequency should be 50MHz */ + + if (((reg & SDHCI_SRS16_TCU) == 0) && (timeout_us < 1000)) { + /* invalid timeout_us value */ + return -1; + } + if (tcfclk_khz == 0) { + /* reported timeout clock frequency is 0 */ + return -1; + } + + if ((reg & SDHCI_SRS16_TCU) != 0) { + tcfclk_khz *= 1000; /* MHz to kHz */ + } + tcfclk_mhz = tcfclk_khz / 1000; + if (tcfclk_mhz == 0) { + tcfclk = tcfclk_khz; + timeout_val = timeout_us / 1000; + } + else { + tcfclk = tcfclk_mhz; + timeout_val = timeout_us; + } + + /* calculate the data timeout counter value */ + dtcv = 8192; /* 2*13 */ + for (i=0; i<15; i++) { + if (timeout_val < (dtcv / tcfclk)) { + break; + } + dtcv *= 2; + } + dtcv = i; + + /* set the data timeout counter value */ + reg = SDHCI_REG(SDHCI_SRS11); + reg &= ~SDHCI_SRS11_DTCV_MASK; + reg |= (dtcv << SDHCI_SRS11_DTCV_SHIFT) & SDHCI_SRS11_DTCV_MASK; + SDHCI_REG_SET(SDHCI_SRS11, reg); + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_set_timeout: timeout_val %d (%d)\n", timeout_val, dtcv); +#endif + + return 0; +} + +/* ============================================================================ + * Power Control + * ============================================================================ */ + +/* voltage values: + * 0 = off + * SDHCI_SRS10_BVS_1_8V + * SDHCI_SRS10_BVS_3_0V + * SDHCI_SRS10_BVS_3_3V + */ +static int sdhci_set_power(uint32_t voltage) +{ + uint32_t reg; + + /* disable bus power */ + reg = SDHCI_REG(SDHCI_SRS10); + reg &= ~SDHCI_SRS10_BP; + SDHCI_REG_SET(SDHCI_SRS10, reg); + + if (voltage != 0) { + /* read voltage capabilities */ + uint32_t cap2 = SDHCI_REG(SDHCI_SRS16); + + /* select voltage (if capable) */ + reg &= ~SDHCI_SRS10_BVS_MASK; + if (voltage == SDHCI_SRS10_BVS_1_8V && (cap2 & SDHCI_SRS16_VS18)) { + reg |= SDHCI_SRS10_BP | SDHCI_SRS10_BVS_1_8V; + } + else if (voltage == SDHCI_SRS10_BVS_3_0V && (cap2 & SDHCI_SRS16_VS30)) { + reg |= SDHCI_SRS10_BP | SDHCI_SRS10_BVS_3_0V; + } + else if (voltage == SDHCI_SRS10_BVS_3_3V && (cap2 & SDHCI_SRS16_VS33)) { + reg |= SDHCI_SRS10_BP | SDHCI_SRS10_BVS_3_3V; + } + else { + /* voltage not supported */ + return -1; + } + /* should be - 0xf06 */ + SDHCI_REG_SET(SDHCI_SRS10, reg); + } + return 0; +} + +/* ============================================================================ + * Clock Control + * ============================================================================ */ + +/* returns actual frequency in kHz */ +static uint32_t sdhci_set_clock(uint32_t clock_khz) +{ + static uint32_t last_clock_khz = 0; + uint32_t reg, base_clk_khz, i, mclk, freq_khz; + + if (last_clock_khz != 0 && last_clock_khz == clock_khz) { + /* clock already set */ + return 0; + } + + /* disable clock */ + sdhci_reg_and(SDHCI_SRS11, ~SDHCI_SRS11_SDCE); + + /* get base clock */ + reg = SDHCI_REG(SDHCI_SRS16); + base_clk_khz = (reg & SDHCI_SRS16_BCSDCLK_MASK) >> SDHCI_SRS16_BCSDCLK_SHIFT; + if (base_clk_khz == 0) { + /* error getting base clock */ + return -1; + } + base_clk_khz *= 1000; /* convert MHz to kHz */ + + /* calculate divider */ + for (i=1; i<2046; i++) { + if (((base_clk_khz / i) < clock_khz) || + (((base_clk_khz / i) == clock_khz) && (base_clk_khz % i) == 0)) { + break; + } + } + mclk = (i / 2); + + /* select clock frequency */ + reg = SDHCI_REG(SDHCI_SRS11); + reg &= ~(SDHCI_SRS11_SDCFSL_MASK | SDHCI_SRS11_SDCFSH_MASK); + reg |= (((mclk & 0x0FF) << SDHCI_SRS11_SDCFSL_SHIFT) & SDHCI_SRS11_SDCFSL_MASK); /* lower 8 bits */ + reg |= (((mclk & 0x300) << SDHCI_SRS11_SDCFSH_SHIFT) & SDHCI_SRS11_SDCFSH_SHIFT); /* upper 2 bits */ + reg |= SDHCI_SRS11_ICE; /* clock enable */ + reg &= ~SDHCI_SRS11_CGS; /* select clock */ + SDHCI_REG_SET(SDHCI_SRS11, reg); + freq_khz = base_clk_khz / i; + + /* wait for clock to stabilize */ + while ((SDHCI_REG(SDHCI_SRS11) & SDHCI_SRS11_ICS) == 0); + + /* enable clock */ + sdhci_reg_or(SDHCI_SRS11, SDHCI_SRS11_SDCE); + last_clock_khz = clock_khz; + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_set_clock: requested khz: %d, actual khz: %d\n", + clock_khz, freq_khz); +#endif + + return freq_khz; +} + +/* ============================================================================ + * Command Response Helpers + * ============================================================================ */ + +static uint32_t sdhci_get_response_type(uint8_t resp_type) +{ + uint32_t cmd_reg; + switch (resp_type) { + case SDHCI_RESP_R2: + cmd_reg = (SDHCI_SRS03_RESP_136 | SDHCI_SRS03_CRCCE); + break; + case SDHCI_RESP_R3: + case SDHCI_RESP_R4: + cmd_reg = SDHCI_SRS03_RESP_48; + break; + case SDHCI_RESP_R1: + case SDHCI_RESP_R5: + case SDHCI_RESP_R6: + case SDHCI_RESP_R7: + cmd_reg = (SDHCI_SRS03_RESP_48 | SDHCI_SRS03_CRCCE | SDHCI_SRS03_CICE); + break; + case SDHCI_RESP_R1B: + case SDHCI_RESP_R5B: + cmd_reg = (SDHCI_SRS03_RESP_48B | SDHCI_SRS03_CRCCE | SDHCI_SRS03_CICE); + break; + case SDHCI_RESP_NONE: + default: + cmd_reg = SDHCI_SRS03_RESP_NONE; + break; + } + return cmd_reg; +} + +/* ============================================================================ + * Command Sending + * ============================================================================ */ + +#define DEVICE_BUSY 1 + +static int sdhci_send_cmd_internal(uint32_t cmd_type, + uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) +{ + int status = 0; + uint32_t cmd_reg; + uint32_t timeout = 0x000FFFFF; + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_send_cmd: cmd_index: %d, cmd_arg: %08X, resp_type: %d\n", + cmd_index, cmd_arg, resp_type); +#endif + + /* wait for command line to be idle */ + while ((SDHCI_REG(SDHCI_SRS09) & SDHCI_SRS09_CICMD) != 0); + + /* set command argument and command transfer registers */ + SDHCI_REG_SET(SDHCI_SRS02, cmd_arg); + cmd_reg = + ((cmd_index << SDHCI_SRS03_CIDX_SHIFT) & SDHCI_SRS03_CIDX_MASK) | + ((cmd_type << SDHCI_SRS03_CT_SHIFT) & SDHCI_SRS03_CT_MASK) | + sdhci_get_response_type(resp_type); + + SDHCI_REG_SET(SDHCI_SRS03, cmd_reg); + + /* wait for command complete or error */ + while ((SDHCI_REG(SDHCI_SRS12) & (SDHCI_SRS12_CC | SDHCI_SRS12_TC | + SDHCI_SRS12_EINT)) == 0 && --timeout > 0); + + if (timeout == 0) { + wolfBoot_printf("sdhci_send_cmd: timeout waiting for command complete\n"); + status = -1; /* error */ + } + else if (SDHCI_REG(SDHCI_SRS12) & SDHCI_SRS12_EINT) { + wolfBoot_printf("sdhci_send_cmd: error SRS12: 0x%08X\n", SDHCI_REG(SDHCI_SRS12)); + status = -1; /* error */ + } + + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_CC); /* clear command complete */ + while ((SDHCI_REG(SDHCI_SRS09) & SDHCI_SRS09_CICMD) != 0); + + if (status == 0) { + /* check for device busy */ + if (resp_type == SDHCI_RESP_R1 || resp_type == SDHCI_RESP_R1B) { + uint32_t resp = SDHCI_REG(SDHCI_SRS04); + #define CARD_STATUS_READY_FOR_DATA (1U << 8) + if ((resp & CARD_STATUS_READY_FOR_DATA) == 0) { + status = DEVICE_BUSY; /* card is busy */ + } + } + } + + return status; +} + +int sdhci_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) +{ + /* send command */ + int status = sdhci_send_cmd_internal(SDHCI_SRS03_CMD_NORMAL, cmd_index, + cmd_arg, resp_type); + + /* clear all status interrupts + * (except current limit, card interrupt/removal/insert) */ + SDHCI_REG_SET(SDHCI_SRS12, ~(SDHCI_SRS12_ECL | + SDHCI_SRS12_CINT | + SDHCI_SRS12_CR | + SDHCI_SRS12_CIN)); + + return status; +} + +/* TODO: Add timeout */ +static int sdhci_wait_busy(int check_dat0) +{ + uint32_t status; + if (check_dat0) { + /* wait for DATA0 not busy */ + while ((SDHCI_REG(SDHCI_SRS09) & SDHCI_SRS09_DAT0_LVL) == 0); + } + /* wait for CMD13 */ + while ((status = sdhci_cmd(MMC_CMD13_SEND_STATUS, + (g_rca << SD_RCA_SHIFT), SDHCI_RESP_R1)) == DEVICE_BUSY); + return status; +} + +/* Reset data and command lines to recover from errors */ +static void sdhci_reset_lines(void) +{ + sdhci_reg_or(SDHCI_SRS11, SDHCI_SRS11_RESET_DAT_CMD); + while (SDHCI_REG(SDHCI_SRS11) & SDHCI_SRS11_RESET_DAT_CMD); +} + +/* ============================================================================ + * Response Parsing Helper + * ============================================================================ */ + +/* Helper to get bits from the response registers (shared by eMMC and SD) */ +static uint32_t sdhci_get_response_bits(int from, int count) +{ + uint32_t mask, ret; + int off, shft; + + from -= 8; + mask = ((count < 32) ? (1U << (uint32_t)count) : 0) - 1; + off = from / 32; + shft = from & 31; + + /* Read the response registers (SRS04-SRS07) */ + volatile uint32_t resp[4]; + resp[0] = SDHCI_REG(SDHCI_SRS04); + resp[1] = SDHCI_REG(SDHCI_SRS05); + resp[2] = SDHCI_REG(SDHCI_SRS06); + resp[3] = SDHCI_REG(SDHCI_SRS07); + + ret = resp[off] >> shft; + if ((from + shft) > 32) { + ret |= resp[off + 1] << ((32 - shft) % 32); + } + return ret & mask; +} + +/* ============================================================================ + * SD Card Specific Functions + * ============================================================================ */ + +#ifdef DISK_SDCARD + +/* Set power and send SD card initialization commands */ +/* voltage: 0=off or SDHCI_SRS10_BVS_[X_X]V */ +static int sdcard_power_init_seq(uint32_t voltage) +{ + /* Set power to specified voltage */ + int status = sdhci_set_power(voltage); + if (status == 0) { + /* send CMD0 (go idle) to reset card */ + status = sdhci_cmd(MMC_CMD0_GO_IDLE, 0, SDHCI_RESP_NONE); + } + if (status == 0) { + /* send the operating conditions command */ + status = sdhci_cmd(SD_CMD8_SEND_IF_COND, SD_IF_COND_27V_33V, + SDHCI_RESP_R7); + } + return status; +} + +/* SD card operating conditions initialization using ACMD41 */ +static int sdcard_card_init(uint32_t acmd41_arg, uint32_t *ocr_reg) +{ + int status = sdhci_cmd(SD_CMD55_APP_CMD, 0, SDHCI_RESP_R1); + if (status == 0) { + status = sdhci_cmd(SD_ACMD41_SEND_OP_COND, acmd41_arg, + SDHCI_RESP_R3); + if (status == 0) { + *ocr_reg = SDHCI_REG(SDHCI_SRS04); + #ifdef DEBUG_SDHCI + wolfBoot_printf("ocr_reg: 0x%08X\n", *ocr_reg); + #endif + } + } + return status; +} + +/* Forward declarations for SD card functions */ +static int sdcard_set_bus_width(uint32_t bus_width); +static int sdcard_set_function(uint32_t function_number, uint32_t group_number); + +/* Full SD card initialization sequence + * Returns 0 on success */ +static int sdcard_card_full_init(void) +{ + int status = 0; + uint32_t reg; + uint32_t ctrl_volts, card_volts; + uint32_t irq_restore; + int xpc, si8r; + + /* Set power to 3.3v and send init commands */ + ctrl_volts = SDHCI_SRS10_BVS_3_3V; /* default to 3.3v */ + status = sdcard_power_init_seq(ctrl_volts); + if (status == 0) { + uint32_t max_ma_3_3v, max_ma_1_8v; + /* determine host controller capabilities */ + reg = SDHCI_REG(SDHCI_SRS18); + max_ma_3_3v = ((reg & SDHCI_SRS18_MC33_MASK) >> SDHCI_SRS18_MC33_SHIFT) * 4; + max_ma_1_8v = ((reg & SDHCI_SRS18_MC18_MASK) >> SDHCI_SRS18_MC18_SHIFT) * 4; + /* does controller support eXtended Power Control (XPC)? */ + xpc = (max_ma_1_8v >= 150) && (max_ma_3_3v >= 150) ? 1 : 0; + /* does controller support UHS-I (Ultra High Speed Interface) v1.8 signaling? */ + si8r = ((SDHCI_REG(SDHCI_SRS16) & SDHCI_SRS16_VS18) && /* 1.8v supported */ + (SDHCI_REG(SDHCI_SRS17) & (SDHCI_SRS17_DDR50 | /* DDR50, SDR104 or SDR50 supported */ + SDHCI_SRS17_SDR104 | + SDHCI_SRS17_SDR50))) ? 1 : 0; + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdcard_init: xpc:%d, si8r:%d, max_ma (3.3v:%d 1.8v:%d)\n", + xpc, si8r, max_ma_3_3v, max_ma_1_8v); + #endif + } + + if (status == 0) { + reg = 0; + /* get operating conditions */ + status = sdcard_card_init(0, ®); + if (status == 0) { + /* pick host and card operating voltages */ + if (reg & SDCARD_REG_OCR_3_3_3_4) { /* 3.3v - 3.4v */ + card_volts = SDCARD_REG_OCR_3_3_3_4; + } + else if (reg & SDCARD_REG_OCR_3_2_3_3) { /* 3.2v - 3.3v */ + card_volts = SDCARD_REG_OCR_3_2_3_3; + } + else if (reg & SDCARD_REG_OCR_3_1_3_2) { /* 3.1v - 3.2v */ + card_volts = SDCARD_REG_OCR_3_1_3_2; + } + else if (reg & SDCARD_REG_OCR_3_0_3_1) { /* 3.0v - 3.1v */ + card_volts = SDCARD_REG_OCR_3_0_3_1; + ctrl_volts = SDHCI_SRS10_BVS_3_0V; + } + else if (reg & SDCARD_REG_OCR_2_9_3_0) { /* 2.9v - 3.0v */ + card_volts = SDCARD_REG_OCR_2_9_3_0; + ctrl_volts = SDHCI_SRS10_BVS_3_0V; + } + else { /* default to v3.3 */ + card_volts = SDCARD_REG_OCR_3_3_3_4; + } + /* if needed change operating voltage and re-init */ + if (ctrl_volts != SDHCI_SRS10_BVS_3_3V) { + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdcard_init: changing operating voltage to 3.0v\n"); + #endif + status = sdcard_power_init_seq(ctrl_volts); + } + } + } + + if (status == 0) { + /* configure operating conditions */ + uint32_t cmd_arg = SDCARD_ACMD41_HCS; + cmd_arg |= card_volts; + if (si8r) { + cmd_arg |= SDCARD_REG_OCR_S18RA; + } + if (xpc) { + cmd_arg |= SDCARD_REG_OCR_XPC; + } + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdcard_init: sending OCR arg: 0x%08X\n", cmd_arg); + #endif + + /* retry until OCR ready */ + do { + status = sdcard_card_init(cmd_arg, ®); + } while (status == 0 && (reg & SDCARD_REG_OCR_READY) == 0); + } + + if (status == 0) { + /* Get card identification */ + status = sdhci_cmd(MMC_CMD2_ALL_SEND_CID, 0, SDHCI_RESP_R2); + } + + if (status == 0) { + /* Set relative address - SD card assigns its own RCA */ + status = sdhci_cmd(MMC_CMD3_SET_REL_ADDR, 0, SDHCI_RESP_R6); + } + + if (status == 0) { + g_rca = ((SDHCI_REG(SDHCI_SRS04) >> SD_RCA_SHIFT) & 0xFFFF); + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdcard_init: rca: %d\n", g_rca); + #endif + } + + if (status == 0) { + /* read CSD register from device */ + status = sdhci_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R2); + } + + if (status == 0) { + /* Get sector size and count */ + uint32_t csd_struct; + uint32_t bl_len, c_size, c_size_mult; + bl_len = sdhci_get_response_bits(22, 4); + g_sector_size = (1U << bl_len); + + csd_struct = sdhci_get_response_bits(126, 2); + switch (csd_struct) { + case 0: + c_size = sdhci_get_response_bits(62, 12); + c_size_mult = sdhci_get_response_bits(47, 3); + g_sector_count = (c_size + 1) << (c_size_mult + 2); + break; + case 1: + c_size = sdhci_get_response_bits(48, 22); + g_sector_count = (c_size + 1) << 10; + break; + default: + /* invalid CSD structure */ + status = -1; + break; + } + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdcard_init: csd_version: %d, sector: size %d count %d\n", + csd_struct, g_sector_size, g_sector_count); + #endif + } + + if (status == 0) { + /* select card */ + status = sdhci_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R1B); + if (status == DEVICE_BUSY) { + status = sdhci_wait_busy(1); + } + } + + irq_restore = SDHCI_REG(SDHCI_SRS13); + if (status == 0) { + /* disable card insert interrupt while changing bus width to avoid false triggers */ + SDHCI_REG_SET(SDHCI_SRS13, (irq_restore & ~SDHCI_SRS13_CINT_SE)); + + status = sdcard_set_bus_width(4); + } + + if (status == 0) { + /* Get SCR registers - 8 bytes */ + uint32_t scr_reg[SCR_REG_DATA_SIZE/sizeof(uint32_t)]; + status = sdhci_read(SD_ACMD51_SEND_SCR, 0, scr_reg, + sizeof(scr_reg)); + } + + if (status == 0) { + /* set UHS mode to SDR25 and driver strength to Type B */ + uint32_t card_access_mode = SDCARD_SWITCH_ACCESS_MODE_SDR25; + status = sdcard_set_function(card_access_mode, 1); + if (status == 0) { + /* set driver strength */ + reg = SDHCI_REG(SDHCI_SRS15); + reg &= ~SDHCI_SRS15_DSS_MASK; + reg |= SDHCI_SRS15_DSS_TYPE_B; /* default */ + SDHCI_REG_SET(SDHCI_SRS15, reg); + + /* enable high speed */ + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_HSE); + + /* set UHS mode */ + reg = SDHCI_REG(SDHCI_SRS15); + reg &= ~SDHCI_SRS15_UMS_MASK; + reg |= SDHCI_SRS15_UMS_SDR25; + SDHCI_REG_SET(SDHCI_SRS15, reg); + } + } + + if (status == 0) { + sdhci_set_clock(SDHCI_CLK_50MHZ); + } + + SDHCI_REG_SET(SDHCI_SRS13, irq_restore); /* re-enable interrupt */ + + return status; +} + +/* Set SD card bus width using ACMD6 */ +static int sdcard_set_bus_width(uint32_t bus_width) +{ + int status; + + if (bus_width == g_bus_width) { + /* nothing to do */ + return 0; + } + + /* set bus width */ + status = sdhci_cmd(SD_CMD55_APP_CMD, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R1); + if (status == 0) { + uint32_t cmd_arg = (bus_width == 4) ? 2 : 0; + status = sdhci_cmd(SD_ACMD6_SET_BUS_WIDTH, cmd_arg, SDHCI_RESP_R1); + if (status == 0) { + /* change host bus width */ + if (bus_width == 4) { + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_DTW); + } + else { + sdhci_reg_and(SDHCI_SRS10, ~SDHCI_SRS10_DTW); + } + } + } + return status; +} + +/* Check or set SD card switch function/group + * Returns 0 if supported */ +static int sdcard_send_switch_function(uint32_t mode, uint32_t function_number, + uint32_t group_number) +{ + int status; + uint32_t timeout = 4; + uint32_t cmd_arg; + uint32_t func_status[64/sizeof(uint32_t)]; /* fixed 512 bits */ + uint8_t* p_func_status = (uint8_t*)func_status; + + if (group_number > 6 || function_number > 15) { + return -1; /* Invalid group or function number */ + } + + cmd_arg = (function_number << ((group_number - 1) * 4)); + do { + /* first run check to see if function is supported */ + status = sdhci_read(SD_CMD6_SWITCH_FUNC, + (mode | cmd_arg), + func_status, sizeof(func_status)); + if (status == 0) { + /* check if busy */ + /* data structure version 368:375 + * (0=supported only, 1=supported and busy) */ + if (p_func_status[17] == 1) { + /* busy status: group 1 272:287 */ + if ((p_func_status[29 - + ((group_number-1)*2)] & (1 << function_number))) { + continue; /* busy */ + } + } + + /* supported: group 1 415:400 */ + if ((p_func_status[13 - + ((group_number-1)*2)] & (1 << function_number))) { + status = 0; /* supported */ + } + else { + status = -1; /* not supported */ + } + break; + } + } while (status == 0 && --timeout > 0); /* retry until function not busy */ + return status; +} + +/* Set SD card function (check first, then switch) */ +static int sdcard_set_function(uint32_t function_number, uint32_t group_number) +{ + /* send check first */ + int status = sdcard_send_switch_function(SDCARD_SWITCH_FUNC_MODE_CHECK, + function_number, group_number); + if (status == 0) { + /* send switch function */ + status = sdcard_send_switch_function(SDCARD_SWITCH_FUNC_MODE_SWITCH, + function_number, group_number); + } + return status; +} + +#endif /* DISK_SDCARD */ + +/* ============================================================================ + * eMMC Specific Functions + * ============================================================================ */ + +#ifdef DISK_EMMC + +/* Send CMD1 (SEND_OP_COND) for eMMC and wait for device ready + * Returns 0 on success, negative on error */ +static int emmc_send_op_cond(uint32_t ocr_arg, uint32_t *ocr_reg) +{ + int status; + uint32_t timeout = 1000; /* retry count */ + uint32_t response; + + /* First CMD1 to query supported voltages */ + status = sdhci_cmd(MMC_CMD1_SEND_OP_COND, 0, SDHCI_RESP_R3); + if (status != 0) { + wolfBoot_printf("eMMC: CMD1 query failed\n"); + return status; + } + + /* Get OCR from response */ + response = SDHCI_REG(SDHCI_SRS04); +#ifdef DEBUG_SDHCI + wolfBoot_printf("eMMC: Initial OCR: 0x%08X\n", response); +#endif + + /* Loop sending CMD1 with operating conditions until device is ready */ + do { + status = sdhci_cmd(MMC_CMD1_SEND_OP_COND, ocr_arg, SDHCI_RESP_R3); + if (status != 0) { + wolfBoot_printf("eMMC: CMD1 failed\n"); + return status; + } + + response = SDHCI_REG(SDHCI_SRS04); + + /* Check if device is ready (busy bit cleared = ready) */ + if (response & MMC_OCR_BUSY_BIT) { + /* Device is ready */ + if (ocr_reg != NULL) { + *ocr_reg = response; + } +#ifdef DEBUG_SDHCI + wolfBoot_printf("eMMC: Device ready, OCR: 0x%08X\n", response); +#endif + return 0; + } + + /* Small delay between retries */ + for (volatile int i = 0; i < 1000; i++); + + } while (--timeout > 0); + + wolfBoot_printf("eMMC: Timeout waiting for device ready\n"); + return -1; +} + +/* Set eMMC bus width using CMD6 SWITCH command + * width: MMC_EXT_CSD_WIDTH_1BIT, MMC_EXT_CSD_WIDTH_4BIT, or MMC_EXT_CSD_WIDTH_8BIT + * Returns 0 on success */ +static int emmc_set_bus_width(uint32_t width) +{ + int status; + uint32_t cmd_arg; + + /* Build CMD6 argument: Access=Write Byte, Index=183 (BUS_WIDTH), Value=width */ + cmd_arg = MMC_DW_CSD | (width << 8); + +#ifdef DEBUG_SDHCI + wolfBoot_printf("eMMC: Setting bus width to %d (CMD6 arg: 0x%08X)\n", + (width == MMC_EXT_CSD_WIDTH_4BIT) ? 4 : + (width == MMC_EXT_CSD_WIDTH_8BIT) ? 8 : 1, cmd_arg); +#endif + + /* Send CMD6 SWITCH */ + status = sdhci_cmd(MMC_CMD6_SWITCH, cmd_arg, SDHCI_RESP_R1B); + if (status == DEVICE_BUSY) { + status = sdhci_wait_busy(1); + } + + if (status != 0) { + wolfBoot_printf("eMMC: Set bus width failed\n"); + return status; + } + + /* Update host controller bus width */ + if (width == MMC_EXT_CSD_WIDTH_4BIT || width == MMC_EXT_CSD_WIDTH_4BIT_DDR) { + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_DTW); + sdhci_reg_and(SDHCI_SRS10, ~SDHCI_SRS10_EDTW); + g_bus_width = 4; + } + else if (width == MMC_EXT_CSD_WIDTH_8BIT || width == MMC_EXT_CSD_WIDTH_8BIT_DDR) { + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_EDTW); + g_bus_width = 8; + } + else { + uint32_t reg = SDHCI_REG(SDHCI_SRS10); + reg &= ~(SDHCI_SRS10_DTW | SDHCI_SRS10_EDTW); + SDHCI_REG_SET(SDHCI_SRS10, reg); + g_bus_width = 1; + } + + return 0; +} + +/* Full eMMC card initialization sequence + * Returns 0 on success */ +static int emmc_card_full_init(void) +{ + int status; + uint32_t ocr_reg; + + /* Send CMD0 (GO_IDLE) to reset eMMC */ + status = sdhci_cmd(MMC_CMD0_GO_IDLE, 0, SDHCI_RESP_NONE); + if (status != 0) { + wolfBoot_printf("eMMC: CMD0 failed\n"); + return status; + } + + /* Small delay after reset */ + for (volatile int i = 0; i < 10000; i++); + + /* Send CMD1 with operating conditions (3.3V, sector mode) */ + status = emmc_send_op_cond(MMC_DEVICE_3_3V_VOLT_SET, &ocr_reg); + if (status != 0) { + return status; + } + + /* CMD2 - Get CID (card identification) */ + status = sdhci_cmd(MMC_CMD2_ALL_SEND_CID, 0, SDHCI_RESP_R2); + if (status != 0) { + wolfBoot_printf("eMMC: CMD2 failed\n"); + return status; + } + + /* CMD3 - Set relative address (host assigns RCA for eMMC) */ + g_rca = MMC_EMMC_RCA_DEFAULT; + status = sdhci_cmd(MMC_CMD3_SET_REL_ADDR, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R1); + if (status != 0) { + wolfBoot_printf("eMMC: CMD3 failed\n"); + return status; + } + +#ifdef DEBUG_SDHCI + wolfBoot_printf("eMMC: RCA set to %d\n", g_rca); +#endif + + /* CMD9 - Get CSD (card-specific data) */ + status = sdhci_cmd(MMC_CMD9_SEND_CSD, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R2); + if (status != 0) { + wolfBoot_printf("eMMC: CMD9 failed\n"); + return status; + } + + /* Parse CSD to get sector size/count */ + { + uint32_t csd_struct, c_size; + uint32_t bl_len = sdhci_get_response_bits(22, 4); + g_sector_size = (1U << bl_len); + + csd_struct = sdhci_get_response_bits(126, 2); + /* eMMC typically uses CSD version 3 (EXT_CSD) with fixed 512-byte sectors */ + if (csd_struct >= 2) { + /* For eMMC, actual capacity is in EXT_CSD, use default for now */ + g_sector_size = 512; + g_sector_count = 0; /* Will be read from EXT_CSD if needed */ + } + else { + /* Legacy CSD parsing */ + c_size = sdhci_get_response_bits(48, 22); + g_sector_count = (c_size + 1) << 10; + } + +#ifdef DEBUG_SDHCI + wolfBoot_printf("eMMC: CSD version %d, sector size %d\n", + csd_struct, g_sector_size); +#endif + } + + /* CMD7 - Select card */ + status = sdhci_cmd(MMC_CMD7_SELECT_CARD, g_rca << SD_RCA_SHIFT, + SDHCI_RESP_R1B); + if (status == DEVICE_BUSY) { + status = sdhci_wait_busy(1); + } + if (status != 0) { + wolfBoot_printf("eMMC: CMD7 failed\n"); + return status; + } + + /* Set bus width to 4-bit */ + status = emmc_set_bus_width(MMC_EXT_CSD_WIDTH_4BIT); + if (status != 0) { + wolfBoot_printf("eMMC: Set bus width failed, continuing with 1-bit\n"); + /* Non-fatal, continue with 1-bit */ + } + + /* Set clock to 25MHz for legacy mode */ + sdhci_set_clock(SDHCI_CLK_25MHZ); + + /* Enable high speed if desired (optional for legacy mode) */ + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_HSE); + + return 0; +} + +#endif /* DISK_EMMC */ + +/* ============================================================================ + * Data Transfer + * ============================================================================ */ + +/* Transfer direction for sdhci_transfer() */ +#define SDHCI_DIR_READ 1 +#define SDHCI_DIR_WRITE 0 + +/* Unified internal transfer function for read and write operations + * dir: SDHCI_DIR_READ or SDHCI_DIR_WRITE + * cmd_index: command to send (e.g., MMC_CMD17_READ_SINGLE, MMC_CMD25_WRITE_MULTIPLE) + * block_addr: block address for the transfer + * buf: data buffer (source for write, destination for read) + * sz: transfer size in bytes + * Returns 0 on success, negative on error */ +static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr, + uint32_t* buf, uint32_t sz) +{ + int status; + uint32_t block_count, reg, cmd_reg, bcr_reg; + int is_multi_block; + + /* Determine if multi-block operation */ + is_multi_block = (dir == SDHCI_DIR_READ) ? + (cmd_index == MMC_CMD18_READ_MULTIPLE) : + (cmd_index == MMC_CMD25_WRITE_MULTIPLE); + + /* Get block count (round up) */ + block_count = (sz + (SDHCI_BLOCK_SIZE - 1)) / SDHCI_BLOCK_SIZE; + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_%s: cmd:%d, addr:0x%08X, buf:%p, sz:%d (%d blocks)\n", + (dir == SDHCI_DIR_READ) ? "read" : "write", + cmd_index, block_addr, buf, sz, block_count); +#endif + + /* Wait for idle */ + status = sdhci_wait_busy(0); + if (status != 0) { + #ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_transfer: wait busy error\n"); + #endif + return status; + } + + /* Reset data and command lines */ + sdhci_reset_lines(); + + /* Wait for command and data line busy to clear */ + while ((SDHCI_REG(SDHCI_SRS09) & (SDHCI_SRS09_CICMD | SDHCI_SRS09_CIDAT)) != 0); + + /* Setup default transfer block count and block size */ + bcr_reg = (block_count << SDHCI_SRS01_BCCT_SHIFT) | sz; + + /* Build command register: + * - CIDX: Command index + * - DPS: Data present + * - DTDS: Data transfer direction (1=read, 0=write) + * - BCE, RECE, RID: Block count enable, response error check, response interrupt disable + * - RESP_48, CRCCE, CICE: 48-bit response, CRC check, index check */ + cmd_reg = ((cmd_index << SDHCI_SRS03_CIDX_SHIFT) | + SDHCI_SRS03_DPS | + SDHCI_SRS03_BCE | SDHCI_SRS03_RECE | SDHCI_SRS03_RID | + SDHCI_SRS03_RESP_48 | SDHCI_SRS03_CRCCE | SDHCI_SRS03_CICE); + + /* Set direction bit for read */ + if (dir == SDHCI_DIR_READ) { + cmd_reg |= SDHCI_SRS03_DTDS; + } + + /* Handle special case for SD_ACMD51_SEND_SCR (read only) */ + if (cmd_index == SD_ACMD51_SEND_SCR) { + status = sdhci_cmd(SD_CMD16, sz, SDHCI_RESP_R1); + if (status == 0) { + status = sdhci_cmd(SD_CMD55_APP_CMD, (g_rca << SD_RCA_SHIFT), + SDHCI_RESP_R1); + } + status = 0; /* ignore error */ + } + else if (is_multi_block) { + cmd_reg |= SDHCI_SRS03_MSBS; /* enable multi-block select */ + + if (sz >= SDHCI_DMA_THRESHOLD) { /* use DMA for large transfers */ + cmd_reg |= SDHCI_SRS03_DMAE; /* enable DMA */ + + bcr_reg = (block_count << SDHCI_SRS01_BCCT_SHIFT) | + SDHCI_DMA_BUFF_BOUNDARY | SDHCI_BLOCK_SIZE; + + /* SDMA mode */ + sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_DMA_SDMA); + if (dir == SDHCI_DIR_WRITE) { + sdhci_reg_or(SDHCI_SRS15, SDHCI_SRS15_HV4E); + sdhci_reg_and(SDHCI_SRS16, ~SDHCI_SRS16_A64S); + } + /* Set SDMA address */ + SDHCI_REG_SET(SDHCI_SRS22, (uint32_t)(uintptr_t)buf); + SDHCI_REG_SET(SDHCI_SRS23, (uint32_t)(((uint64_t)(uintptr_t)buf) >> 32)); + + /* Enable SDMA interrupts */ + sdhci_enable_sdma_interrupts(); + } + else { + bcr_reg = (block_count << SDHCI_SRS01_BCCT_SHIFT) | + SDHCI_BLOCK_SIZE; + } + } + + /* Execute command */ + SDHCI_REG_SET(SDHCI_SRS01, bcr_reg); + SDHCI_REG_SET(SDHCI_SRS02, block_addr); + SDHCI_REG_SET(SDHCI_SRS03, cmd_reg); + + /* Handle data transfer */ + if (cmd_reg & SDHCI_SRS03_DMAE) { + /* DMA mode with interrupt support */ + while (1) { + status = sdhci_wait_irq(SDHCI_IRQ_FLAG_TC, 0x00FFFFFF); + if (status != 0) { + wolfBoot_printf("sdhci_transfer: SDMA timeout/error\n"); + status = -1; + break; + } + if (g_mmc_irq_status & SDHCI_IRQ_FLAG_TC) { + g_mmc_irq_status &= ~SDHCI_IRQ_FLAG_TC; + break; + } + } + sdhci_disable_sdma_interrupts(); + } + else { + /* Blocking mode - buffer ready flag differs for read vs write */ + uint32_t buf_ready_flag = (dir == SDHCI_DIR_READ) ? + SDHCI_SRS12_BRR : SDHCI_SRS12_BWR; + + while (sz > 0) { + /* Wait for buffer ready (or error) */ + while (((reg = SDHCI_REG(SDHCI_SRS12)) & + (buf_ready_flag | SDHCI_SRS12_EINT)) == 0); + + if (reg & buf_ready_flag) { + uint32_t i, xfer_sz = (sz > SDHCI_BLOCK_SIZE) ? + SDHCI_BLOCK_SIZE : sz; + for (i = 0; i < xfer_sz; i += 4) { + if (dir == SDHCI_DIR_READ) { + *buf = SDHCI_REG(SDHCI_SRS08); + } else { + SDHCI_REG_SET(SDHCI_SRS08, *buf); + } + buf++; + } + sz -= xfer_sz; + + #ifdef DISK_EMMC /* workaround for eMMC only */ + /* For multi-block READ: clear BRR by writing 1 to it (W1C), + * then the outer loop waits for BRR to be set again when the + * next block's data is available from the card. + * For WRITE: BWR auto-clears when buffer full, don't touch. */ + if (sz > 0 && dir == SDHCI_DIR_READ) { + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_BRR); + } + #endif + } + if (reg & SDHCI_SRS12_EINT) { + break; /* error */ + } + } + + /* For write: wait for transfer complete before checking status */ + if (dir == SDHCI_DIR_WRITE) { + while (((reg = SDHCI_REG(SDHCI_SRS12)) & + (SDHCI_SRS12_TC | SDHCI_SRS12_EINT)) == 0); + } + } + + /* Check for errors */ + reg = SDHCI_REG(SDHCI_SRS12); + if ((reg & SDHCI_SRS12_ERR_STAT) == 0) { + /* If multi-block, send CMD12 to stop transfer */ + if (is_multi_block) { + #ifdef DISK_EMMC + uint32_t stop_arg = 0; + #else + uint32_t stop_arg = (g_rca << SD_RCA_SHIFT); + #endif + + SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_TC); /* Clear transfer complete */ + + /* Send stop multi-block transfer */ + status = sdhci_send_cmd_internal(SDHCI_SRS03_CMD_ABORT, + MMC_CMD12_STOP_TRANS, stop_arg, SDHCI_RESP_R1B); + /* Card may be busy programming data after CMD12 */ + if (status == DEVICE_BUSY) { + status = sdhci_wait_busy(1); + } + if (status != 0) { + wolfBoot_printf("sdhci_transfer: CMD12 error\n"); + } + } + if (status == 0) { + status = sdhci_wait_busy(0); + } + } + else { + wolfBoot_printf("sdhci_transfer: error SRS12: 0x%08X\n", reg); + status = -1; + } + +#ifdef DEBUG_SDHCI + wolfBoot_printf("sdhci_%s: status: %d\n", + (dir == SDHCI_DIR_READ) ? "read" : "write", status); +#endif + + /* Clear status interrupts (except current limit, card interrupt/removal/insert) */ + sdhci_reset_lines(); + SDHCI_REG_SET(SDHCI_SRS12, ~(SDHCI_SRS12_ECL | SDHCI_SRS12_CINT | + SDHCI_SRS12_CR | SDHCI_SRS12_CIN)); + + return status; +} + +/* Public API: Read from MMC/SD card */ +int sdhci_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t sz) +{ + return sdhci_transfer(SDHCI_DIR_READ, cmd_index, block_addr, dst, sz); +} + +/* Public API: Write to MMC/SD card */ +int sdhci_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, uint32_t sz) +{ + return sdhci_transfer(SDHCI_DIR_WRITE, cmd_index, block_addr, (uint32_t*)src, sz); +} + +/* ============================================================================ + * Controller Initialization + * ============================================================================ */ + +int sdhci_init(void) +{ + int status = 0; + uint32_t reg, cap; + + /* Call platform-specific initialization (clocks, resets, pin mux) */ + sdhci_platform_init(); + + /* Reset the host controller */ + sdhci_reg_or(SDHCI_HRS00, SDHCI_HRS00_SWR); + /* Bit will clear when reset is done */ + while ((SDHCI_REG(SDHCI_HRS00) & SDHCI_HRS00_SWR) != 0); + + /* Set debounce period to ~15ms (platform-specific value may be different) */ + SDHCI_REG_SET(SDHCI_HRS01, (0x300000UL << SDHCI_HRS01_DP_SHIFT) & + SDHCI_HRS01_DP_MASK); + + /* Select card mode */ + reg = SDHCI_REG(SDHCI_HRS06); + reg &= ~SDHCI_HRS06_EMM_MASK; +#ifdef DISK_EMMC + reg |= SDHCI_HRS06_MODE_LEGACY; /* eMMC Legacy mode */ +#else + reg |= SDHCI_HRS06_MODE_SD; /* SD card mode */ +#endif + SDHCI_REG_SET(SDHCI_HRS06, reg); + + /* Let platform set bus mode (SD vs eMMC) */ +#ifdef DISK_EMMC + sdhci_platform_set_bus_mode(1); +#else + sdhci_platform_set_bus_mode(0); +#endif + + /* Clear error/interrupt status */ + SDHCI_REG_SET(SDHCI_SRS12, (SDHCI_SRS12_NORM_STAT | SDHCI_SRS12_ERR_STAT)); + + /* Check and enable 64-bit DMA support */ + reg = SDHCI_REG(SDHCI_SRS15); + cap = SDHCI_REG(SDHCI_SRS16); + if (cap & SDHCI_SRS16_A64S) { + reg |= SDHCI_SRS15_A64; + reg |= SDHCI_SRS15_HV4E; + SDHCI_REG_SET(SDHCI_SRS15, reg); + } + /* Set all status enables - 0xbff40ff */ + SDHCI_REG_SET(SDHCI_SRS13, ( + SDHCI_SRS13_ETUNE_SE | SDHCI_SRS13_EADMA_SE | SDHCI_SRS13_EAC_SE | + SDHCI_SRS13_ECL_SE | SDHCI_SRS13_EDEB_SE | + SDHCI_SRS13_EDCRC_SE | SDHCI_SRS13_EDT_SE | + SDHCI_SRS13_ECI_SE | SDHCI_SRS13_ECEB_SE | SDHCI_SRS13_ECCRC_SE | + SDHCI_SRS13_ECT_SE | SDHCI_SRS13_RTUNE_SE | + SDHCI_SRS13_INT_ONC | SDHCI_SRS13_INT_ONB | SDHCI_SRS13_INT_ONA | + SDHCI_SRS13_CR_SE | SDHCI_SRS13_CIN_SE | + SDHCI_SRS13_BRR_SE | SDHCI_SRS13_BWR_SE | SDHCI_SRS13_DMAINT_SE | + SDHCI_SRS13_BGE_SE | SDHCI_SRS13_TC_SE | SDHCI_SRS13_CC_SE | + SDHCI_SRS13_ERSP_SE | SDHCI_SRS13_CQINT_SE + )); + /* Clear all signal enables (will be enabled per-transfer for SDMA) */ + SDHCI_REG_SET(SDHCI_SRS14, 0); + + /* Initialize platform interrupts (PLIC/NVIC/GIC/etc.) */ + sdhci_platform_irq_init(); + + /* Set initial timeout to 500ms */ + status = sdhci_set_timeout(SDHCI_INIT_TIMEOUT_US); + if (status != 0) { + return status; + } + /* Turn off host controller power */ + (void)sdhci_set_power(0); + + /* check if card inserted and stable */ + reg = SDHCI_REG(SDHCI_SRS09); + if ((reg & SDHCI_SRS09_CSS) == 0) { + /* card not inserted or not stable */ + return -1; + } +#ifdef DISK_SDCARD + /* For SD card: check if card is inserted + * (eMMC is soldered on board, skip this check) */ + if ((reg & SDHCI_SRS09_CI) == 0) { + /* card not inserted */ + return -1; + } +#endif + + /* Start in 1-bit bus mode */ + reg = SDHCI_REG(SDHCI_SRS10); + reg &= ~(SDHCI_SRS10_EDTW | SDHCI_SRS10_DTW); + SDHCI_REG_SET(SDHCI_SRS10, reg); + + /* Setup 400khz starting clock */ + sdhci_set_clock(SDHCI_CLK_400KHZ); + +#ifdef DISK_EMMC + /* ========================================================================= + * eMMC Initialization Path + * ========================================================================= */ + + /* Set power to 3.3v */ + status = sdhci_set_power(SDHCI_SRS10_BVS_3_3V); + if (status != 0) { + wolfBoot_printf("eMMC: Failed to set power\n"); + return status; + } + + /* Run full eMMC card initialization */ + status = emmc_card_full_init(); + if (status != 0) { + wolfBoot_printf("eMMC: Card initialization failed\n"); + return status; + } + +#else /* DISK_SDCARD */ + /* ========================================================================= + * SD Card Initialization Path + * ========================================================================= */ + + /* Run full SD card initialization */ + status = sdcard_card_full_init(); + if (status != 0) { + wolfBoot_printf("SD Card: Card initialization failed\n"); + return status; + } + +#endif /* DISK_EMMC */ + + /* Common finalization for both eMMC and SD */ + if (status == 0) { + /* Set data timeout to 3000ms */ + status = sdhci_set_timeout(SDHCI_DATA_TIMEOUT_US); + } + return status; +} + +/* ============================================================================ + * disk.h Interface + * ============================================================================ */ + +/* returns number of bytes read on success or negative on error */ +/* start may not be block aligned and count may not be block multiple */ +int disk_read(int drv, uint64_t start, uint32_t count, uint8_t *buf) +{ + int status = 0; + uint32_t read_sz, block_addr; + uint32_t tmp_block[SDHCI_BLOCK_SIZE/sizeof(uint32_t)]; + uint32_t start_offset = (start % SDHCI_BLOCK_SIZE); + (void)drv; /* only one drive supported */ + +#ifdef DEBUG_SDHCI + wolfBoot_printf("disk_read: drv:%d, start:%llu, count:%d, dst:%p\n", + drv, start, count, buf); +#endif + + while (count > 0) { + block_addr = (start / SDHCI_BLOCK_SIZE); + read_sz = count; + if (read_sz > SDHCI_BLOCK_SIZE) { + read_sz = SDHCI_BLOCK_SIZE; + } + if (read_sz < SDHCI_BLOCK_SIZE || /* last partial */ + start_offset != 0 || /* start not block aligned */ + ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ + { + /* block read to temporary buffer */ + status = sdhci_read(MMC_CMD17_READ_SINGLE, block_addr, + tmp_block, SDHCI_BLOCK_SIZE); + if (status == 0) { + uint8_t* tmp_buf = (uint8_t*)tmp_block; + memcpy(buf, tmp_buf + start_offset, read_sz); + start_offset = 0; + } + } + else { + /* direct full block(s) read */ + uint32_t blocks = (count / SDHCI_BLOCK_SIZE); + read_sz = (blocks * SDHCI_BLOCK_SIZE); + status = sdhci_read(blocks > 1 ? + MMC_CMD18_READ_MULTIPLE : + MMC_CMD17_READ_SINGLE, + block_addr, (uint32_t*)buf, read_sz); + } + if (status != 0) { + break; + } + + start += read_sz; + buf += read_sz; + count -= read_sz; + } + return status; +} + +int disk_write(int drv, uint64_t start, uint32_t count, const uint8_t *buf) +{ + int status = 0; + uint32_t write_sz, block_addr; + uint32_t tmp_block[SDHCI_BLOCK_SIZE/sizeof(uint32_t)]; + uint32_t start_offset = (start % SDHCI_BLOCK_SIZE); + (void)drv; /* only one drive supported */ + +#ifdef DEBUG_SDHCI + wolfBoot_printf("disk_write: drv:%d, start:%llu, count:%d, src:%p\n", + drv, start, count, buf); +#endif + + while (count > 0) { + block_addr = (start / SDHCI_BLOCK_SIZE); + write_sz = count; + if (write_sz > SDHCI_BLOCK_SIZE) { + write_sz = SDHCI_BLOCK_SIZE; + } + if (write_sz < SDHCI_BLOCK_SIZE || /* partial block */ + start_offset != 0 || /* start not block aligned */ + ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ + { + /* read-modify-write for partial block */ + status = sdhci_read(MMC_CMD17_READ_SINGLE, block_addr, + tmp_block, SDHCI_BLOCK_SIZE); + if (status == 0) { + uint8_t* tmp_buf = (uint8_t*)tmp_block; + memcpy(tmp_buf + start_offset, buf, write_sz); + status = sdhci_write(MMC_CMD24_WRITE_SINGLE, block_addr, + tmp_block, SDHCI_BLOCK_SIZE); + start_offset = 0; + } + } + else { + /* direct full block(s) write */ + uint32_t blocks = (count / SDHCI_BLOCK_SIZE); + write_sz = (blocks * SDHCI_BLOCK_SIZE); + status = sdhci_write(blocks > 1 ? + MMC_CMD25_WRITE_MULTIPLE : + MMC_CMD24_WRITE_SINGLE, + block_addr, (const uint32_t*)buf, write_sz); + } + if (status != 0) { + break; + } + + start += write_sz; + buf += write_sz; + count -= write_sz; + } + return status; +} + +#ifdef DISK_TEST + +/* disk_test: Test read/write functionality + * Tests sizes: 128, 512, 1024, 512KB (524288), 1MB (1048576) bytes + * Returns 0 on success, negative on failure */ +static int disk_test(int drv) +{ + int status = 0; + int test_num = 0; + uint32_t i; + static const uint32_t test_sizes[] = { + 128, /* partial block */ + 512, /* single block */ + 1024, /* two blocks */ + 512 * 1024, /* 512KB - DMA threshold */ + 1024 * 1024 /* 1MB */ + }; + /* Use platform-defined buffer address */ + uint32_t* tmp_buf32 = (uint32_t*)WOLFBOOT_LOAD_ADDRESS; + uint8_t* tmp_buf = (uint8_t*)tmp_buf32; + + wolfBoot_printf("disk_test: Starting tests at block %d (buf @ %p)\n", + DISK_TEST_BLOCK_ADDR, tmp_buf); + + for (test_num = 0; test_num < (int)(sizeof(test_sizes)/sizeof(test_sizes[0])); test_num++) { + uint32_t test_sz = test_sizes[test_num]; + uint64_t test_addr = (uint64_t)DISK_TEST_BLOCK_ADDR * SDHCI_BLOCK_SIZE; + uint32_t blocks_needed = (test_sz + SDHCI_BLOCK_SIZE - 1) / SDHCI_BLOCK_SIZE; + + wolfBoot_printf(" Test %d: size=%u bytes (%u blocks)... ", + test_num + 1, test_sz, blocks_needed); + + /* Fill with test pattern */ + for (i = 0; i < test_sz / sizeof(uint32_t); i++) { + tmp_buf32[i] = (test_num << 24) | i; + } + /* Handle remaining bytes for non-word-aligned sizes */ + for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { + tmp_buf[i] = (uint8_t)((test_num << 4) | (i & 0x0F)); + } + + /* Write */ + status = disk_write(drv, test_addr, test_sz, tmp_buf); + if (status != 0) { + wolfBoot_printf("FAIL (write error %d)\n", status); + continue; + } + + /* Clear buffer */ + memset(tmp_buf, 0, test_sz); + + /* Read back */ + status = disk_read(drv, test_addr, test_sz, tmp_buf); + if (status != 0) { + wolfBoot_printf("FAIL (read error %d)\n", status); + continue; + } + + /* Verify pattern */ + for (i = 0; i < test_sz / sizeof(uint32_t); i++) { + uint32_t expected = (test_num << 24) | i; + if (tmp_buf32[i] != expected) { + wolfBoot_printf("FAIL (verify @ word %u: got 0x%08X, expected 0x%08X)\n", + i, tmp_buf32[i], expected); + status = -1; + break; + } + } + /* Verify remaining bytes for non-word-aligned sizes */ + if (status == 0) { + for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { + uint8_t expected = (uint8_t)((test_num << 4) | (i & 0x0F)); + if (tmp_buf[i] != expected) { + wolfBoot_printf("FAIL (verify @ byte %u: got 0x%02X, expected 0x%02X)\n", + i, tmp_buf[i], expected); + status = -1; + break; + } + } + } + + if (status == 0) { + wolfBoot_printf("PASS\n"); + } + } + + wolfBoot_printf("disk_test: Complete\n"); + return status; +} +#endif /* DISK_TEST */ + +int disk_init(int drv) +{ + int r = sdhci_init(); + if (r != 0) { + wolfBoot_printf("Failed to initialize SDHCI\n"); + } + (void)drv; +#ifdef DISK_TEST + disk_test(drv); +#endif + return r; +} + +void disk_close(int drv) +{ + (void)drv; +} + +#endif /* DISK_SDCARD || DISK_EMMC */ + From cde69694d1124dd293d780110b1ee45ca314075d Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 31 Dec 2025 15:35:23 -0800 Subject: [PATCH 6/6] 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 32f1ee846f..f78c7095cf 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 4d24f630eb..2137cebf7f 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 fe32444412..36c3bda239 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)