diff options
author | Grygorii Strashko | 2018-11-28 19:17:51 +0100 |
---|---|---|
committer | Tom Rini | 2018-12-07 08:13:45 -0500 |
commit | b3309918740f00735d414c44ed2a3f26c418715b (patch) | |
tree | fe3b17919c591818ee251996f09a483e3626204c /drivers/dma | |
parent | 27ab27f85057801953d65d563f2340a22859bbbe (diff) |
test: dma: add dma-uclass test
Add a sandbox DMA driver implementation (provider) and corresponding DM
test.
Reviewed-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/Kconfig | 7 | ||||
-rw-r--r-- | drivers/dma/Makefile | 1 | ||||
-rw-r--r-- | drivers/dma/sandbox-dma-test.c | 282 |
3 files changed, 290 insertions, 0 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b9b85c65fc2..8a4162eccdb 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -19,6 +19,13 @@ config DMA_CHANNELS Enable channels support for DMA. Some DMA controllers have multiple channels which can either transfer data to/from different devices. +config SANDBOX_DMA + bool "Enable the sandbox DMA test driver" + depends on DMA && DMA_CHANNELS && SANDBOX + help + Enable support for a test DMA uclass implementation. It stimulates + DMA transfer by simple copying data between channels. + config TI_EDMA3 bool "TI EDMA3 driver" help diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 4eaef8ac651..aff31f986a1 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DMA) += dma-uclass.o obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o obj-$(CONFIG_APBH_DMA) += apbh_dma.o obj-$(CONFIG_FSL_DMA) += fsl_dma.o +obj-$(CONFIG_SANDBOX_DMA) += sandbox-dma-test.o obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o obj-$(CONFIG_TI_EDMA3) += ti-edma3.o obj-$(CONFIG_DMA_LPC32XX) += lpc32xx_dma.o diff --git a/drivers/dma/sandbox-dma-test.c b/drivers/dma/sandbox-dma-test.c new file mode 100644 index 00000000000..8fcef1863e2 --- /dev/null +++ b/drivers/dma/sandbox-dma-test.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Direct Memory Access U-Class Simulation driver + * + * Copyright (C) 2018 Texas Instruments Incorporated <www.ti.com> + * + * Author: Grygorii Strashko <grygorii.strashko@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/read.h> +#include <dma-uclass.h> +#include <dt-structs.h> +#include <errno.h> + +#define SANDBOX_DMA_CH_CNT 3 +#define SANDBOX_DMA_BUF_SIZE 1024 + +struct sandbox_dma_chan { + struct sandbox_dma_dev *ud; + char name[20]; + u32 id; + enum dma_direction dir; + bool in_use; + bool enabled; +}; + +struct sandbox_dma_dev { + struct device *dev; + u32 ch_count; + struct sandbox_dma_chan channels[SANDBOX_DMA_CH_CNT]; + uchar buf[SANDBOX_DMA_BUF_SIZE]; + uchar *buf_rx; + size_t data_len; + u32 meta; +}; + +static int sandbox_dma_transfer(struct udevice *dev, int direction, + void *dst, void *src, size_t len) +{ + memcpy(dst, src, len); + + return 0; +} + +static int sandbox_dma_of_xlate(struct dma *dma, + struct ofnode_phandle_args *args) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + debug("%s(dma id=%u)\n", __func__, args->args[0]); + + if (args->args[0] >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + dma->id = args->args[0]; + + uc = &ud->channels[dma->id]; + + if (dma->id == 1) + uc->dir = DMA_MEM_TO_DEV; + else if (dma->id == 2) + uc->dir = DMA_DEV_TO_MEM; + else + uc->dir = DMA_MEM_TO_MEM; + debug("%s(dma id=%lu dir=%d)\n", __func__, dma->id, uc->dir); + + return 0; +} + +static int sandbox_dma_request(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->in_use) + return -EBUSY; + + uc->in_use = true; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_free(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + + uc->in_use = false; + ud->buf_rx = NULL; + ud->data_len = 0; + debug("%s(dma id=%lu in_use=%d)\n", __func__, dma->id, uc->in_use); + + return 0; +} + +static int sandbox_dma_enable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (uc->enabled) + return -EINVAL; + + uc->enabled = true; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_disable(struct dma *dma) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + + uc->enabled = false; + debug("%s(dma id=%lu enabled=%d)\n", __func__, dma->id, uc->enabled); + + return 0; +} + +static int sandbox_dma_send(struct dma *dma, + void *src, size_t len, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!src || !metadata) + return -EINVAL; + + debug("%s(dma id=%lu)\n", __func__, dma->id); + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_MEM_TO_DEV) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (len >= SANDBOX_DMA_BUF_SIZE) + return -EINVAL; + + memcpy(ud->buf, src, len); + ud->data_len = len; + ud->meta = *((u32 *)metadata); + + debug("%s(dma id=%lu len=%zu meta=%08x)\n", + __func__, dma->id, len, ud->meta); + + return 0; +} + +static int sandbox_dma_receive(struct dma *dma, void **dst, void *metadata) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + struct sandbox_dma_chan *uc; + + if (dma->id >= SANDBOX_DMA_CH_CNT) + return -EINVAL; + if (!dst || !metadata) + return -EINVAL; + + uc = &ud->channels[dma->id]; + if (uc->dir != DMA_DEV_TO_MEM) + return -EINVAL; + if (!uc->in_use) + return -EINVAL; + if (!uc->enabled) + return -EINVAL; + if (!ud->data_len) + return 0; + + if (ud->buf_rx) { + memcpy(ud->buf_rx, ud->buf, ud->data_len); + *dst = ud->buf_rx; + } else { + memcpy(*dst, ud->buf, ud->data_len); + } + + *((u32 *)metadata) = ud->meta; + + debug("%s(dma id=%lu len=%zu meta=%08x %p)\n", + __func__, dma->id, ud->data_len, ud->meta, *dst); + + return ud->data_len; +} + +static int sandbox_dma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) +{ + struct sandbox_dma_dev *ud = dev_get_priv(dma->dev); + + ud->buf_rx = dst; + + return 0; +} + +static const struct dma_ops sandbox_dma_ops = { + .transfer = sandbox_dma_transfer, + .of_xlate = sandbox_dma_of_xlate, + .request = sandbox_dma_request, + .free = sandbox_dma_free, + .enable = sandbox_dma_enable, + .disable = sandbox_dma_disable, + .send = sandbox_dma_send, + .receive = sandbox_dma_receive, + .prepare_rcv_buf = sandbox_dma_prepare_rcv_buf, +}; + +static int sandbox_dma_probe(struct udevice *dev) +{ + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct sandbox_dma_dev *ud = dev_get_priv(dev); + int i, ret = 0; + + uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | + DMA_SUPPORTS_MEM_TO_DEV | + DMA_SUPPORTS_DEV_TO_MEM; + + ud->ch_count = SANDBOX_DMA_CH_CNT; + ud->buf_rx = NULL; + ud->meta = 0; + ud->data_len = 0; + + pr_err("Number of channels: %u\n", ud->ch_count); + + for (i = 0; i < ud->ch_count; i++) { + struct sandbox_dma_chan *uc = &ud->channels[i]; + + uc->ud = ud; + uc->id = i; + sprintf(uc->name, "DMA chan%d\n", i); + uc->in_use = false; + uc->enabled = false; + } + + return ret; +} + +static const struct udevice_id sandbox_dma_ids[] = { + { .compatible = "sandbox,dma" }, + { } +}; + +U_BOOT_DRIVER(sandbox_dma) = { + .name = "sandbox-dma", + .id = UCLASS_DMA, + .of_match = sandbox_dma_ids, + .ops = &sandbox_dma_ops, + .probe = sandbox_dma_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_dma_dev), +}; |