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:
committed by
Henrik Brix Andersen
parent
4d2af2647e
commit
e724188a6f
@@ -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 */
|
||||
|
||||
@@ -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) */
|
||||
|
||||
Reference in New Issue
Block a user