From 9d43b784b4dd021921696fe0393d8e875ea5f8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Fri, 17 Oct 2025 10:40:40 +0200 Subject: [PATCH 1/4] dts: bindings: vendor-prefixes: Add spinalhdl prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SpinalHDL vendor prefix. Signed-off-by: Fin Maaß --- dts/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index db92063114842..822e91247d199 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -655,6 +655,7 @@ solomon Solomon Systech Limited sony Sony Corporation spansion Spansion Inc. sparkfun SparkFun Electronics +spinalhdl SpinalHDL sprd Spreadtrum Communications Inc. sqn Sequans Communications sst Silicon Storage Technology, Inc. From 3d6b9d0f6e0dd6a20112d338c19c507b9177f857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 16 Oct 2025 12:50:01 +0200 Subject: [PATCH 2/4] arch: riscv: vexriscv: add VexRiscv cache driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add driver for VexRiscv CPU cache controller. Signed-off-by: Fin Maaß --- arch/riscv/custom/CMakeLists.txt | 1 + arch/riscv/custom/Kconfig | 6 + arch/riscv/custom/vexriscv/CMakeLists.txt | 4 + arch/riscv/custom/vexriscv/Kconfig | 9 ++ arch/riscv/custom/vexriscv/cache_vexriscv.c | 116 ++++++++++++++++++ dts/bindings/cpu/litex,vexriscv-standard.yaml | 8 +- dts/bindings/cpu/spinalhdl,vexriscv.yaml | 8 ++ dts/riscv/riscv32-litex-vexriscv.dtsi | 2 +- soc/litex/litex_vexriscv/Kconfig | 3 + 9 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 arch/riscv/custom/vexriscv/CMakeLists.txt create mode 100644 arch/riscv/custom/vexriscv/Kconfig create mode 100644 arch/riscv/custom/vexriscv/cache_vexriscv.c create mode 100644 dts/bindings/cpu/spinalhdl,vexriscv.yaml diff --git a/arch/riscv/custom/CMakeLists.txt b/arch/riscv/custom/CMakeLists.txt index fab46a8142a6c..ee166d7615a43 100644 --- a/arch/riscv/custom/CMakeLists.txt +++ b/arch/riscv/custom/CMakeLists.txt @@ -6,4 +6,5 @@ add_subdirectory_ifdef(CONFIG_DT_HAS_OPENHWGROUP_CVA6_ENABLED openhwgroup/cva6) add_subdirectory_ifdef(CONFIG_DT_HAS_NUCLEI_BUMBLEBEE_ENABLED nuclei) add_subdirectory_ifdef(CONFIG_DT_HAS_OPENISA_RI5CY_ENABLED openisa/ri5cy) add_subdirectory_ifdef(CONFIG_DT_HAS_OPENISA_ZERO_RI5CY_ENABLED openisa/zero_riscy) +add_subdirectory_ifdef(CONFIG_DT_HAS_SPINALHDL_VEXRISCV_ENABLED vexriscv) add_subdirectory_ifdef(CONFIG_DT_HAS_XUANTIE_E907_ENABLED thead) diff --git a/arch/riscv/custom/Kconfig b/arch/riscv/custom/Kconfig index e14abc77280d4..24b2b820fa088 100644 --- a/arch/riscv/custom/Kconfig +++ b/arch/riscv/custom/Kconfig @@ -7,6 +7,12 @@ rsource "andes/Kconfig" endif # DT_HAS_ANDESTECH_ANDESCORE_V5_ENABLED +if DT_HAS_SPINALHDL_VEXRISCV_ENABLED + +rsource "vexriscv/Kconfig" + +endif # DT_HAS_SPINALHDL_VEXRISCV_ENABLED + if DT_HAS_XUANTIE_E907_ENABLED rsource "thead/Kconfig" diff --git a/arch/riscv/custom/vexriscv/CMakeLists.txt b/arch/riscv/custom/vexriscv/CMakeLists.txt new file mode 100644 index 0000000000000..6e708a5df562c --- /dev/null +++ b/arch/riscv/custom/vexriscv/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_RISCV_CUSTOM_CSR_VEXRISCV_CACHE cache_vexriscv.c) diff --git a/arch/riscv/custom/vexriscv/Kconfig b/arch/riscv/custom/vexriscv/Kconfig new file mode 100644 index 0000000000000..18caf790dcd54 --- /dev/null +++ b/arch/riscv/custom/vexriscv/Kconfig @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config RISCV_CUSTOM_CSR_VEXRISCV_CACHE + bool + default y + depends on ARCH_CACHE + help + This option enables cache support for VexRiscv family of CPUs. diff --git a/arch/riscv/custom/vexriscv/cache_vexriscv.c b/arch/riscv/custom/vexriscv/cache_vexriscv.c new file mode 100644 index 0000000000000..1fc379db24723 --- /dev/null +++ b/arch/riscv/custom/vexriscv/cache_vexriscv.c @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifdef CONFIG_DCACHE +void arch_dcache_enable(void) +{ + /* Nothing */ +} + +void arch_dcache_disable(void) +{ + /* Nothing */ +} + +int arch_dcache_invd_all(void) +{ + __asm__ volatile(".insn 0x500F\n"); + + return 0; +} + +int arch_dcache_invd_range(void *addr, size_t size) +{ + __asm__ volatile( + "mv a0, %1\n" + "j 2f\n" + "3:\n" + ".insn 0x5500F\n" /* 0x500f | (a0 << 15) */ + "add a0, a0, %0\n" + "2:\n" + "bltu a0, %2, 3b\n" + : : "r"(CONFIG_DCACHE_LINE_SIZE), + "r"((unsigned int)(addr) & ~((CONFIG_DCACHE_LINE_SIZE) - 1UL)), + "r"((unsigned int)(addr) + (size)) + : "a0"); + + return 0; +} + + +int arch_dcache_flush_all(void) +{ + /* VexRiscv cache is write-through */ + return 0; +} + +int arch_dcache_flush_range(void *addr __unused, size_t size __unused) +{ + return 0; +} + +int arch_dcache_flush_and_invd_all(void) +{ + return arch_dcache_invd_all(); +} + +int arch_dcache_flush_and_invd_range(void *addr, size_t size) +{ + return arch_dcache_invd_range(addr, size); +} +#endif /* CONFIG_DCACHE */ + +#ifdef CONFIG_ICACHE +void arch_icache_enable(void) +{ + /* Nothing */ +} + +void arch_icache_disable(void) +{ + /* Nothing */ +} + +int arch_icache_flush_all(void) +{ + __asm__ volatile("fence.i\n"); + + return 0; +} + +int arch_icache_invd_all(void) +{ + return arch_icache_flush_all(); +} + +int arch_icache_invd_range(void *addr_in __unused, size_t size __unused) +{ + return arch_icache_flush_all(); +} + +int arch_icache_flush_and_invd_all(void) +{ + return arch_icache_flush_all(); +} + +int arch_icache_flush_range(void *addr __unused, size_t size __unused) +{ + return arch_icache_flush_all(); +} + +int arch_icache_flush_and_invd_range(void *addr __unused, size_t size __unused) +{ + return arch_icache_flush_all(); +} +#endif /* CONFIG_ICACHE */ + +void arch_cache_init(void) +{ + /* Nothing */ +} diff --git a/dts/bindings/cpu/litex,vexriscv-standard.yaml b/dts/bindings/cpu/litex,vexriscv-standard.yaml index 86de7c7a9c008..420e927f473c9 100644 --- a/dts/bindings/cpu/litex,vexriscv-standard.yaml +++ b/dts/bindings/cpu/litex,vexriscv-standard.yaml @@ -6,4 +6,10 @@ description: VexRiscv core with the standard configuration as used by LiteX compatible: "litex,vexriscv-standard" -include: riscv,cpus.yaml +include: spinalhdl,vexriscv.yaml + +properties: + i-cache-line-size: + default: 32 + d-cache-line-size: + default: 32 diff --git a/dts/bindings/cpu/spinalhdl,vexriscv.yaml b/dts/bindings/cpu/spinalhdl,vexriscv.yaml new file mode 100644 index 0000000000000..62901fc03def2 --- /dev/null +++ b/dts/bindings/cpu/spinalhdl,vexriscv.yaml @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: VexRiscv core + +compatible: "spinalhdl,vexriscv" + +include: riscv,cpus.yaml diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index 33f7bd03fc286..78a561ba77309 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -22,7 +22,7 @@ cpu0: cpu@0 { clock-frequency = <100000000>; - compatible = "litex,vexriscv-standard", "riscv"; + compatible = "litex,vexriscv-standard", "spinalhdl,vexriscv", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32im_zicsr_zifencei"; diff --git a/soc/litex/litex_vexriscv/Kconfig b/soc/litex/litex_vexriscv/Kconfig index 6a684f5c4ca9a..5543d09bbe724 100644 --- a/soc/litex/litex_vexriscv/Kconfig +++ b/soc/litex/litex_vexriscv/Kconfig @@ -8,6 +8,9 @@ config SOC_LITEX_VEXRISCV select RISCV_ISA_EXT_M select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI + # There are varriants of the Vexriscv without cache, be able to set it + select CPU_HAS_ICACHE if $(dt_node_int_prop_int,/cpus/cpu@0,i-cache-line-size) > 0 + select CPU_HAS_DCACHE if $(dt_node_int_prop_int,/cpus/cpu@0,d-cache-line-size) > 0 imply XIP if SOC_LITEX_VEXRISCV From cc70422c6d7079cc3f34fe54dcd046b5253b4559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 16 Oct 2025 20:34:06 +0200 Subject: [PATCH 3/4] drivers: sdhc: litex: add liteadcard driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add litex litesdcard driver. Signed-off-by: Fin Maaß --- drivers/sdhc/CMakeLists.txt | 1 + drivers/sdhc/Kconfig | 1 + drivers/sdhc/Kconfig.litex | 26 + drivers/sdhc/sdhc_litex_litesdcard.c | 520 +++++++++++++++++++ dts/bindings/sdhc/litex,litesdcard-sdhc.yaml | 20 + 5 files changed, 568 insertions(+) create mode 100644 drivers/sdhc/Kconfig.litex create mode 100644 drivers/sdhc/sdhc_litex_litesdcard.c create mode 100644 dts/bindings/sdhc/litex,litesdcard-sdhc.yaml diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index 1f9b95aba968e..c6b1d07b1df00 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c) zephyr_library_sources_ifdef(CONFIG_CDNS_SDHC sdhc_cdns_ll.c sdhc_cdns.c) zephyr_library_sources_ifdef(CONFIG_SDHC_ESP32 sdhc_esp32.c) zephyr_library_sources_ifdef(CONFIG_SDHC_RENESAS_RA sdhc_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_SDHC_LITEX_LITESDCARD sdhc_litex_litesdcard.c) zephyr_library_sources_ifdef(CONFIG_SDHC_MAX32 sdhc_max32.c) zephyr_library_sources_ifdef(CONFIG_SDHC_AMBIQ sdhc_ambiq.c) zephyr_library_sources_ifdef(CONFIG_XLNX_SDHC xlnx_sdhc.c) diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 475f2342a5633..9aa6139304cc4 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -19,6 +19,7 @@ source "drivers/sdhc/Kconfig.intel" source "drivers/sdhc/Kconfig.sdhc_cdns" source "drivers/sdhc/Kconfig.esp32" source "drivers/sdhc/Kconfig.renesas_ra" +source "drivers/sdhc/Kconfig.litex" source "drivers/sdhc/Kconfig.max32" source "drivers/sdhc/Kconfig.ambiq" source "drivers/sdhc/Kconfig.xlnx" diff --git a/drivers/sdhc/Kconfig.litex b/drivers/sdhc/Kconfig.litex new file mode 100644 index 0000000000000..72ae9feb010d7 --- /dev/null +++ b/drivers/sdhc/Kconfig.litex @@ -0,0 +1,26 @@ +# Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config SDHC_LITEX_LITESDCARD + bool "LiteX LiteSDCard SDHC driver" + default y + depends on DT_HAS_LITEX_LITESDCARD_SDHC_ENABLED + select SDHC_SUPPORTS_NATIVE_MODE + help + sdhc driver for LiteX LiteSDCard. + +if SDHC_LITEX_LITESDCARD + +configdefault SDHC_BUFFER_ALIGNMENT + default 4 + +config SDHC_LITEX_LITESDCARD_NO_COHERENT_DMA + bool "No coherent DMA bus, need cache management" + select CACHE_MANAGEMENT + depends on DCACHE + help + This needs to be enabled if the LiteSDCard Module is not connected + to a coherent DMA bus, meaning that the cache needs to be managed + before and after DMA operations. + +endif # SDHC_LITEX_LITESDCARD diff --git a/drivers/sdhc/sdhc_litex_litesdcard.c b/drivers/sdhc/sdhc_litex_litesdcard.c new file mode 100644 index 0000000000000..9ba948454540a --- /dev/null +++ b/drivers/sdhc/sdhc_litex_litesdcard.c @@ -0,0 +1,520 @@ +/* + * Copyright The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT litex_litesdcard_sdhc + +#include +#include +#include +#include +#include +#include +#include + + +LOG_MODULE_REGISTER(sdhc_litex, CONFIG_SDHC_LOG_LEVEL); + +#include + +#define SDCARD_CTRL_DATA_TRANSFER_NONE 0 +#define SDCARD_CTRL_DATA_TRANSFER_READ 1 +#define SDCARD_CTRL_DATA_TRANSFER_WRITE 2 + +#define SDCARD_CTRL_RESP_NONE 0 +#define SDCARD_CTRL_RESP_SHORT 1 +#define SDCARD_CTRL_RESP_LONG 2 +#define SDCARD_CTRL_RESP_SHORT_BUSY 3 +#define SDCARD_CTRL_RESP_CRC BIT(2) + +#define SDCARD_EV_CARD_DETECT_BIT 0 +#define SDCARD_EV_BLOCK2MEM_DMA_BIT 1 +#define SDCARD_EV_MEM2BLOCK_DMA_BIT 2 +#define SDCARD_EV_CMD_DONE_BIT 3 + +#define SDCARD_EV_CARD_DETECT BIT(SDCARD_EV_CARD_DETECT_BIT) +#define SDCARD_EV_BLOCK2MEM_DMA BIT(SDCARD_EV_BLOCK2MEM_DMA_BIT) +#define SDCARD_EV_MEM2BLOCK_DMA BIT(SDCARD_EV_MEM2BLOCK_DMA_BIT) +#define SDCARD_EV_CMD_DONE BIT(SDCARD_EV_CMD_DONE_BIT) + +#define SDCARD_CORE_EVENT_DONE_BIT 0 +#define SDCARD_CORE_EVENT_ERROR_BIT 1 +#define SDCARD_CORE_EVENT_TIMEOUT_BIT 2 +#define SDCARD_CORE_EVENT_CRC_ERROR_BIT 3 + +#define SDCARD_PHY_SETTINGS_PHY_SPEED_1X 0 +#define SDCARD_PHY_SETTINGS_PHY_SPEED_4X BIT(0) +#define SDCARD_PHY_SETTINGS_PHY_SPEED_8X BIT(1) + +struct sdhc_litex_data { + struct k_mutex lock; + struct k_sem cmd_done_sem; + struct k_sem dma_done_sem; + bool cmd23_not_supported; +}; + +struct sdhc_litex_config { + void (*irq_config_func)(void); + enum sdhc_bus_width bus_width; + mem_addr_t phy_card_detect_addr; + mem_addr_t phy_clocker_divider_addr; + mem_addr_t phy_init_initialize_addr; + mem_addr_t phy_cmdr_timeout_addr; + mem_addr_t phy_dataw_status_addr; + mem_addr_t phy_datar_timeout_addr; + mem_addr_t phy_settings_addr; + mem_addr_t core_cmd_argument_addr; + mem_addr_t core_cmd_command_addr; + mem_addr_t core_cmd_send_addr; + mem_addr_t core_cmd_response_addr; + mem_addr_t core_cmd_event_addr; + mem_addr_t core_data_event_addr; + mem_addr_t core_block_length_addr; + mem_addr_t core_block_count_addr; + mem_addr_t block2mem_dma_base_addr; + mem_addr_t block2mem_dma_length_addr; + mem_addr_t block2mem_dma_enable_addr; + mem_addr_t block2mem_dma_done_addr; + mem_addr_t mem2block_dma_base_addr; + mem_addr_t mem2block_dma_length_addr; + mem_addr_t mem2block_dma_enable_addr; + mem_addr_t mem2block_dma_done_addr; + mem_addr_t ev_status_addr; + mem_addr_t ev_pending_addr; + mem_addr_t ev_enable_addr; +}; + +#define DEV_CFG(_dev_) ((const struct sdhc_litex_config * const) (_dev_)->config) +#define DEV_DATA(_dev_) ((struct sdhc_litex_data * const) (_dev_)->data) + +static void set_clk_divider(const struct device *dev, enum sdhc_clock_speed speed) +{ + uint32_t divider = DIV_ROUND_UP(sys_clock_hw_cycles_per_sec(), speed); + + litex_write16(CLAMP(divider, 2, 256), DEV_CFG(dev)->phy_clocker_divider_addr); +} + +static int sdhc_litex_card_busy(const struct device *dev) +{ + const struct sdhc_litex_config *dev_config = dev->config; + + return !IS_BIT_SET(litex_read8(dev_config->core_cmd_event_addr), + SDCARD_CORE_EVENT_DONE_BIT) && + !IS_BIT_SET(litex_read8(dev_config->core_data_event_addr), + SDCARD_CORE_EVENT_DONE_BIT); +} + +static int litex_mmc_send_cmd(const struct device *dev, uint8_t cmd, uint8_t transfer, uint32_t arg, + uint32_t *response, uint8_t response_len) +{ + const struct sdhc_litex_config *dev_config = dev->config; + struct sdhc_litex_data *dev_data = dev->data; + uint8_t cmd_event; + + LOG_DBG("Requesting command: opcode=%d, transfer=%d, arg=0x%08x, response_len=%d", cmd, + transfer, arg, response_len); + + litex_write32(arg, dev_config->core_cmd_argument_addr); + litex_write32(cmd << 8 | transfer << 5 | response_len, dev_config->core_cmd_command_addr); + + k_sem_reset(&dev_data->cmd_done_sem); + + litex_write8(1, dev_config->core_cmd_send_addr); + + litex_write8(litex_read8(dev_config->ev_enable_addr) | SDCARD_EV_CMD_DONE, + dev_config->ev_enable_addr); + + k_sem_take(&dev_data->cmd_done_sem, K_FOREVER); + + if ((response_len != SDCARD_CTRL_RESP_NONE) && (response != NULL)) { + litex_read32_array(dev_config->core_cmd_response_addr, response, 4); + LOG_HEXDUMP_DBG(response, sizeof(uint32_t) * 4, "Response: "); + } + + cmd_event = litex_read8(dev_config->core_cmd_event_addr); + + if (IS_BIT_SET(cmd_event, SDCARD_CORE_EVENT_ERROR_BIT)) { + LOG_WRN("Command error for cmd %d", cmd); + return -EIO; + } + if (IS_BIT_SET(cmd_event, SDCARD_CORE_EVENT_TIMEOUT_BIT)) { + LOG_WRN("Command timeout for cmd %d", cmd); + return -ETIMEDOUT; + } + if (IS_BIT_SET(cmd_event, SDCARD_CORE_EVENT_CRC_ERROR_BIT)) { + LOG_WRN("Command CRC error for cmd %d", cmd); + return -EILSEQ; + } + + return 0; +} + +static int sdhc_litex_wait_for_dma(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data, uint8_t *transfer) +{ + const struct sdhc_litex_config *dev_config = dev->config; + struct sdhc_litex_data *dev_data = dev->data; + uint8_t data_event; + + if (dev_data->cmd23_not_supported && (data->blocks > 1)) { + uint8_t response_len = SDCARD_CTRL_RESP_CRC; + + response_len |= (*transfer == SDCARD_CTRL_DATA_TRANSFER_READ) + ? SDCARD_CTRL_RESP_SHORT + : SDCARD_CTRL_RESP_SHORT_BUSY; + + litex_mmc_send_cmd(dev, SD_STOP_TRANSMISSION, SDCARD_CTRL_DATA_TRANSFER_NONE, + data->blocks, NULL, response_len); + } + + k_sem_take(&dev_data->dma_done_sem, K_FOREVER); + + data_event = litex_read8(dev_config->core_data_event_addr); + + if (IS_BIT_SET(data_event, SDCARD_CORE_EVENT_ERROR_BIT)) { + LOG_WRN("Data error"); + return -EIO; + } + if (IS_BIT_SET(data_event, SDCARD_CORE_EVENT_TIMEOUT_BIT)) { + LOG_WRN("Data timeout"); + return -ETIMEDOUT; + } + if (IS_BIT_SET(data_event, SDCARD_CORE_EVENT_CRC_ERROR_BIT)) { + LOG_WRN("Data CRC error"); + return -EILSEQ; + } + + if (IS_ENABLED(CONFIG_SDHC_LITEX_LITESDCARD_NO_COHERENT_DMA) && + (*transfer == SDCARD_CTRL_DATA_TRANSFER_READ)) { + sys_cache_data_invd_range(data->data, data->block_size * data->blocks); + } + + return 0; +} + +static void sdhc_litex_prepare_dma(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data, uint8_t *transfer) +{ + const struct sdhc_litex_config *dev_config = dev->config; + + litex_write32(data->timeout_ms * (sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC), + dev_config->phy_datar_timeout_addr); + + switch (cmd->opcode) { + case SD_WRITE_SINGLE_BLOCK: + case SD_WRITE_MULTIPLE_BLOCK: + *transfer = SDCARD_CTRL_DATA_TRANSFER_WRITE; + if (IS_ENABLED(CONFIG_SDHC_LITEX_LITESDCARD_NO_COHERENT_DMA)) { + sys_cache_data_flush_range(data->data, data->block_size * data->blocks); + } + litex_write8(0, dev_config->mem2block_dma_enable_addr); + litex_write64((uint64_t)(uintptr_t)(data->data), + dev_config->mem2block_dma_base_addr); + litex_write32(data->block_size * data->blocks, + dev_config->mem2block_dma_length_addr); + break; + default: + *transfer = SDCARD_CTRL_DATA_TRANSFER_READ; + litex_write8(0, dev_config->block2mem_dma_enable_addr); + litex_write64((uint64_t)(uintptr_t)(data->data), + dev_config->block2mem_dma_base_addr); + litex_write32(data->block_size * data->blocks, + dev_config->block2mem_dma_length_addr); + break; + } + + litex_write16(data->block_size, dev_config->core_block_length_addr); + litex_write32(data->blocks, dev_config->core_block_count_addr); +} + +static void sdhc_litex_do_dma(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data, uint8_t *transfer) +{ + const struct sdhc_litex_config *dev_config = dev->config; + struct sdhc_litex_data *dev_data = dev->data; + + LOG_DBG("Setting up DMA for command: opcode=%d, arg=0x%08x, blocks=%d, block_size=%d", + cmd->opcode, cmd->arg, data->blocks, data->block_size); + + if (!dev_data->cmd23_not_supported && (data->blocks > 1)) { + litex_mmc_send_cmd(dev, SD_SET_BLOCK_COUNT, SDCARD_CTRL_DATA_TRANSFER_NONE, + data->blocks, NULL, + SDCARD_CTRL_RESP_SHORT | SDCARD_CTRL_RESP_CRC); + } + + k_sem_reset(&dev_data->dma_done_sem); + + if (*transfer == SDCARD_CTRL_DATA_TRANSFER_WRITE) { + litex_write8(0, dev_config->mem2block_dma_enable_addr); + litex_write8(1, dev_config->mem2block_dma_enable_addr); + } else { + litex_write8(0, dev_config->block2mem_dma_enable_addr); + litex_write8(1, dev_config->block2mem_dma_enable_addr); + } +} + +static inline void sdhc_litex_check_cmd23_support(const struct device *dev, struct sdhc_data *data) +{ + struct sdhc_litex_data *dev_data = dev->data; + uint32_t *scr = data->data; + + dev_data->cmd23_not_supported = (sys_be32_to_cpu(scr[0]) & BIT(1)) == 0U; + + LOG_INF("CMD23 is%s supported", dev_data->cmd23_not_supported ? " not" : ""); +} + +static int sdhc_litex_request(const struct device *dev, struct sdhc_command *cmd, + struct sdhc_data *data) +{ + const struct sdhc_litex_config *dev_config = dev->config; + struct sdhc_litex_data *dev_data = dev->data; + uint8_t transfer = SDCARD_CTRL_DATA_TRANSFER_NONE; + uint8_t response_len; + unsigned int tries = 0; + int ret = 0; + + k_mutex_lock(&dev_data->lock, K_FOREVER); + + litex_write32(cmd->timeout_ms * (sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC), + dev_config->phy_cmdr_timeout_addr); + + if (cmd->opcode == SD_GO_IDLE_STATE) { + litex_write8(BIT(0), dev_config->phy_init_initialize_addr); + k_sleep(K_MSEC(1)); + } + + switch (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK) { + case SD_RSP_TYPE_NONE: + response_len = SDCARD_CTRL_RESP_NONE; + break; + case SD_RSP_TYPE_R1b: + response_len = SDCARD_CTRL_RESP_SHORT_BUSY | SDCARD_CTRL_RESP_CRC; + break; + case SD_RSP_TYPE_R2: + response_len = SDCARD_CTRL_RESP_LONG | SDCARD_CTRL_RESP_CRC; + break; + case SD_RSP_TYPE_R3: + case SD_RSP_TYPE_R4: + response_len = SDCARD_CTRL_RESP_SHORT; + break; + default: + response_len = SDCARD_CTRL_RESP_SHORT | SDCARD_CTRL_RESP_CRC; + break; + } + + if (data != NULL) { + sdhc_litex_prepare_dma(dev, cmd, data, &transfer); + } + + do { + + if (data != NULL) { + sdhc_litex_do_dma(dev, cmd, data, &transfer); + } + + do { + ret = litex_mmc_send_cmd(dev, cmd->opcode, transfer, cmd->arg, + cmd->response, response_len); + if (ret == 0) { + break; + } + tries++; + } while (tries <= cmd->retries); + + if (data == NULL || ret < 0) { + break; /* No data transfer, exit loop */ + } + + ret = sdhc_litex_wait_for_dma(dev, cmd, data, &transfer); + if (ret == 0) { + if ((cmd->opcode == SD_APP_SEND_SCR) && + (cmd->response[0] & SD_R1_APP_CMD)) { + sdhc_litex_check_cmd23_support(dev, data); + } + break; + } + + tries++; + } while (tries <= cmd->retries); + + k_mutex_unlock(&dev_data->lock); + + return ret; +} + +static int sdhc_litex_get_card_present(const struct device *dev) +{ + int ret = IS_BIT_SET(litex_read8(DEV_CFG(dev)->phy_card_detect_addr), 0) ? 0 : 1; + + LOG_DBG("Card present check: %s present", ret ? "" : "not"); + + return ret; +} + +static int sdhc_litex_get_host_props(const struct device *dev, struct sdhc_host_props *props) +{ + const struct sdhc_litex_config *dev_config = dev->config; + + memset(props, 0, sizeof(struct sdhc_host_props)); + + props->f_min = sys_clock_hw_cycles_per_sec() / 256; + props->f_max = sys_clock_hw_cycles_per_sec() / 2; + props->is_spi = 0; + props->max_current_180 = 0; + props->max_current_300 = 0; + props->max_current_330 = 0; + props->host_caps.timeout_clk_freq = 0x01; + props->host_caps.timeout_clk_unit = 1; + props->host_caps.bus_8_bit_support = dev_config->bus_width >= SDHC_BUS_WIDTH8BIT; + props->host_caps.bus_4_bit_support = dev_config->bus_width >= SDHC_BUS_WIDTH4BIT; + props->host_caps.high_spd_support = true; + props->host_caps.vol_330_support = true; + props->host_caps.vol_300_support = false; + props->host_caps.vol_180_support = false; + props->host_caps.sdr50_support = true; + props->host_caps.sdr104_support = true; + props->host_caps.ddr50_support = false; + props->host_caps.uhs_2_support = false; + props->host_caps.drv_type_a_support = true; + props->host_caps.drv_type_c_support = true; + props->host_caps.drv_type_d_support = true; + + LOG_INF("SDHC LiteX driver properties: " + "f_min=%d, f_max=%d, bus_width=%d, 4/8-bit support=%d/%d", + props->f_min, props->f_max, dev_config->bus_width, + props->host_caps.bus_4_bit_support, props->host_caps.bus_8_bit_support); + + return 0; +} + +static int sdhc_litex_set_io(const struct device *dev, struct sdhc_io *ios) +{ + const struct sdhc_litex_config *dev_config = dev->config; + enum sdhc_clock_speed speed = ios->clock; + uint8_t phy_settings = 0; + + if (speed) { + set_clk_divider(dev, speed); + } + + if (ios->bus_width) { + if (ios->bus_width > dev_config->bus_width) { + LOG_ERR("Bus width range error %d", ios->bus_width); + return -ENOTSUP; + } + + switch (ios->bus_width) { + case SDHC_BUS_WIDTH4BIT: + phy_settings = SDCARD_PHY_SETTINGS_PHY_SPEED_4X; + break; + case SDHC_BUS_WIDTH8BIT: + phy_settings = SDCARD_PHY_SETTINGS_PHY_SPEED_8X; + break; + + default: + phy_settings = SDCARD_PHY_SETTINGS_PHY_SPEED_1X; + break; + } + + litex_write8(phy_settings, dev_config->phy_settings_addr); + } + + return 0; +} + +static DEVICE_API(sdhc, sdhc_litex_driver_api) = { + .request = sdhc_litex_request, + .set_io = sdhc_litex_set_io, + .get_card_present = sdhc_litex_get_card_present, + .card_busy = sdhc_litex_card_busy, + .get_host_props = sdhc_litex_get_host_props, +}; + +static int sdhc_litex_init(const struct device *dev) +{ + const struct sdhc_litex_config *dev_config = dev->config; + + LOG_DBG("Initializing SDHC LiteX driver"); + + litex_write8(UINT8_MAX, dev_config->ev_pending_addr); + litex_write8(0, dev_config->ev_enable_addr); + + dev_config->irq_config_func(); + + litex_write8(SDCARD_EV_BLOCK2MEM_DMA | SDCARD_EV_MEM2BLOCK_DMA, dev_config->ev_enable_addr); + + litex_write8(SDCARD_PHY_SETTINGS_PHY_SPEED_1X, dev_config->phy_settings_addr); + + return 0; +} + +static void sdhc_litex_irq_handler(const struct device *dev) +{ + struct sdhc_litex_data *dev_data = dev->data; + const struct sdhc_litex_config *dev_config = dev->config; + uint8_t ev_enable = litex_read8(dev_config->ev_enable_addr); + uint8_t ev_pending = litex_read8(dev_config->ev_pending_addr) & ev_enable; + + if (IS_BIT_SET(ev_pending, SDCARD_EV_CMD_DONE_BIT)) { + k_sem_give(&dev_data->cmd_done_sem); + litex_write8(ev_enable & ~SDCARD_EV_CMD_DONE, dev_config->ev_enable_addr); + } + + if (IS_BIT_SET(ev_pending, SDCARD_EV_BLOCK2MEM_DMA_BIT) || + IS_BIT_SET(ev_pending, SDCARD_EV_MEM2BLOCK_DMA_BIT)) { + k_sem_give(&dev_data->dma_done_sem); + } + + litex_write8(ev_pending, dev_config->ev_pending_addr); +} + +#define DEFINE_SDHC_LITEX(n) \ + static void sdhc_litex_irq_config##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), sdhc_litex_irq_handler, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + }; \ + static struct sdhc_litex_data sdhc_litex_data_##n = { \ + .lock = Z_MUTEX_INITIALIZER(sdhc_litex_data_##n.lock), \ + .cmd_done_sem = Z_SEM_INITIALIZER(sdhc_litex_data_##n.cmd_done_sem, 0, 1), \ + .dma_done_sem = Z_SEM_INITIALIZER(sdhc_litex_data_##n.dma_done_sem, 0, 1), \ + }; \ + static const struct sdhc_litex_config sdhc_litex_config_##n = { \ + .irq_config_func = sdhc_litex_irq_config##n, \ + .bus_width = (enum sdhc_bus_width)DT_INST_PROP(n, bus_width), \ + .phy_card_detect_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_card_detect), \ + .phy_clocker_divider_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_clocker_divider), \ + .phy_init_initialize_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_init_initialize), \ + .phy_cmdr_timeout_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_cmdr_timeout), \ + .phy_dataw_status_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_dataw_status), \ + .phy_datar_timeout_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_datar_timeout), \ + .phy_settings_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_settings), \ + .core_cmd_argument_addr = DT_INST_REG_ADDR_BY_NAME(n, core_cmd_argument), \ + .core_cmd_command_addr = DT_INST_REG_ADDR_BY_NAME(n, core_cmd_command), \ + .core_cmd_send_addr = DT_INST_REG_ADDR_BY_NAME(n, core_cmd_send), \ + .core_cmd_response_addr = DT_INST_REG_ADDR_BY_NAME(n, core_cmd_response), \ + .core_cmd_event_addr = DT_INST_REG_ADDR_BY_NAME(n, core_cmd_event), \ + .core_data_event_addr = DT_INST_REG_ADDR_BY_NAME(n, core_data_event), \ + .core_block_length_addr = DT_INST_REG_ADDR_BY_NAME(n, core_block_length), \ + .core_block_count_addr = DT_INST_REG_ADDR_BY_NAME(n, core_block_count), \ + .block2mem_dma_base_addr = DT_INST_REG_ADDR_BY_NAME(n, block2mem_dma_base), \ + .block2mem_dma_length_addr = DT_INST_REG_ADDR_BY_NAME(n, block2mem_dma_length), \ + .block2mem_dma_enable_addr = DT_INST_REG_ADDR_BY_NAME(n, block2mem_dma_enable), \ + .block2mem_dma_done_addr = DT_INST_REG_ADDR_BY_NAME(n, block2mem_dma_done), \ + .mem2block_dma_base_addr = DT_INST_REG_ADDR_BY_NAME(n, mem2block_dma_base), \ + .mem2block_dma_length_addr = DT_INST_REG_ADDR_BY_NAME(n, mem2block_dma_length), \ + .mem2block_dma_enable_addr = DT_INST_REG_ADDR_BY_NAME(n, mem2block_dma_enable), \ + .mem2block_dma_done_addr = DT_INST_REG_ADDR_BY_NAME(n, mem2block_dma_done), \ + .ev_status_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_status), \ + .ev_pending_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_pending), \ + .ev_enable_addr = DT_INST_REG_ADDR_BY_NAME(n, ev_enable), \ + }; \ + DEVICE_DT_INST_DEFINE(n, sdhc_litex_init, NULL, &sdhc_litex_data_##n, \ + &sdhc_litex_config_##n, POST_KERNEL, CONFIG_SDHC_INIT_PRIORITY, \ + &sdhc_litex_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_SDHC_LITEX) diff --git a/dts/bindings/sdhc/litex,litesdcard-sdhc.yaml b/dts/bindings/sdhc/litex,litesdcard-sdhc.yaml new file mode 100644 index 0000000000000..e00a041196a89 --- /dev/null +++ b/dts/bindings/sdhc/litex,litesdcard-sdhc.yaml @@ -0,0 +1,20 @@ +# Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: LiteX SDHC + +compatible: "litex,litesdcard-sdhc" + +include: [sdhc.yaml] + +properties: + bus-width: + type: int + enum: + - 1 + - 4 + - 8 + default: 4 + + interrupts: + required: true From 6a02a389e2215a6c7081202f246092b8013bd073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 16 Oct 2025 20:36:08 +0200 Subject: [PATCH 4/4] boards: litex: litex_vexriscv: add litesdcard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add litesdcard host controller. Signed-off-by: Fin Maaß --- .../litex_vexriscv/Kconfig.defconfig | 7 +- .../litex_vexriscv/litex_vexriscv.dts | 74 +++++++++++++++++++ .../litex_vexriscv/litex_vexriscv.yaml | 1 + 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/boards/enjoydigital/litex_vexriscv/Kconfig.defconfig b/boards/enjoydigital/litex_vexriscv/Kconfig.defconfig index f48e777e7a740..b5ac7b1b9785c 100644 --- a/boards/enjoydigital/litex_vexriscv/Kconfig.defconfig +++ b/boards/enjoydigital/litex_vexriscv/Kconfig.defconfig @@ -3,11 +3,10 @@ if BOARD_LITEX_VEXRISCV -if NETWORKING - -config NET_L2_ETHERNET +configdefault NET_L2_ETHERNET default y -endif # NETWORKING +configdefault SDHC_LITEX_LITESDCARD_NO_COHERENT_DMA + default y endif # BOARD_LITEX_VEXRISCV diff --git a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts index 4f94a15fad6ba..eed48bd9c03a4 100644 --- a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts +++ b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.dts @@ -26,6 +26,80 @@ device_type = "memory"; reg = <0x40000000 0x10000000>; }; + + soc { + sdhc0: sdhc@e000e800 { + compatible = "litex,litesdcard-sdhc"; + interrupt-parent = <&intc0>; + reg = <0xe000e800 0x4>, + <0xe000e804 0x4>, + <0xe000e808 0x4>, + <0xe000e80c 0x4>, + <0xe000e810 0x4>, + <0xe000e814 0x4>, + <0xe000e818 0x4>, + <0xe000e81c 0x4>, + <0xe000e820 0x4>, + <0xe000e824 0x4>, + <0xe000e828 0x10>, + <0xe000e838 0x4>, + <0xe000e83c 0x4>, + <0xe000e840 0x4>, + <0xe000e844 0x4>, + <0xe000e848 0x8>, + <0xe000e850 0x4>, + <0xe000e854 0x4>, + <0xe000e858 0x4>, + <0xe000e85c 0x4>, + <0xe000e860 0x4>, + <0xe000e864 0x8>, + <0xe000e86c 0x4>, + <0xe000e870 0x4>, + <0xe000e874 0x4>, + <0xe000e878 0x4>, + <0xe000e87c 0x4>, + <0xe000e880 0x4>, + <0xe000e884 0x4>, + <0xe000e888 0x4>; + reg-names = "phy_card_detect", + "phy_clocker_divider", + "phy_init_initialize", + "phy_cmdr_timeout", + "phy_dataw_status", + "phy_datar_timeout", + "phy_settings", + "core_cmd_argument", + "core_cmd_command", + "core_cmd_send", + "core_cmd_response", + "core_cmd_event", + "core_data_event", + "core_block_length", + "core_block_count", + "block2mem_dma_base", + "block2mem_dma_length", + "block2mem_dma_enable", + "block2mem_dma_done", + "block2mem_dma_loop", + "block2mem_dma_offset", + "mem2block_dma_base", + "mem2block_dma_length", + "mem2block_dma_enable", + "mem2block_dma_done", + "mem2block_dma_loop", + "mem2block_dma_offset", + "ev_status", + "ev_pending", + "ev_enable"; + interrupts = <5 1>; + status = "okay"; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + disk-name = "SD"; + }; + }; + }; }; &ctrl0 { diff --git a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml index b0dcc5b14a1ab..89271c4888418 100644 --- a/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml +++ b/boards/enjoydigital/litex_vexriscv/litex_vexriscv.yaml @@ -15,6 +15,7 @@ supported: - gpio - uart - spi + - sdhc - i2s - i2c - watchdog