/* * SPDX-License-Identifier: Apache-2.0 * Copyright (c) 2024 sensry.io */ #include "soc.h" #include "udma.h" #define SY1XX_UDMA_CTRL_PER_CG (SY1XX_ARCHI_UDMA_ADDR + SY1XX_UDMA_CONF_OFFSET) #define SY1XX_MAX_UART_COUNT 3 #define SY1XX_MAX_I2C_COUNT 4 #define SY1XX_MAX_SPI_COUNT 7 #define SY1XX_MAX_ETH_COUNT 1 void sy1xx_udma_enable_clock(sy1xx_udma_module_t module, uint32_t instance) { uint32_t udma_ctrl_per_cg = sys_read32(SY1XX_UDMA_CTRL_PER_CG); switch (module) { case SY1XX_UDMA_MODULE_UART: if (instance >= SY1XX_MAX_UART_COUNT) { return; } udma_ctrl_per_cg |= 1 << (instance + 0); break; case SY1XX_UDMA_MODULE_I2C: if (instance >= SY1XX_MAX_I2C_COUNT) { return; } udma_ctrl_per_cg |= 1 << (instance + 10); break; case SY1XX_UDMA_MODULE_SPI: if (instance >= SY1XX_MAX_SPI_COUNT) { return; } udma_ctrl_per_cg |= 1 << (instance + 3); break; case SY1XX_UDMA_MODULE_MAC: if (instance >= SY1XX_MAX_ETH_COUNT) { return; } udma_ctrl_per_cg |= 1 << (instance + 20); break; case SY1XX_UDMA_MAX_MODULE_COUNT: break; } sys_write32(udma_ctrl_per_cg, SY1XX_UDMA_CTRL_PER_CG); } void sy1xx_udma_disable_clock(sy1xx_udma_module_t module, uint32_t instance) { uint32_t udma_ctrl_per_cg = sys_read32(SY1XX_UDMA_CTRL_PER_CG); switch (module) { case SY1XX_UDMA_MODULE_UART: if (instance >= SY1XX_MAX_UART_COUNT) { return; } udma_ctrl_per_cg &= ~(1 << (instance + 0)); break; case SY1XX_UDMA_MODULE_I2C: if (instance >= SY1XX_MAX_I2C_COUNT) { return; } udma_ctrl_per_cg &= ~(1 << (instance + 10)); break; case SY1XX_UDMA_MODULE_SPI: if (instance >= SY1XX_MAX_SPI_COUNT) { return; } udma_ctrl_per_cg &= ~(1 << (instance + 3)); break; case SY1XX_UDMA_MODULE_MAC: if (instance >= SY1XX_MAX_ETH_COUNT) { return; } udma_ctrl_per_cg &= ~(1 << (instance + 20)); break; case SY1XX_UDMA_MAX_MODULE_COUNT: break; } sys_write32(udma_ctrl_per_cg, SY1XX_UDMA_CTRL_PER_CG); } void sy1xx_udma_busy_delay(uint32_t msec) { uint32_t sec = 250000000; uint32_t millis = (sec / 1000) * msec; for (uint32_t i = 0; i < millis; i++) { __asm__("nop"); } } int32_t sy1xx_udma_cancel(uint32_t base, uint32_t channel) { uint32_t channel_offset = channel == 0 ? 0x00 : 0x10; /* clear existing */ SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_CFG_REG + channel_offset, SY1XX_UDMA_CHANNEL_CFG_CLEAR); return 0; } int32_t sy1xx_udma_is_ready(uint32_t base, uint32_t channel) { uint32_t channel_offset = channel == 0 ? 0x00 : 0x10; int32_t isBusy = SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_CFG_REG + channel_offset) & (SY1XX_UDMA_CHANNEL_CFG_EN); return isBusy ? 0 : 1; } int32_t sy1xx_udma_wait_for_finished(uint32_t base, uint32_t channel) { uint32_t channel_offset = channel == 0 ? 0x00 : 0x10; volatile uint32_t timeout = 200; while (SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_CFG_REG + channel_offset) & (SY1XX_UDMA_CHANNEL_CFG_EN)) { sy1xx_udma_busy_delay(1); timeout--; if (timeout == 0) { return -1; } } return 0; } int32_t sy1xx_udma_wait_for_status(uint32_t base) { volatile uint32_t timeout = 200; while (SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_STATUS) & (0x3)) { sy1xx_udma_busy_delay(1); timeout--; if (timeout == 0) { return -1; } } return 0; } int32_t sy1xx_udma_start(uint32_t base, uint32_t channel, uint32_t saddr, uint32_t size, uint32_t optional_cfg) { uint32_t channel_offset = channel == 0 ? 0x00 : 0x10; SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_SADDR_REG + channel_offset, saddr); SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_SIZE_REG + channel_offset, size); SY1XX_UDMA_WRITE_REG(base, SY1XX_UDMA_CFG_REG + channel_offset, SY1XX_UDMA_CHANNEL_CFG_EN | optional_cfg); return 0; } int32_t sy1xx_udma_get_remaining(uint32_t base, uint32_t channel) { uint32_t channel_offset = channel == 0 ? 0x00 : 0x10; int32_t size = SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_SIZE_REG + channel_offset); return size; }