Skip to content

drivers: dma: sam: add support for sama7g5 DMA Controller (XDMAC) #92816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@
};
};

&dma0 {
status = "okay";
};

&dma1 {
status = "okay";
};

&dma2 {
status = "okay";
};

&flx3 {
mchp,flexcom-mode = <SAM_FLEXCOM_MODE_USART>;
status = "okay";
Expand Down
173 changes: 139 additions & 34 deletions drivers/dma/dma_sam_xdmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -233,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 =
Expand All @@ -254,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;
Expand Down Expand Up @@ -300,11 +317,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;
}

Expand All @@ -325,10 +344,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;
}

Expand All @@ -352,9 +374,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();

Expand All @@ -375,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)
{
Expand Down Expand Up @@ -404,26 +501,34 @@ 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,
};

/* 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 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, \
CONFIG_DMA_INIT_PRIORITY, &sam_xdmac_driver_api);

DT_INST_FOREACH_STATUS_OKAY(DMA_INIT)
33 changes: 33 additions & 0 deletions dts/arm/microchip/sam/sama7g5.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,39 @@
#clock-cells = <1>;
};

dma0: dma-controller@e2808000 {
compatible = "atmel,sam-xdmac";
reg = <0xe2808000 0x1000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
#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 = <GIC_SPI 113 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
#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 = <GIC_SPI 114 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
#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>;
Expand Down
3 changes: 3 additions & 0 deletions soc/microchip/sam/sama7g5/Kconfig.defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC
config MMU
default y

config CACHE_MANAGEMENT
default y

endif # SOC_SERIES_SAMA7G5
8 changes: 8 additions & 0 deletions soc/microchip/sam/sama7g5/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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 = {
Expand Down