From a28b74eecbb81a717172ba691be2efa8f7a94a2d Mon Sep 17 00:00:00 2001 From: Tony Han Date: Fri, 20 Jun 2025 10:56:54 +0800 Subject: [PATCH 1/7] soc: microchip: sam: enable CACHE_MANAGEMENT for sama7g5 series Enable cache manamegent for sama7g5 series. Signed-off-by: Tony Han --- soc/microchip/sam/sama7g5/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/microchip/sam/sama7g5/Kconfig.defconfig b/soc/microchip/sam/sama7g5/Kconfig.defconfig index dd102f1621cc6..067cabe8f301f 100644 --- a/soc/microchip/sam/sama7g5/Kconfig.defconfig +++ b/soc/microchip/sam/sama7g5/Kconfig.defconfig @@ -14,4 +14,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config MMU default y +config CACHE_MANAGEMENT + default y + endif # SOC_SERIES_SAMA7G5 From 763687ad605b211062dac593c1f0260325232f35 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Fri, 20 Jun 2025 10:48:43 +0800 Subject: [PATCH 2/7] soc: microchip: sam: update MMU for sama7g5 XDMAC When the XDMAC is activated in the DT, configure it's register region with strong ordered, read and write access. Signed-off-by: Tony Han --- soc/microchip/sam/sama7g5/soc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/soc/microchip/sam/sama7g5/soc.c b/soc/microchip/sam/sama7g5/soc.c index 169d9e551b26b..555890cfd841b 100644 --- a/soc/microchip/sam/sama7g5/soc.c +++ b/soc/microchip/sam/sama7g5/soc.c @@ -15,6 +15,12 @@ MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),), \ ()) +#define MMU_REGION_XDMAC_DEFN(idx, n) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(dma##n)), \ + (MMU_REGION_FLAT_ENTRY("xdmac"#n, XDMAC##n##_BASE_ADDRESS, 0x4000, \ + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),), \ + ()) + static const struct arm_mmu_region mmu_regions[] = { MMU_REGION_FLAT_ENTRY("vectors", CONFIG_KERNEL_VM_BASE, 0x1000, MT_STRONGLY_ORDERED | MPERM_R | MPERM_X), @@ -35,6 +41,8 @@ static const struct arm_mmu_region mmu_regions[] = { MMU_REGION_FLAT_ENTRY("sckc", SCKC_BASE_ADDRESS, 0x4, MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + FOR_EACH_IDX(MMU_REGION_XDMAC_DEFN, (), 0, 1, 2) }; const struct arm_mmu_config mmu_config = { From 7611429bf94ef65bec3257d6ffd835f390b0c0e7 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 11:13:25 +0800 Subject: [PATCH 3/7] drivers: dma: sam: update to support multiple DMA instances This update xdmac driver to support multiple DMA instancess. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 436991a482af2..5270bead45923 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -407,23 +407,24 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .get_status = sam_xdmac_get_status, }; -/* DMA0 */ - -static void dma0_sam_irq_config(void) -{ - IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), sam_xdmac_isr, - DEVICE_DT_INST_GET(0), 0); -} - -static const struct sam_xdmac_dev_cfg dma0_sam_config = { - .regs = (Xdmac *)DT_INST_REG_ADDR(0), - .irq_config = dma0_sam_irq_config, - .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(0), - .irq_id = DT_INST_IRQN(0), -}; - -static struct sam_xdmac_dev_data dma0_sam_data; - -DEVICE_DT_INST_DEFINE(0, sam_xdmac_initialize, NULL, - &dma0_sam_data, &dma0_sam_config, POST_KERNEL, - CONFIG_DMA_INIT_PRIORITY, &sam_xdmac_driver_api); +#define DMA_INIT(n) \ + static void dma##n##_irq_config(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + sam_xdmac_isr, DEVICE_DT_INST_GET(n), 0); \ + } \ + \ + static const struct sam_xdmac_dev_cfg dma##n##_config = { \ + .regs = (Xdmac *)DT_INST_REG_ADDR(n), \ + .irq_config = dma##n##_irq_config, \ + .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n), \ + .irq_id = DT_INST_IRQN(n), \ + }; \ + \ + static struct sam_xdmac_dev_data dma##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &sam_xdmac_initialize, NULL, \ + &dma##n##_data, &dma##n##_config, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, &sam_xdmac_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) From b4236c31e23bc9327cbfa1a9d82008e08bb89f06 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 11:28:54 +0800 Subject: [PATCH 4/7] drivers: dma: sam: support different num of channels for each instance As the number of DMA channels could be different between DMA instances, get the number from "XDMAC Global Type Register" and validate the channel used. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 47 +++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 5270bead45923..ec57702d26b12 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -26,7 +26,7 @@ LOG_MODULE_REGISTER(dma_sam_xdmac); #define XDMAC_INT_ERR (XDMAC_CIE_RBIE | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE) -#define DMA_CHANNELS_NO XDMACCHID_NUMBER +#define DMA_CHANNELS_MAX 31 /* DMA channel configuration */ struct sam_xdmac_channel_cfg { @@ -45,13 +45,15 @@ struct sam_xdmac_dev_cfg { /* Device run time data */ struct sam_xdmac_dev_data { - struct sam_xdmac_channel_cfg dma_channels[DMA_CHANNELS_NO]; + struct dma_context dma_ctx; + struct sam_xdmac_channel_cfg dma_channels[DMA_CHANNELS_MAX + 1]; }; static void sam_xdmac_isr(const struct device *dev) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; struct sam_xdmac_channel_cfg *channel_cfg; @@ -61,7 +63,7 @@ static void sam_xdmac_isr(const struct device *dev) /* Get global interrupt status */ isr_status = xdmac->XDMAC_GIS; - for (int channel = 0; channel < DMA_CHANNELS_NO; channel++) { + for (int channel = 0; channel < channel_num; channel++) { if (!(isr_status & (1 << channel))) { continue; } @@ -83,10 +85,13 @@ int sam_xdmac_channel_configure(const struct device *dev, uint32_t channel, struct sam_xdmac_channel_config *param) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -126,10 +131,13 @@ int sam_xdmac_transfer_configure(const struct device *dev, uint32_t channel, struct sam_xdmac_transfer_config *param) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = dev_cfg->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -179,13 +187,15 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, struct dma_config *cfg) { struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; struct sam_xdmac_channel_config channel_cfg; struct sam_xdmac_transfer_config transfer_cfg; uint32_t burst_size; uint32_t data_size; int ret; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -300,11 +310,13 @@ static int sam_xdmac_transfer_reload(const struct device *dev, uint32_t channel, int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) { const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = config->regs; - if (channel >= DMA_CHANNELS_NO) { - LOG_DBG("Channel %d out of range", channel); + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -325,10 +337,13 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel) int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) { const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; Xdmac * const xdmac = config->regs; - if (channel >= DMA_CHANNELS_NO) { + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); return -EINVAL; } @@ -352,9 +367,16 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel) static int sam_xdmac_initialize(const struct device *dev) { const struct sam_xdmac_dev_cfg *const dev_cfg = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; Xdmac * const xdmac = dev_cfg->regs; + dev_data->dma_ctx.dma_channels = FIELD_GET(XDMAC_GTYPE_NB_CH_Msk, xdmac->XDMAC_GTYPE) + 1; + if (dev_data->dma_ctx.dma_channels > DMA_CHANNELS_MAX + 1) { + LOG_ERR("Maximum supported channels is %d", DMA_CHANNELS_MAX + 1); + return -EINVAL; + } + /* Configure interrupts */ dev_cfg->irq_config(); @@ -421,7 +443,12 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .irq_id = DT_INST_IRQN(n), \ }; \ \ - static struct sam_xdmac_dev_data dma##n##_data; \ + static ATOMIC_DEFINE(dma_channels_atomic_##n, DMA_CHANNELS_MAX); \ + \ + static struct sam_xdmac_dev_data dma##n##_data = { \ + .dma_ctx.magic = DMA_MAGIC, \ + .dma_ctx.atomic = dma_channels_atomic_##n, \ + }; \ \ DEVICE_DT_INST_DEFINE(n, &sam_xdmac_initialize, NULL, \ &dma##n##_data, &dma##n##_config, POST_KERNEL, \ From 2ab4266490535e224cacb74f41f6c83c8ed438fc Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 14:06:51 +0800 Subject: [PATCH 5/7] drivers: dma: sam: update to support sama7g5 XDMAC peripheral Update the driver to support sama7g5 XDMAC peripheral. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index ec57702d26b12..42b7ccb375493 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -243,6 +243,10 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, | XDMAC_CC_MBSIZE(burst_size == 0U ? 0 : burst_size - 1) | XDMAC_CC_SAM_INCREMENTED_AM | XDMAC_CC_DAM_INCREMENTED_AM; +#if defined(CONFIG_SOC_SERIES_SAMA7G5) + /* When a memory-to-memory transfer is performed, configure PERID to 0x7F. */ + cfg->dma_slot = 0x7F; +#endif break; case MEMORY_TO_PERIPHERAL: channel_cfg.cfg = @@ -264,11 +268,14 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel, return -EINVAL; } - channel_cfg.cfg |= - XDMAC_CC_DWIDTH(data_size) - | XDMAC_CC_SIF_AHB_IF1 - | XDMAC_CC_DIF_AHB_IF1 - | XDMAC_CC_PERID(cfg->dma_slot); + channel_cfg.cfg |= XDMAC_CC_DWIDTH(data_size) | +#ifdef XDMAC_CC_SIF_AHB_IF1 + XDMAC_CC_SIF_AHB_IF1 | +#endif +#ifdef XDMAC_CC_DIF_AHB_IF1 + XDMAC_CC_DIF_AHB_IF1 | +#endif + XDMAC_CC_PERID(cfg->dma_slot); channel_cfg.ds_msp = 0U; channel_cfg.sus = 0U; channel_cfg.dus = 0U; From 97075062590473f220bbef18e6fcc93bd3fde173 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 8 Jul 2025 14:41:19 +0800 Subject: [PATCH 6/7] drivers: dma: sam: add DMA channel suspend and resume support Add support for XDMA channel read write suspend and read write resume. Signed-off-by: Tony Han --- drivers/dma/dma_sam_xdmac.c | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/dma/dma_sam_xdmac.c b/drivers/dma/dma_sam_xdmac.c index 42b7ccb375493..73efb2dd7a7eb 100644 --- a/drivers/dma/dma_sam_xdmac.c +++ b/drivers/dma/dma_sam_xdmac.c @@ -404,6 +404,74 @@ static int sam_xdmac_initialize(const struct device *dev) return 0; } +static int xdmac_suspend(const struct device *dev, uint32_t channel) +{ + const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; + + Xdmac * const xdmac = config->regs; + + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); + return -EINVAL; + } + + if (!(xdmac->XDMAC_GS & BIT(channel))) { + LOG_DBG("Channel %d not enabled", channel); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_SAMX7X) + if (xdmac->XDMAC_GRS & BIT(channel) || xdmac->XDMAC_GWS & BIT(channel)) { +#elif defined(CONFIG_SOC_SERIES_SAMA7G5) + if (xdmac->XDMAC_GRSS & BIT(channel) || xdmac->XDMAC_GWSS & BIT(channel)) { +#else +#error Unsupported SoC family +#endif + LOG_DBG("Channel %d already suspended", channel); + return 0; + } + + xdmac->XDMAC_GRWS |= BIT(channel); + + return 0; +} + +static int xdmac_resume(const struct device *dev, uint32_t channel) +{ + const struct sam_xdmac_dev_cfg *config = dev->config; + struct sam_xdmac_dev_data *const dev_data = dev->data; + uint32_t channel_num = dev_data->dma_ctx.dma_channels; + + Xdmac * const xdmac = config->regs; + + if (channel >= channel_num) { + LOG_ERR("Channel %d out of range", channel); + return -EINVAL; + } + + if (!(xdmac->XDMAC_GS & BIT(channel))) { + LOG_DBG("Channel %d not enabled", channel); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_SAMX7X) + if (!(xdmac->XDMAC_GRS & BIT(channel) || xdmac->XDMAC_GWS & BIT(channel))) { +#elif defined(CONFIG_SOC_SERIES_SAMA7G5) + if (!(xdmac->XDMAC_GRSS & BIT(channel) || xdmac->XDMAC_GWSS & BIT(channel))) { +#else +#error Unsupported SoC family +#endif + LOG_DBG("Channel %d not suspended", channel); + return 0; + } + + xdmac->XDMAC_GRWR |= BIT(channel); + + return 0; +} + static int sam_xdmac_get_status(const struct device *dev, uint32_t channel, struct dma_status *status) { @@ -433,6 +501,8 @@ static DEVICE_API(dma, sam_xdmac_driver_api) = { .reload = sam_xdmac_transfer_reload, .start = sam_xdmac_transfer_start, .stop = sam_xdmac_transfer_stop, + .suspend = xdmac_suspend, + .resume = xdmac_resume, .get_status = sam_xdmac_get_status, }; From d6109d549abe3f7f50747f098d3b3d3bd01d1e97 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Thu, 17 Apr 2025 18:20:29 +0800 Subject: [PATCH 7/7] dts: arm: microchip: sama7g5: add DMA Controller (XDMAC) support Add dma nodes to sama7g5.dtsi and sama7g54_ek.dts files. Signed-off-by: Tony Han --- .../microchip/sam/sama7g54_ek/sama7g54_ek.dts | 12 +++++++ dts/arm/microchip/sam/sama7g5.dtsi | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts index d17d3ac722e42..39b37debd9e81 100644 --- a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts +++ b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts @@ -37,6 +37,18 @@ }; }; +&dma0 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + &flx3 { mchp,flexcom-mode = ; status = "okay"; diff --git a/dts/arm/microchip/sam/sama7g5.dtsi b/dts/arm/microchip/sam/sama7g5.dtsi index 5a68520614541..d1c191262f00b 100644 --- a/dts/arm/microchip/sam/sama7g5.dtsi +++ b/dts/arm/microchip/sam/sama7g5.dtsi @@ -46,6 +46,39 @@ #clock-cells = <1>; }; + dma0: dma-controller@e2808000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe2808000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 22>; + clock-names = "dma_clk"; + status = "disabled"; + }; + + dma1: dma-controller@e280c000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe280c000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 23>; + clock-names = "dma_clk"; + status = "disabled"; + }; + + dma2: dma-controller@e1200000 { + compatible = "atmel,sam-xdmac"; + reg = <0xe1200000 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + #dma-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 24>; + clock-names = "dma_clk"; + status = "disabled"; + }; + flx0: flexcom@e1818000 { compatible = "microchip,sam-flexcom"; reg = <0xe1818000 0x200>;