drivers: dma: Add half complete callback for SF32LB chipset

Add callback of half complete in DMA processing, Fix DMA size bug.

Signed-off-by: Gang He <ganghe@sifli.com>
This commit is contained in:
Gang He
2025-11-24 13:41:29 +08:00
committed by Henrik Brix Andersen
parent 4d2af2647e
commit e724188a6f
2 changed files with 60 additions and 15 deletions

View File

@@ -44,6 +44,7 @@ LOG_MODULE_REGISTER(dma_sf32lb, CONFIG_DMA_LOG_LEVEL);
#define DMAC_CSELR2 offsetof(DMAC_TypeDef, CSELR2)
#define DMAC_ISR_TCIF(n) (DMAC_ISR_TCIF1_Msk << (n * 4U))
#define DMAC_ISR_HTIF(n) (DMAC_ISR_HTIF1_Msk << (n * 4U))
#define DMAC_IFCR_ALL(n) \
((DMAC_IFCR_CGIF1_Msk | DMAC_IFCR_CTCIF1_Msk | DMAC_IFCR_CHTIF1_Msk | \
@@ -51,6 +52,7 @@ LOG_MODULE_REGISTER(dma_sf32lb, CONFIG_DMA_LOG_LEVEL);
<< (n * 4U))
#define DMAC_IFCR_CTCIF(n) (DMAC_IFCR_CTCIF1_Msk << (n * 4U))
#define DMAC_IFCR_CTEIF(n) (DMAC_IFCR_CTEIF1_Msk << (n * 4U))
#define DMAC_IFCR_CTHIF(n) (DMAC_IFCR_CHTIF1_Msk << (n * 4U))
#define DMAC_CCRX_PSIZE(n) FIELD_PREP(DMAC_CCR1_PSIZE_Msk, LOG2CEIL(n))
#define DMAC_CCRX_MSIZE(n) FIELD_PREP(DMAC_CCR1_MSIZE_Msk, LOG2CEIL(n))
@@ -74,6 +76,7 @@ struct dma_sf32lb_config {
struct dma_sf32lb_channel {
dma_callback_t callback;
void *user_data;
uint32_t size;
enum dma_channel_direction direction;
};
@@ -93,12 +96,16 @@ static void dma_sf32lb_isr(const struct device *dev, uint8_t channel)
isr = sys_read32(config->dmac + DMAC_ISR);
if ((isr & DMAC_ISR_TCIF(channel)) != 0U) {
status = DMA_STATUS_COMPLETE;
} else if ((isr & DMAC_ISR_HTIF(channel)) != 0U) {
status = DMA_STATUS_HALF_COMPLETE;
atomic_clear_bit(data->status, channel);
} else {
} else if (isr) {
status = -EIO;
} else {
status = -EINPROGRESS;
}
if (config->channels[channel].callback) {
if (status != -EINPROGRESS && config->channels[channel].callback != NULL) {
config->channels[channel].callback(dev, config->channels[channel].user_data,
channel, status);
}
@@ -114,16 +121,9 @@ static void dma_sf32lb_isr(const struct device *dev, uint8_t channel)
LISTIFY(8, DMA_SF32LB_IRQ_DEFINE, ())
static int dma_sf32lb_config(const struct device *dev, uint32_t channel,
struct dma_config *config_dma)
static int check_dma_config(uint32_t channel, struct dma_config *config_dma,
const struct dma_sf32lb_config *config)
{
const struct dma_sf32lb_config *config = dev->config;
struct dma_sf32lb_data *data = dev->data;
uint32_t ccrx;
uint32_t cselrx;
uint32_t cparx;
uint32_t cm0arx;
if (channel >= config->n_channels) {
LOG_ERR("Invalid channel (%" PRIu32 ", max %" PRIu32 ")", channel,
config->n_channels);
@@ -174,6 +174,30 @@ static int dma_sf32lb_config(const struct device *dev, uint32_t channel,
return -EINVAL;
}
if (config_dma->dest_data_size != config_dma->source_data_size) {
LOG_ERR("Destination and source sizes not equal");
return -EINVAL;
}
return 0;
}
static int dma_sf32lb_config(const struct device *dev, uint32_t channel,
struct dma_config *config_dma)
{
int ret;
const struct dma_sf32lb_config *config = dev->config;
struct dma_sf32lb_data *data = dev->data;
uint32_t ccrx;
uint32_t cselrx;
uint32_t cparx;
uint32_t cm0arx;
ret = check_dma_config(channel, config_dma, config);
if (ret < 0) {
return ret;
}
/* configure transfer parameters */
ccrx = sys_read32(config->dmac + DMAC_CCRX(channel));
if ((ccrx & DMAC_CCR1_EN) != 0U) {
@@ -188,6 +212,14 @@ static int dma_sf32lb_config(const struct device *dev, uint32_t channel,
ccrx |= FIELD_PREP(DMAC_CCR1_PL_Msk, config_dma->channel_priority);
if (config_dma->head_block->dest_reload_en || config_dma->head_block->source_reload_en) {
ccrx |= DMAC_CCR1_CIRC;
}
if (config_dma->half_complete_callback_en) {
ccrx |= DMAC_CCR1_HTIE;
}
switch (config_dma->channel_direction) {
case MEMORY_TO_MEMORY:
ccrx |= DMAC_CCR1_MEM2MEM;
@@ -254,6 +286,7 @@ static int dma_sf32lb_config(const struct device *dev, uint32_t channel,
config->channels[channel].callback = config_dma->dma_callback;
config->channels[channel].user_data = config_dma->user_data;
config->channels[channel].direction = config_dma->channel_direction;
config->channels[channel].size = config_dma->source_data_size;
return 0;
}
@@ -284,6 +317,13 @@ static int dma_sf32lb_reload(const struct device *dev, uint32_t channel, uint32_
}
/* configure size, src/dst addresses */
if (config->channels[channel].size == 4) {
size >>= 2;
} else if (config->channels[channel].size == 2) {
size >>= 1;
} else {
}
sys_write32(size, config->dmac + DMAC_CNDTRX(channel));
switch (config->channels[channel].direction) {
@@ -321,7 +361,8 @@ static int dma_sf32lb_start(const struct device *dev, uint32_t channel)
ccrx = sys_read32(config->dmac + DMAC_CCRX(channel));
if ((ccrx & DMAC_CCR1_EN) != 0U) {
return 0;
LOG_ERR("start not possible with DMA enabled");
return -EIO;
}
/* clear all transfer flags */

View File

@@ -164,9 +164,11 @@ struct dma_block_config {
};
/** The DMA callback event has occurred at the completion of a transfer list */
#define DMA_STATUS_COMPLETE 0
#define DMA_STATUS_COMPLETE 0
/** The DMA callback has occurred at the completion of a single transfer block in a transfer list */
#define DMA_STATUS_BLOCK 1
#define DMA_STATUS_BLOCK 1
/** The DMA callback event has occurred at the half completion of a single transfer block */
#define DMA_STATUS_HALF_COMPLETE 2
/**
* @typedef dma_callback_t
@@ -208,6 +210,8 @@ struct dma_config {
* - others hardware specific
*/
uint32_t channel_direction : 3;
/** enable half completion callback when set to 1 */
uint32_t half_complete_callback_en : 1;
/**
* Completion callback enable
*
@@ -249,7 +253,7 @@ struct dma_config {
/** Cyclic transfer list, HW specific */
uint32_t cyclic : 1;
uint32_t _reserved : 3;
uint32_t _reserved : 2;
/** Width of source data (in bytes) */
uint32_t source_data_size : 16;
/** Width of destination data (in bytes) */