From 3e9c6bc9939771ea0eced7076b460d5257ee77cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Tue, 21 Apr 2026 10:32:08 +0200 Subject: [PATCH 1/8] imx6ull-sdma: add missing const TASK: MSH-36 --- dma/imx6ull-sdma/libsdma.c | 4 ++-- dma/imx6ull-sdma/sdma-api.h | 1 + dma/imx6ull-sdma/sdma.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dma/imx6ull-sdma/libsdma.c b/dma/imx6ull-sdma/libsdma.c index f5f1b0eef..b5273ad1b 100644 --- a/dma/imx6ull-sdma/libsdma.c +++ b/dma/imx6ull-sdma/libsdma.c @@ -80,7 +80,7 @@ int sdma_channel_configure(sdma_t *s, sdma_channel_config_t *cfg) return sdma_dev_ctl(s, &dev_ctl, NULL, 0); } -int sdma_data_mem_write(sdma_t *s, void *data, size_t size, addr_t addr) +int sdma_data_mem_write(sdma_t *s, const void *data, size_t size, addr_t addr) { sdma_dev_ctl_t dev_ctl; @@ -88,7 +88,7 @@ int sdma_data_mem_write(sdma_t *s, void *data, size_t size, addr_t addr) dev_ctl.mem.addr = addr; dev_ctl.mem.len = size; - return sdma_dev_ctl(s, &dev_ctl, data, size); + return sdma_dev_ctl(s, &dev_ctl, (void *)data, size); } int sdma_data_mem_read(sdma_t *s, void *data, size_t size, addr_t addr) diff --git a/dma/imx6ull-sdma/sdma-api.h b/dma/imx6ull-sdma/sdma-api.h index 7baecdf3a..3a4bfbecf 100644 --- a/dma/imx6ull-sdma/sdma-api.h +++ b/dma/imx6ull-sdma/sdma-api.h @@ -124,6 +124,7 @@ typedef enum { sdma_dev_ctl__ocram_alloc } sdma_dev_ctl_type_t; +/* TODO: use separate types for input/output devctl and remove msg.o being used for input data (both raw and data) */ typedef struct { sdma_dev_ctl_type_t type; diff --git a/dma/imx6ull-sdma/sdma.h b/dma/imx6ull-sdma/sdma.h index 12cc3fbd5..fef5b7356 100644 --- a/dma/imx6ull-sdma/sdma.h +++ b/dma/imx6ull-sdma/sdma.h @@ -25,7 +25,7 @@ int sdma_close(sdma_t *s); int sdma_channel_configure(sdma_t *s, sdma_channel_config_t *cfg); -int sdma_data_mem_write(sdma_t *s, void *data, size_t size, addr_t addr); +int sdma_data_mem_write(sdma_t *s, const void *data, size_t size, addr_t addr); int sdma_data_mem_read(sdma_t *s, void *data, size_t size, addr_t addr); int sdma_context_dump(sdma_t *s, sdma_context_t *ctx); From a2c2c39a88f6895d5d79852240ff40f61ce72b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Tue, 21 Apr 2026 10:32:49 +0200 Subject: [PATCH 2/8] imx6ull-sdma: format TASK: MSH-36 --- dma/imx6ull-sdma/imx6ull-sdma.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index 239a72b65..3b2f177cc 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -339,30 +339,22 @@ static int sdma_free_uncached(void *vaddr, size_t size) return munmap(vaddr, n*_PAGE_SIZE); } -static int __attribute__((unused)) sdma_program_memory_dump(uint16_t addr, - addr_t buffer, - size_t size) +static int __attribute__((unused)) sdma_program_memory_dump(uint16_t addr, addr_t buffer, size_t size) { return sdma_run_channel0_cmd(size, SDMA_CMD_C0_GET_PM, buffer, addr); } -static int __attribute__((unused)) sdma_program_memory_write(uint16_t addr, - addr_t buffer, - size_t size) +static int __attribute__((unused)) sdma_program_memory_write(uint16_t addr, addr_t buffer, size_t size) { return sdma_run_channel0_cmd(size, SDMA_CMD_C0_SET_PM, buffer, addr); } -static int sdma_data_memory_dump(uint16_t addr, - addr_t buffer, - size_t size) +static int sdma_data_memory_dump(uint16_t addr, addr_t buffer, size_t size) { return sdma_run_channel0_cmd(size, SDMA_CMD_C0_GET_DM, buffer, addr); } -static int sdma_data_memory_write(uint16_t addr, - addr_t buffer, - size_t size) +static int sdma_data_memory_write(uint16_t addr, addr_t buffer, size_t size) { return sdma_run_channel0_cmd(size, SDMA_CMD_C0_SET_DM, buffer, addr); } From 9100f203e8db46b987b6abffdf825e0270cb271f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Wed, 13 May 2026 11:14:20 +0200 Subject: [PATCH 3/8] imx6ull-sdma: check size alignment in data read/write TASK: MSH-36 --- dma/imx6ull-sdma/imx6ull-sdma.c | 4 ++-- dma/imx6ull-sdma/sdma.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index 3b2f177cc..a4b5ec8af 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -698,7 +698,7 @@ static int dev_ctl(msg_t *msg) return EOK; case sdma_dev_ctl__data_mem_write: - if (msg->o.size != dev_ctl.mem.len || msg->o.size > common.tmp_size) { + if ((msg->o.size != dev_ctl.mem.len) || (msg->o.size > common.tmp_size) || (msg->o.size % 4 != 0)) { log_error("dev_ctl: invalid size"); return -EIO; } @@ -706,7 +706,7 @@ static int dev_ctl(msg_t *msg) return sdma_data_memory_write(dev_ctl.mem.addr, common.tmp_paddr, dev_ctl.mem.len); case sdma_dev_ctl__data_mem_read: - if (msg->o.size != dev_ctl.mem.len || msg->o.size > common.tmp_size) { + if ((msg->o.size != dev_ctl.mem.len) || (msg->o.size > common.tmp_size) || (msg->o.size % 4 != 0)) { log_error("dev_ctl: invalid size"); return -EIO; } diff --git a/dma/imx6ull-sdma/sdma.h b/dma/imx6ull-sdma/sdma.h index fef5b7356..7d23cb486 100644 --- a/dma/imx6ull-sdma/sdma.h +++ b/dma/imx6ull-sdma/sdma.h @@ -25,7 +25,21 @@ int sdma_close(sdma_t *s); int sdma_channel_configure(sdma_t *s, sdma_channel_config_t *cfg); +/* + * write SDMA memory using data mode (32 bit word access) + * + * @param[in] data,size source buffer, expressed in bytes, must be multiple of 4 bytes (32 bit word) + * @param[in] addr destination address in 32 bit words + */ int sdma_data_mem_write(sdma_t *s, const void *data, size_t size, addr_t addr); + + +/* + * read SDMA memory using data mode (32 bit word access) + * + * @param[out] data,size destination buffer; expressed in bytes; must be multiple of 4 bytes (32 bit word) + * @param[in] addr source address in 32 bit words + */ int sdma_data_mem_read(sdma_t *s, void *data, size_t size, addr_t addr); int sdma_context_dump(sdma_t *s, sdma_context_t *ctx); From 14c0c0ae1a99ff4cf03eca2cfdee2ad9cc416abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Tue, 21 Apr 2026 10:34:50 +0200 Subject: [PATCH 4/8] imx6ull-sdma: fix data memory read/write size calculation SDMA commands GET_DM and SET_DM take size in 32 bit words. TASK: MSH-36 --- dma/imx6ull-sdma/imx6ull-sdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index a4b5ec8af..e540a2122 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -703,14 +703,14 @@ static int dev_ctl(msg_t *msg) return -EIO; } memcpy(common.tmp, msg->o.data, msg->o.size); - return sdma_data_memory_write(dev_ctl.mem.addr, common.tmp_paddr, dev_ctl.mem.len); + return sdma_data_memory_write(dev_ctl.mem.addr, common.tmp_paddr, dev_ctl.mem.len / 4); case sdma_dev_ctl__data_mem_read: if ((msg->o.size != dev_ctl.mem.len) || (msg->o.size > common.tmp_size) || (msg->o.size % 4 != 0)) { log_error("dev_ctl: invalid size"); return -EIO; } - res = sdma_data_memory_dump(dev_ctl.mem.addr, common.tmp_paddr, dev_ctl.mem.len); + res = sdma_data_memory_dump(dev_ctl.mem.addr, common.tmp_paddr, dev_ctl.mem.len / 4); memcpy(msg->o.data, common.tmp, msg->o.size); return res; From fc73d2b2467b5ee145f356cbe749761054ea1493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Wed, 29 Apr 2026 18:50:28 +0200 Subject: [PATCH 5/8] imx6ull-sdma: optimize lock usage Lock is always released inside condWait TASK: MSH-36 --- dma/imx6ull-sdma/imx6ull-sdma.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index e540a2122..c6b750b9e 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -1074,8 +1074,8 @@ int main(int argc, char *argv[]) unsigned i, intr_cnt[NUM_OF_SDMA_CHANNELS], cnt; memset(intr_cnt, 0, sizeof(intr_cnt)); + mutexLock(common.lock); while (1) { - mutexLock(common.lock); res = condWait(common.intr_cond, common.lock, INTR_WAIT_TIMEOUT_US); if (res == -ETIME) { @@ -1091,8 +1091,6 @@ int main(int argc, char *argv[]) common.broken = 1; } - - mutexUnlock(common.lock); continue; } @@ -1113,11 +1111,10 @@ int main(int argc, char *argv[]) condSignal(common.channel[i].intr_cond); intr_cnt[i] = cnt; } - - mutexUnlock(common.lock); } /* Should never be reached */ + mutexUnlock(common.lock); log_error("Exiting!"); return 0; } From d6a3d38a1a887197463473df5b8fee25dda82890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Tue, 12 May 2026 16:49:26 +0200 Subject: [PATCH 6/8] imx6ull-sdma: add README TASK: MSH-36 --- dma/imx6ull-sdma/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 dma/imx6ull-sdma/README.md diff --git a/dma/imx6ull-sdma/README.md b/dma/imx6ull-sdma/README.md new file mode 100644 index 000000000..ee5e8da67 --- /dev/null +++ b/dma/imx6ull-sdma/README.md @@ -0,0 +1,17 @@ +SDMA driver for IMX6ULL + +## (in)Frequently Asked Questions + +### Why there are references to BP / DSP / StarCore in IMX6 Reference Manual? + +It seems that SDMA documentation was copied from older devices using same IP core without proper care. Descriptions and +register were left with original terms that are not defined anywhere. + +* BP - Baseband Processor/Platform (aka. StarCore/DSP) +* AP - Application Processor/Platform + +There is limited amount of publicly available documentation but this [MXC300 fact-sheet] contains diagram that includes +SDMA with both application processor and DSP core. There are other diagrams here: [MOTOKRZR K3 – Theory of operation]. + +[MXC300 fact-sheet]: https://www.nxp.com/docs/en/fact-sheet/MXC300301FS.pdf +[MOTOKRZR K3 – Theory of operation]: https://firmware.center/firmware/Motorola/KRZR%20K3%20%28Sumba%29/Service%20Docs/MOTOKRZR_K3_Theory_of_Operation_v.1.0.pdf From c1198c24395e5150990218fd938a2d66da929e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Mon, 4 May 2026 18:52:43 +0200 Subject: [PATCH 7/8] imx6ull-sdma: remove noop write to reserved register There is no need to `DSPOVR`o register. IMX6 does not have DSP core. It is set to 0xffffffff after reset and there is no need for any explicit writes from driver. Line `DSPOVR |= 1 << channel_id` looks like it might do something important. It does not. It makes `sdma_init_core` harder to understand without any benefit. TASK: MSH-36 --- dma/imx6ull-sdma/imx6ull-sdma.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index c6b750b9e..c79aabb8b 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -453,7 +453,6 @@ static void sdma_init_core(void) common.regs->EVTOVR = 0; common.regs->HOSTOVR = 0; - common.regs->DSPOVR = 0xffffffff; /* Clear channel pending status */ common.regs->EVTPEND = common.regs->EVTPEND; @@ -558,8 +557,6 @@ static int sdma_channel_configure(uint8_t channel_id, sdma_channel_config_t *cfg return -1; } - common.regs->DSPOVR |= 1 << channel_id; - if (cfg->trig == sdma_trig__event) { if (cfg->event >= NUM_OF_SDMA_REQUESTS) { log_error("event number is too high (%d)", cfg->event); From 8f35865fcbecd9d58a2992fb0a007c03ae8a1315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wi=C5=9Bniewski?= Date: Fri, 17 Apr 2026 21:08:40 +0200 Subject: [PATCH 8/8] !imx6ull-sdma: make BD_DONE handing optional BD_DONE flags indicate that SDMA "owns" buffer described in BD and can write into it. When SDMA returns ownership to processor/driver buffer content should be read *before* setting BD_DONE flag. This ensures data integrity (no read / write collisions). This description assumes RX transfer, but same applies to TX with read / writes swapped. Automatic BD_DONE set can still be useful in some cases like sending fixed buffer repeatedaly (like read requests from ADC). Backwards incompatible. Use `channelCfg.options = sdma_chOption__auto_bd_done` to keep old behaviour. TASK: MSH-36 --- adc/ad7779/imx6ull/dma.c | 1 + dma/imx6ull-sdma/imx6ull-sdma.c | 24 ++++++++++++++---------- dma/imx6ull-sdma/sdma-api.h | 5 +++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/adc/ad7779/imx6ull/dma.c b/adc/ad7779/imx6ull/dma.c index 88aa1b1b3..475465cb1 100644 --- a/adc/ad7779/imx6ull/dma.c +++ b/adc/ad7779/imx6ull/dma.c @@ -69,6 +69,7 @@ static void sdma_configure(void) cfg.trig = sdma_trig__event; cfg.event = event_channel; cfg.priority = SDMA_CHANNEL_PRIORITY_MIN + 1; + cfg.options = sdma_chOption__auto_bd_done; sdma_channel_configure(&sdma_common.sdma, &cfg); } diff --git a/dma/imx6ull-sdma/imx6ull-sdma.c b/dma/imx6ull-sdma/imx6ull-sdma.c index c79aabb8b..e546ade88 100644 --- a/dma/imx6ull-sdma/imx6ull-sdma.c +++ b/dma/imx6ull-sdma/imx6ull-sdma.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -135,7 +136,7 @@ typedef enum { typedef struct { int active; - int auto_bd_done; + bool auto_bd_done; sdma_buffer_desc_t *bd; addr_t bd_paddr; @@ -371,20 +372,22 @@ static int sdma_intr(unsigned int intr, void *arg) unsigned i; for (i = 1; i < NUM_OF_SDMA_CHANNELS; i++) { + sdma_channel_t *channel = &cmn->channel[i]; /* Check if channel is active and it's interrupt flag is set */ - if (_INTR & (1 << i) && cmn->channel[i].active) { - - /* Set BD_DONE in all buffer descriptors */ - sdma_buffer_desc_t *current = cmn->channel[i].bd; - do { - if (!(current->flags & SDMA_BD_DONE)) - current->flags |= SDMA_BD_DONE; - } while (!((current++)->flags & SDMA_BD_WRAP)); + if (_INTR & (1 << i) && channel->active) { + if (channel->auto_bd_done) { + /* Set BD_DONE in all buffer descriptors */ + sdma_buffer_desc_t *current = channel->bd; + do { + if (!(current->flags & SDMA_BD_DONE)) + current->flags |= SDMA_BD_DONE; + } while (!((current++)->flags & SDMA_BD_WRAP)); + } /* Increase interrupt count to notify dispatcher that interrupt for * this channel occurred */ - cmn->channel[i].intr_cnt++; + channel->intr_cnt++; } } } @@ -573,6 +576,7 @@ static int sdma_channel_configure(uint8_t channel_id, sdma_channel_config_t *cfg common.regs->HOSTOVR &= ~(1 << channel_id); } + common.channel[channel_id].auto_bd_done = (cfg->options & sdma_chOption__auto_bd_done) != 0; sdma_set_channel_priority(channel_id, cfg->priority); if ((res = sdma_set_bd_array(channel_id, cfg->bd_paddr, cfg->bd_cnt)) < 0) { diff --git a/dma/imx6ull-sdma/sdma-api.h b/dma/imx6ull-sdma/sdma-api.h index 3a4bfbecf..cf365fee4 100644 --- a/dma/imx6ull-sdma/sdma-api.h +++ b/dma/imx6ull-sdma/sdma-api.h @@ -104,12 +104,17 @@ typedef enum { sdma_trig__host, } sdma_trig_t; +enum sdma_chOption { + sdma_chOption__auto_bd_done = (1 << 0), +}; + typedef struct { addr_t bd_paddr; /* Physical address of buffer descriptor array */ unsigned bd_cnt; sdma_trig_t trig; unsigned event; unsigned priority; + unsigned options; } sdma_channel_config_t; typedef enum {