diff --git a/drivers/misc/mods/mods_dma.c b/drivers/misc/mods/mods_dma.c
index f7a32db5..6f33cd18 100644
--- a/drivers/misc/mods/mods_dma.c
+++ b/drivers/misc/mods/mods_dma.c
@@ -18,10 +18,15 @@
* If not, see .
*/
-#include
+#include
#include
+#include
+#include
+#include
#include "mods_internal.h"
+static struct device *mods_tegra_dma_dev;
+
#define MODS_DMA_MAX_CHANNEL 32
struct mods_dma_chan_info {
rwlock_t lock;
@@ -61,26 +66,14 @@ static void mods_release_dma_id(u32 id)
static int mods_get_chan_by_id(u32 id, struct mods_dma_chan_info **p_dma_chan)
{
- if (id > MODS_DMA_MAX_CHANNEL)
- return -ERANGE;
+ if (id >= MODS_DMA_MAX_CHANNEL)
+ return -ERANGE;
*p_dma_chan = &dma_info_chan_list[id];
return OK;
}
-void mods_init_dma(void)
-{
- struct mods_dma_chan_info *p_chan_info;
- int i;
-
- for (i = 0; i < MODS_DMA_MAX_CHANNEL; i++) {
- p_chan_info = &dma_info_chan_list[i];
- rwlock_init(&(p_chan_info->lock));
- p_chan_info->in_use = false;
- }
-}
-
static void mods_release_channel(u32 id)
{
struct mods_dma_chan_info *p_mods_chan;
@@ -107,14 +100,6 @@ static void mods_release_channel(u32 id)
}
}
-void mods_exit_dma(void)
-{
- int i;
-
- for (i = 0; i < MODS_DMA_MAX_CHANNEL; i++)
- mods_release_channel(i);
-}
-
static bool mods_chan_is_inuse(struct mods_dma_chan_info *p_mods_chan)
{
bool in_use = false;
@@ -128,23 +113,23 @@ static bool mods_chan_is_inuse(struct mods_dma_chan_info *p_mods_chan)
}
static int mods_get_inuse_chan_by_handle(struct MODS_DMA_HANDLE *p_handle,
- struct mods_dma_chan_info **p_mods_chan)
+ struct mods_dma_chan_info **p_mods_chan)
{
- int ret;
+ int err;
bool in_use;
struct mods_dma_chan_info *p_mods_ch;
- ret = mods_get_chan_by_id(p_handle->dma_id, &p_mods_ch);
- if (ret != OK) {
+ err = mods_get_chan_by_id(p_handle->dma_id, &p_mods_ch);
+ if (err != OK) {
mods_error_printk("get dma channel failed, id %d\n",
- p_handle->dma_id);
+ p_handle->dma_id);
return -ENODEV;
}
in_use = mods_chan_is_inuse(p_mods_ch);
if (!in_use) {
mods_error_printk("invalid dma channel: %d, not in use\n",
- p_handle->dma_id);
+ p_handle->dma_id);
return -EINVAL;
}
*p_mods_chan = p_mods_ch;
@@ -152,36 +137,36 @@ static int mods_get_inuse_chan_by_handle(struct MODS_DMA_HANDLE *p_handle,
}
static int mods_dma_sync_wait(struct MODS_DMA_HANDLE *p_handle,
- mods_dma_cookie_t cookie)
+ mods_dma_cookie_t cookie)
{
- int ret = OK;
+ int err = OK;
struct mods_dma_chan_info *p_mods_chan;
- ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
- if (ret != OK)
- return ret;
+ err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
+ if (err != OK)
+ return err;
mods_debug_printk(DEBUG_TEGRADMA,
- "Wait on chan: %p\n", p_mods_chan->pch);
+ "Wait on chan: %p\n", p_mods_chan->pch);
read_lock(&(p_mods_chan->lock));
if (dma_sync_wait(p_mods_chan->pch, cookie) != DMA_COMPLETE)
- ret = -1;
+ err = -1;
read_unlock(&(p_mods_chan->lock));
- return ret;
+ return err;
}
static int mods_dma_async_is_tx_complete(struct MODS_DMA_HANDLE *p_handle,
- mods_dma_cookie_t cookie,
- __u32 *p_is_complete)
+ mods_dma_cookie_t cookie,
+ __u32 *p_is_complete)
{
- int ret = OK;
+ int err = OK;
struct mods_dma_chan_info *p_mods_chan;
enum dma_status status;
- ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
- if (ret != OK)
- return ret;
+ err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
+ if (err != OK)
+ return err;
read_lock(&(p_mods_chan->lock));
status = dma_async_is_tx_complete(p_mods_chan->pch, cookie, NULL, NULL);
@@ -192,49 +177,64 @@ static int mods_dma_async_is_tx_complete(struct MODS_DMA_HANDLE *p_handle,
else if (status == DMA_IN_PROGRESS)
*p_is_complete = false;
else
- ret = -EINVAL;
+ err = -EINVAL;
- return ret;
+ return err;
}
-int esc_mods_dma_request_channel(struct mods_client *client,
- struct MODS_DMA_HANDLE *p_handle)
+int esc_mods_dma_request_channel_2(struct mods_client *client,
+ struct MODS_DMA_HANDLE_2 *p_handle)
{
- struct dma_chan *chan;
- struct mods_dma_chan_info *p_mods_chan;
- dma_cap_mask_t mask;
- u32 id;
- int ret;
+ struct dma_chan *chan = NULL;
+ struct mods_dma_chan_info *p_mods_chan = NULL;
+ u32 id = MODS_DMA_MAX_CHANNEL;
+ int err = -EINVAL;
LOG_ENT();
- ret = mods_get_dma_id(&id);
- if (ret != OK) {
- cl_error("no dma handle available\n");
- return ret;
+ if (p_handle->dma_type >= MODS_DMA_TX_TYPE_END) {
+ cl_error("dma type %d not available\n", p_handle->dma_type);
+ goto failed;
}
- ret = mods_get_chan_by_id(id, &p_mods_chan);
- if (ret != OK) {
+ err = mods_get_dma_id(&id);
+ if (err != OK) {
+ cl_error("no dma handle available\n");
+ goto failed;
+ }
+
+ err = mods_get_chan_by_id(id, &p_mods_chan);
+ if (err != OK) {
cl_error("get dma channel failed\n");
- return ret;
+ goto failed;
}
read_lock(&(p_mods_chan->lock));
if (p_mods_chan->in_use) {
cl_error("mods dma channel in use\n");
read_unlock(&(p_mods_chan->lock));
- return -EBUSY;
+ err = -EBUSY;
+ goto failed;
}
read_unlock(&(p_mods_chan->lock));
- dma_cap_zero(mask);
- dma_cap_set(p_handle->dma_type, mask);
- chan = dma_request_channel(mask, NULL, NULL);
+ // dma channel is requested in the old-fashion way
+ if (p_handle->ctrl_dir[0] == '\0') {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(p_handle->dma_type, mask);
+ chan = dma_request_channel(mask, NULL, NULL);
+ } else if (mods_tegra_dma_dev) {
+ // get dma chan from dt node
+ cl_debug(DEBUG_TEGRADMA, "dmach is asked for %s\n", p_handle->ctrl_dir);
+ chan = dma_request_chan(mods_tegra_dma_dev, p_handle->ctrl_dir);
+ }
if (!chan) {
cl_error("dma channel is not available\n");
mods_release_dma_id(id);
- return -EBUSY;
+ err = -EBUSY;
+ goto failed;
}
write_lock(&(p_mods_chan->lock));
@@ -244,30 +244,49 @@ int esc_mods_dma_request_channel(struct mods_client *client,
p_handle->dma_id = id;
cl_debug(DEBUG_TEGRADMA, "request get dma id: %d\n", id);
- LOG_EXT();
- return 0;
+failed:
+ LOG_EXT();
+ return err;
+}
+
+int esc_mods_dma_request_channel(struct mods_client *client,
+ struct MODS_DMA_HANDLE *p_handle)
+{
+ int err;
+ struct MODS_DMA_HANDLE_2 handle = {0};
+
+ handle.ctrl_dir[0] = '\0';
+ handle.dma_type = p_handle->dma_type;
+ err = esc_mods_dma_request_channel_2(client, &handle);
+ if (err == 0)
+ p_handle->dma_id = handle.dma_id;
+
+ return err;
}
int esc_mods_dma_release_channel(struct mods_client *client,
- struct MODS_DMA_HANDLE *p_handle)
+ struct MODS_DMA_HANDLE *p_handle)
{
mods_release_channel(p_handle->dma_id);
return OK;
}
int esc_mods_dma_set_config(struct mods_client *client,
- struct MODS_DMA_CHANNEL_CONFIG *p_config)
+ struct MODS_DMA_CHANNEL_CONFIG *p_config)
{
struct dma_slave_config config;
struct mods_dma_chan_info *p_mods_chan;
- int ret;
+ int err;
LOG_ENT();
- ret = mods_get_inuse_chan_by_handle(&p_config->handle, &p_mods_chan);
- if (ret != OK)
- return ret;
+
+ err = mods_get_inuse_chan_by_handle(&p_config->handle, &p_mods_chan);
+ if (err != OK) {
+ LOG_EXT();
+ return err;
+ }
config.direction = p_config->direction;
config.src_addr = p_config->src_addr;
@@ -282,30 +301,33 @@ int esc_mods_dma_set_config(struct mods_client *client,
#endif
cl_debug(DEBUG_TEGRADMA,
- "ch: %d dir [%d], addr[%p -> %p], burst [%d %d]",
- p_config->handle.dma_id,
- config.direction,
- (void *)config.src_addr, (void *)config.dst_addr,
- config.src_maxburst, config.dst_maxburst);
+ "ch: %d dir [%d], addr[%p -> %p], burst [%d %d] width [%d %d]\n",
+ p_config->handle.dma_id,
+ config.direction,
+ (void *)config.src_addr, (void *)config.dst_addr,
+ config.src_maxburst, config.dst_maxburst,
+ config.src_addr_width, config.dst_addr_width);
+
+#if KERNEL_VERSION(5, 17, 0) > MODS_KERNEL_VERSION
cl_debug(DEBUG_TEGRADMA,
- "width [%d %d] slave id %d\n",
- config.src_addr_width, config.dst_addr_width,
- p_config->slave_id);
+ "slave id %d\n",
+ config.slave_id);
+#endif
write_lock(&(p_mods_chan->lock));
- ret = dmaengine_slave_config(p_mods_chan->pch, &config);
+ err = dmaengine_slave_config(p_mods_chan->pch, &config);
write_unlock(&(p_mods_chan->lock));
LOG_EXT();
- return ret;
+ return err;
}
int esc_mods_dma_submit_request(struct mods_client *client,
struct MODS_DMA_TX_DESC *p_mods_desc)
{
- int ret = OK;
+ int err = OK;
struct mods_dma_chan_info *p_mods_chan;
struct dma_async_tx_descriptor *desc;
struct dma_device *dev;
@@ -315,12 +337,15 @@ int esc_mods_dma_submit_request(struct mods_client *client,
LOG_ENT();
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
- ret = mods_get_inuse_chan_by_handle(&p_mods_desc->handle, &p_mods_chan);
- if (ret != OK)
- return ret;
+ err = mods_get_inuse_chan_by_handle(&p_mods_desc->handle, &p_mods_chan);
+ if (err != OK) {
+ LOG_EXT();
+ return err;
+ }
if (p_mods_desc->mode != MODS_DMA_SINGLE) {
cl_error("unsupported mode: %d\n", p_mods_desc->mode);
+ LOG_EXT();
return -EINVAL;
}
@@ -337,20 +362,20 @@ int esc_mods_dma_submit_request(struct mods_client *client,
flags);
} else {
cl_debug(DEBUG_TEGRADMA,
- "Phys Addr [%p], len [%d], dir [%d]\n",
- (void *)p_mods_desc->phys,
- p_mods_desc->length,
- p_mods_desc->data_dir);
+ "Phys Addr [%p], len [%d], dir [%d]\n",
+ (void *)p_mods_desc->phys,
+ p_mods_desc->length,
+ p_mods_desc->data_dir);
desc = dmaengine_prep_slave_single(p_mods_chan->pch,
- p_mods_desc->phys,
- p_mods_desc->length,
- p_mods_desc->data_dir,
- flags);
+ p_mods_desc->phys,
+ p_mods_desc->length,
+ p_mods_desc->data_dir,
+ flags);
}
if (desc == NULL) {
cl_error("unable to get desc for Tx\n");
- ret = -EIO;
+ err = -EIO;
goto failed;
}
@@ -362,54 +387,57 @@ failed:
write_unlock(&(p_mods_chan->lock));
if (dma_submit_error(cookie)) {
cl_error("submit cookie: %x\n", cookie);
+ LOG_EXT();
return -EIO;
}
p_mods_desc->cookie = cookie;
LOG_EXT();
- return ret;
+ return err;
}
int esc_mods_dma_async_issue_pending(struct mods_client *client,
- struct MODS_DMA_HANDLE *p_handle)
+ struct MODS_DMA_HANDLE *p_handle)
{
- int ret = OK;
+ int err = OK;
struct mods_dma_chan_info *p_mods_chan;
LOG_ENT();
- ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
- if (ret != OK)
- return ret;
+ err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
+ if (err != OK) {
+ LOG_EXT();
+ return err;
+ }
cl_debug(DEBUG_TEGRADMA, "issue pending on chan: %p\n",
- p_mods_chan->pch);
+ p_mods_chan->pch);
read_lock(&(p_mods_chan->lock));
dma_async_issue_pending(p_mods_chan->pch);
read_unlock(&(p_mods_chan->lock));
LOG_EXT();
- return ret;
+ return err;
}
int esc_mods_dma_wait(struct mods_client *client,
- struct MODS_DMA_WAIT_DESC *p_wait_desc)
+ struct MODS_DMA_WAIT_DESC *p_wait_desc)
{
- int ret;
+ int err;
LOG_ENT();
if (p_wait_desc->type == MODS_DMA_SYNC_WAIT)
- ret = mods_dma_sync_wait(&p_wait_desc->handle,
- p_wait_desc->cookie);
+ err = mods_dma_sync_wait(&p_wait_desc->handle,
+ p_wait_desc->cookie);
else if (p_wait_desc->type == MODS_DMA_ASYNC_WAIT)
- ret = mods_dma_async_is_tx_complete(&p_wait_desc->handle,
- p_wait_desc->cookie,
- &p_wait_desc->tx_complete);
+ err = mods_dma_async_is_tx_complete(&p_wait_desc->handle,
+ p_wait_desc->cookie,
+ &p_wait_desc->tx_complete);
else
- ret = -EINVAL;
+ err = -EINVAL;
LOG_EXT();
- return ret;
+ return err;
}
int esc_mods_dma_alloc_coherent(struct mods_client *client,
@@ -426,10 +454,10 @@ int esc_mods_dma_alloc_coherent(struct mods_client *client,
GFP_KERNEL);
cl_debug(DEBUG_MEM,
- "num_bytes=%d, p_cpu_addr=%p, p_phys_addr=%p\n",
- p->num_bytes,
- (void *)p_cpu_addr,
- (void *)p_phys_addr);
+ "num_bytes=%d, p_cpu_addr=%p, p_phys_addr=%p\n",
+ p->num_bytes,
+ (void *)p_cpu_addr,
+ (void *)p_phys_addr);
if (!p_cpu_addr) {
cl_error(
@@ -451,15 +479,15 @@ int esc_mods_dma_alloc_coherent(struct mods_client *client,
}
int esc_mods_dma_free_coherent(struct mods_client *client,
- struct MODS_DMA_COHERENT_MEM_HANDLE *p)
+ struct MODS_DMA_COHERENT_MEM_HANDLE *p)
{
LOG_ENT();
cl_debug(DEBUG_MEM,
- "num_bytes = %d, p_cpu_addr=%p, p_phys_addr=%p\n",
- p->num_bytes,
- (void *)(p->memory_handle_virt),
- (void *)(p->memory_handle_phys));
+ "num_bytes = %d, p_cpu_addr=%p, p_phys_addr=%p\n",
+ p->num_bytes,
+ (void *)(p->memory_handle_virt),
+ (void *)(p->memory_handle_phys));
dma_free_coherent(NULL,
p->num_bytes,
@@ -474,23 +502,86 @@ int esc_mods_dma_free_coherent(struct mods_client *client,
}
int esc_mods_dma_copy_to_user(struct mods_client *client,
- struct MODS_DMA_COPY_TO_USER *p)
+ struct MODS_DMA_COPY_TO_USER *p)
{
int retval;
LOG_ENT();
cl_debug(DEBUG_MEM,
- "memory_handle_dst=%p, memory_handle_src=%p, num_bytes=%d\n",
- (void *)(p->memory_handle_dst),
- (void *)(p->memory_handle_src),
- p->num_bytes);
+ "memory_handle_dst=%p, memory_handle_src=%p, num_bytes=%d\n",
+ (void *)(p->memory_handle_dst),
+ (void *)(p->memory_handle_src),
+ p->num_bytes);
retval = copy_to_user((void __user *)p->memory_handle_dst,
- (void *)p->memory_handle_src,
- p->num_bytes);
+ (void *)p->memory_handle_src,
+ p->num_bytes);
LOG_EXT();
return retval;
}
+
+static int tegra_dma_driver_probe(struct platform_device *pdev)
+{
+ LOG_ENT();
+
+ mods_debug_printk(DEBUG_TEGRADMA, "mods_tegra_dma probe\n");
+ mods_tegra_dma_dev = get_device(&pdev->dev);
+
+ LOG_EXT();
+ return 0;
+}
+
+static int tegra_dma_driver_remove(struct platform_device *pdev)
+{
+ put_device(&pdev->dev);
+ mods_tegra_dma_dev = NULL;
+ return 0;
+}
+
+static const struct of_device_id of_ids[] = {
+ { .compatible = "nvidia,mods_tegra_dma" },
+ { }
+};
+
+static struct platform_driver mods_tegra_dma_driver = {
+ .probe = tegra_dma_driver_probe,
+ .remove = tegra_dma_driver_remove,
+ .driver = {
+ .name = "mods_tegra_dma",
+ .owner = THIS_MODULE,
+ .of_match_table = of_ids,
+ },
+};
+
+int mods_init_dma(void)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < MODS_DMA_MAX_CHANNEL; i++) {
+ struct mods_dma_chan_info *p_chan_info;
+
+ p_chan_info = &dma_info_chan_list[i];
+ rwlock_init(&(p_chan_info->lock));
+ p_chan_info->in_use = false;
+ }
+
+ err = platform_driver_register(&mods_tegra_dma_driver);
+ if (err < 0)
+ mods_error_printk("register mods dma driver failed\n");
+
+ return err;
+}
+
+void mods_exit_dma(void)
+{
+ int i;
+
+ for (i = 0; i < MODS_DMA_MAX_CHANNEL; i++)
+ mods_release_channel(i);
+
+ platform_driver_unregister(&mods_tegra_dma_driver);
+}
diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h
index 6658ed53..6f8e79ac 100644
--- a/drivers/misc/mods/mods_internal.h
+++ b/drivers/misc/mods/mods_internal.h
@@ -631,10 +631,12 @@ int esc_mods_oist_status(struct mods_client *client,
struct MODS_TEGRA_OIST_STATUS *p);
#ifdef CONFIG_DMA_ENGINE
-void mods_init_dma(void);
+int mods_init_dma(void);
void mods_exit_dma(void);
int esc_mods_dma_request_channel(struct mods_client *client,
struct MODS_DMA_HANDLE *p);
+int esc_mods_dma_request_channel_2(struct mods_client *client,
+ struct MODS_DMA_HANDLE_2 *p_handle_2);
int esc_mods_dma_release_channel(struct mods_client *client,
struct MODS_DMA_HANDLE *p);
int esc_mods_dma_set_config(struct mods_client *client,
diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c
index c2002bbd..754d97a3 100644
--- a/drivers/misc/mods/mods_krnl.c
+++ b/drivers/misc/mods/mods_krnl.c
@@ -471,7 +471,9 @@ static int __init mods_init_module(void)
#endif
#if defined(CONFIG_DMA_ENGINE)
- mods_init_dma();
+ rc = mods_init_dma();
+ if (rc < 0)
+ return rc;
#endif
#endif
@@ -2409,6 +2411,11 @@ static long mods_krnl_ioctl(struct file *fp,
esc_mods_dma_request_channel,
MODS_DMA_HANDLE);
break;
+ case MODS_ESC_DMA_REQUEST_HANDLE_2:
+ MODS_IOCTL(MODS_ESC_DMA_REQUEST_HANDLE_2,
+ esc_mods_dma_request_channel_2,
+ MODS_DMA_HANDLE_2);
+ break;
case MODS_ESC_DMA_RELEASE_HANDLE:
MODS_IOCTL_NORETVAL(MODS_ESC_DMA_RELEASE_HANDLE,
esc_mods_dma_release_channel,
@@ -2430,7 +2437,7 @@ static long mods_krnl_ioctl(struct file *fp,
MODS_DMA_TX_DESC);
break;
case MODS_ESC_DMA_TX_WAIT:
- MODS_IOCTL(MODS_MODS_ESC_DMA_TX_WAIT,
+ MODS_IOCTL(MODS_ESC_DMA_TX_WAIT,
esc_mods_dma_wait,
MODS_DMA_WAIT_DESC);
break;
diff --git a/include/uapi/misc/mods.h b/include/uapi/misc/mods.h
index bd9f326b..dba23884 100644
--- a/include/uapi/misc/mods.h
+++ b/include/uapi/misc/mods.h
@@ -1616,9 +1616,30 @@ struct MODS_DMA_HANDLE {
/* IN */
__u32 dma_type; /* Indicate the DMA Type*/
/* OUT */
- __u32 dma_id; /* Inditify for the DMA */
+ __u32 dma_id; /* Identifier for the DMA */
};
+#define MODS_DMA_HANDLE_CTRL_DIR_LEN 20
+
+/* Used by ioctls:
+ * - MODS_ESC_DMA_REQUEST_HANDLE_2
+ *
+ * Available only on Tegra.
+ */
+struct MODS_DMA_HANDLE_2 {
+ /* IN */
+ __u32 dma_type; /* Indicate the DMA Type*/
+ /* OUT */
+ __u32 dma_id; /* Identifier for the DMA */
+
+ /* ctrl#index_dir
+ * for example, spi0_tx, i2c1_rx
+ * to keep back-compatibility, strlen of ctrl_dir is allowed to be zero
+ */
+ char ctrl_dir[MODS_DMA_HANDLE_CTRL_DIR_LEN];
+};
+
+
enum MODS_DMA_TRANSFER_DIRECTION {
MODS_DMA_MEM_TO_MEM,
MODS_DMA_MEM_TO_DEV,
@@ -1962,6 +1983,7 @@ struct MODS_TEGRA_OIST_STATUS {
/* Deprecated */
#define MODS_ESC_PCI_UNMAP_RESOURCE MODSIO(W, 79, MODS_PCI_UNMAP_RESOURCE)
#define MODS_ESC_DMA_REQUEST_HANDLE MODSIO(R, 80, MODS_DMA_HANDLE)
+#define MODS_ESC_DMA_REQUEST_HANDLE_2 MODSIO(R, 80, MODS_DMA_HANDLE_2)
#define MODS_ESC_DMA_RELEASE_HANDLE MODSIO(W, 81, MODS_DMA_HANDLE)
#define MODS_ESC_DMA_SET_CONFIG MODSIO(W, 82, MODS_DMA_CHANNEL_CONFIG)
#define MODS_ESC_DMA_TX_SUBMIT MODSIO(W, 83, MODS_DMA_TX_DESC)