mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 09:42:19 +03:00
MODS: add mods_tegra_dma platform driver
For upstream dma engine slave_id in <struct dma_slave_config> is obsolete.
The Correct way to specify slave_id is
to call dma_request_chan API along with device name defined in dts node.
mods_tegra_dma: mods_tegra_dma {
compatible = "nvidia,mods_tegra_dma";
dmas = <&gpcdma 15>, <&gpcdma 16>;
dma-names = "spi1_rx", "spi2_tx";
status = "okay";
};
To keep kernel ABI compatibility,
add a new ioctl cmd MODS_ESC_DMA_REQUEST_HANDLE_2.
A new struct MODS_DMA_HANDLE_2 is used together with it.
A new function esc_mods_dma_request_channel_2 is implemented accordingly.
JIRA:TM-728
Change-Id: Ic84f294e2248d800b9aacd597a7ce0a84fc94a1d
Signed-off-by: andersm <andersm@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2711537
Signed-off-by: xueyuanb <xueyuanb@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2753148
Reviewed-by: Chris Dragan <kdragan@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
@@ -18,10 +18,15 @@
|
|||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/device.h>
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
#include "mods_internal.h"
|
#include "mods_internal.h"
|
||||||
|
|
||||||
|
static struct device *mods_tegra_dma_dev;
|
||||||
|
|
||||||
#define MODS_DMA_MAX_CHANNEL 32
|
#define MODS_DMA_MAX_CHANNEL 32
|
||||||
struct mods_dma_chan_info {
|
struct mods_dma_chan_info {
|
||||||
rwlock_t lock;
|
rwlock_t lock;
|
||||||
@@ -61,7 +66,7 @@ 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)
|
static int mods_get_chan_by_id(u32 id, struct mods_dma_chan_info **p_dma_chan)
|
||||||
{
|
{
|
||||||
if (id > MODS_DMA_MAX_CHANNEL)
|
if (id >= MODS_DMA_MAX_CHANNEL)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
*p_dma_chan = &dma_info_chan_list[id];
|
*p_dma_chan = &dma_info_chan_list[id];
|
||||||
@@ -69,18 +74,6 @@ static int mods_get_chan_by_id(u32 id, struct mods_dma_chan_info **p_dma_chan)
|
|||||||
return OK;
|
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)
|
static void mods_release_channel(u32 id)
|
||||||
{
|
{
|
||||||
struct mods_dma_chan_info *p_mods_chan;
|
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)
|
static bool mods_chan_is_inuse(struct mods_dma_chan_info *p_mods_chan)
|
||||||
{
|
{
|
||||||
bool in_use = false;
|
bool in_use = false;
|
||||||
@@ -130,12 +115,12 @@ 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,
|
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;
|
bool in_use;
|
||||||
struct mods_dma_chan_info *p_mods_ch;
|
struct mods_dma_chan_info *p_mods_ch;
|
||||||
|
|
||||||
ret = mods_get_chan_by_id(p_handle->dma_id, &p_mods_ch);
|
err = mods_get_chan_by_id(p_handle->dma_id, &p_mods_ch);
|
||||||
if (ret != OK) {
|
if (err != OK) {
|
||||||
mods_error_printk("get dma channel failed, id %d\n",
|
mods_error_printk("get dma channel failed, id %d\n",
|
||||||
p_handle->dma_id);
|
p_handle->dma_id);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -154,34 +139,34 @@ 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,
|
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;
|
struct mods_dma_chan_info *p_mods_chan;
|
||||||
|
|
||||||
ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
||||||
if (ret != OK)
|
if (err != OK)
|
||||||
return ret;
|
return err;
|
||||||
|
|
||||||
mods_debug_printk(DEBUG_TEGRADMA,
|
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));
|
read_lock(&(p_mods_chan->lock));
|
||||||
if (dma_sync_wait(p_mods_chan->pch, cookie) != DMA_COMPLETE)
|
if (dma_sync_wait(p_mods_chan->pch, cookie) != DMA_COMPLETE)
|
||||||
ret = -1;
|
err = -1;
|
||||||
read_unlock(&(p_mods_chan->lock));
|
read_unlock(&(p_mods_chan->lock));
|
||||||
|
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mods_dma_async_is_tx_complete(struct MODS_DMA_HANDLE *p_handle,
|
static int mods_dma_async_is_tx_complete(struct MODS_DMA_HANDLE *p_handle,
|
||||||
mods_dma_cookie_t cookie,
|
mods_dma_cookie_t cookie,
|
||||||
__u32 *p_is_complete)
|
__u32 *p_is_complete)
|
||||||
{
|
{
|
||||||
int ret = OK;
|
int err = OK;
|
||||||
struct mods_dma_chan_info *p_mods_chan;
|
struct mods_dma_chan_info *p_mods_chan;
|
||||||
enum dma_status status;
|
enum dma_status status;
|
||||||
|
|
||||||
ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
||||||
if (ret != OK)
|
if (err != OK)
|
||||||
return ret;
|
return err;
|
||||||
|
|
||||||
read_lock(&(p_mods_chan->lock));
|
read_lock(&(p_mods_chan->lock));
|
||||||
status = dma_async_is_tx_complete(p_mods_chan->pch, cookie, NULL, NULL);
|
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)
|
else if (status == DMA_IN_PROGRESS)
|
||||||
*p_is_complete = false;
|
*p_is_complete = false;
|
||||||
else
|
else
|
||||||
ret = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int esc_mods_dma_request_channel(struct mods_client *client,
|
int esc_mods_dma_request_channel_2(struct mods_client *client,
|
||||||
struct MODS_DMA_HANDLE *p_handle)
|
struct MODS_DMA_HANDLE_2 *p_handle)
|
||||||
{
|
{
|
||||||
struct dma_chan *chan;
|
struct dma_chan *chan = NULL;
|
||||||
struct mods_dma_chan_info *p_mods_chan;
|
struct mods_dma_chan_info *p_mods_chan = NULL;
|
||||||
dma_cap_mask_t mask;
|
u32 id = MODS_DMA_MAX_CHANNEL;
|
||||||
u32 id;
|
int err = -EINVAL;
|
||||||
int ret;
|
|
||||||
|
|
||||||
LOG_ENT();
|
LOG_ENT();
|
||||||
|
|
||||||
ret = mods_get_dma_id(&id);
|
if (p_handle->dma_type >= MODS_DMA_TX_TYPE_END) {
|
||||||
if (ret != OK) {
|
cl_error("dma type %d not available\n", p_handle->dma_type);
|
||||||
cl_error("no dma handle available\n");
|
goto failed;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mods_get_chan_by_id(id, &p_mods_chan);
|
err = mods_get_dma_id(&id);
|
||||||
if (ret != OK) {
|
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");
|
cl_error("get dma channel failed\n");
|
||||||
return ret;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_lock(&(p_mods_chan->lock));
|
read_lock(&(p_mods_chan->lock));
|
||||||
if (p_mods_chan->in_use) {
|
if (p_mods_chan->in_use) {
|
||||||
cl_error("mods dma channel in use\n");
|
cl_error("mods dma channel in use\n");
|
||||||
read_unlock(&(p_mods_chan->lock));
|
read_unlock(&(p_mods_chan->lock));
|
||||||
return -EBUSY;
|
err = -EBUSY;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
read_unlock(&(p_mods_chan->lock));
|
read_unlock(&(p_mods_chan->lock));
|
||||||
|
|
||||||
|
// 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_zero(mask);
|
||||||
dma_cap_set(p_handle->dma_type, mask);
|
dma_cap_set(p_handle->dma_type, mask);
|
||||||
chan = dma_request_channel(mask, NULL, NULL);
|
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) {
|
if (!chan) {
|
||||||
cl_error("dma channel is not available\n");
|
cl_error("dma channel is not available\n");
|
||||||
mods_release_dma_id(id);
|
mods_release_dma_id(id);
|
||||||
return -EBUSY;
|
err = -EBUSY;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock(&(p_mods_chan->lock));
|
write_lock(&(p_mods_chan->lock));
|
||||||
@@ -244,9 +244,25 @@ int esc_mods_dma_request_channel(struct mods_client *client,
|
|||||||
|
|
||||||
p_handle->dma_id = id;
|
p_handle->dma_id = id;
|
||||||
cl_debug(DEBUG_TEGRADMA, "request get dma id: %d\n", 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,
|
int esc_mods_dma_release_channel(struct mods_client *client,
|
||||||
@@ -262,12 +278,15 @@ int esc_mods_dma_set_config(struct mods_client *client,
|
|||||||
{
|
{
|
||||||
struct dma_slave_config config;
|
struct dma_slave_config config;
|
||||||
struct mods_dma_chan_info *p_mods_chan;
|
struct mods_dma_chan_info *p_mods_chan;
|
||||||
int ret;
|
int err;
|
||||||
|
|
||||||
LOG_ENT();
|
LOG_ENT();
|
||||||
ret = mods_get_inuse_chan_by_handle(&p_config->handle, &p_mods_chan);
|
|
||||||
if (ret != OK)
|
err = mods_get_inuse_chan_by_handle(&p_config->handle, &p_mods_chan);
|
||||||
return ret;
|
if (err != OK) {
|
||||||
|
LOG_EXT();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
config.direction = p_config->direction;
|
config.direction = p_config->direction;
|
||||||
config.src_addr = p_config->src_addr;
|
config.src_addr = p_config->src_addr;
|
||||||
@@ -282,30 +301,33 @@ int esc_mods_dma_set_config(struct mods_client *client,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
cl_debug(DEBUG_TEGRADMA,
|
cl_debug(DEBUG_TEGRADMA,
|
||||||
"ch: %d dir [%d], addr[%p -> %p], burst [%d %d]",
|
"ch: %d dir [%d], addr[%p -> %p], burst [%d %d] width [%d %d]\n",
|
||||||
p_config->handle.dma_id,
|
p_config->handle.dma_id,
|
||||||
config.direction,
|
config.direction,
|
||||||
(void *)config.src_addr, (void *)config.dst_addr,
|
(void *)config.src_addr, (void *)config.dst_addr,
|
||||||
config.src_maxburst, config.dst_maxburst);
|
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,
|
cl_debug(DEBUG_TEGRADMA,
|
||||||
"width [%d %d] slave id %d\n",
|
"slave id %d\n",
|
||||||
config.src_addr_width, config.dst_addr_width,
|
config.slave_id);
|
||||||
p_config->slave_id);
|
#endif
|
||||||
|
|
||||||
write_lock(&(p_mods_chan->lock));
|
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));
|
write_unlock(&(p_mods_chan->lock));
|
||||||
|
|
||||||
LOG_EXT();
|
LOG_EXT();
|
||||||
|
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int esc_mods_dma_submit_request(struct mods_client *client,
|
int esc_mods_dma_submit_request(struct mods_client *client,
|
||||||
struct MODS_DMA_TX_DESC *p_mods_desc)
|
struct MODS_DMA_TX_DESC *p_mods_desc)
|
||||||
{
|
{
|
||||||
int ret = OK;
|
int err = OK;
|
||||||
struct mods_dma_chan_info *p_mods_chan;
|
struct mods_dma_chan_info *p_mods_chan;
|
||||||
struct dma_async_tx_descriptor *desc;
|
struct dma_async_tx_descriptor *desc;
|
||||||
struct dma_device *dev;
|
struct dma_device *dev;
|
||||||
@@ -315,12 +337,15 @@ int esc_mods_dma_submit_request(struct mods_client *client,
|
|||||||
LOG_ENT();
|
LOG_ENT();
|
||||||
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
|
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
|
||||||
|
|
||||||
ret = mods_get_inuse_chan_by_handle(&p_mods_desc->handle, &p_mods_chan);
|
err = mods_get_inuse_chan_by_handle(&p_mods_desc->handle, &p_mods_chan);
|
||||||
if (ret != OK)
|
if (err != OK) {
|
||||||
return ret;
|
LOG_EXT();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_mods_desc->mode != MODS_DMA_SINGLE) {
|
if (p_mods_desc->mode != MODS_DMA_SINGLE) {
|
||||||
cl_error("unsupported mode: %d\n", p_mods_desc->mode);
|
cl_error("unsupported mode: %d\n", p_mods_desc->mode);
|
||||||
|
LOG_EXT();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +375,7 @@ int esc_mods_dma_submit_request(struct mods_client *client,
|
|||||||
|
|
||||||
if (desc == NULL) {
|
if (desc == NULL) {
|
||||||
cl_error("unable to get desc for Tx\n");
|
cl_error("unable to get desc for Tx\n");
|
||||||
ret = -EIO;
|
err = -EIO;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,25 +387,28 @@ failed:
|
|||||||
write_unlock(&(p_mods_chan->lock));
|
write_unlock(&(p_mods_chan->lock));
|
||||||
if (dma_submit_error(cookie)) {
|
if (dma_submit_error(cookie)) {
|
||||||
cl_error("submit cookie: %x\n", cookie);
|
cl_error("submit cookie: %x\n", cookie);
|
||||||
|
LOG_EXT();
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_mods_desc->cookie = cookie;
|
p_mods_desc->cookie = cookie;
|
||||||
|
|
||||||
LOG_EXT();
|
LOG_EXT();
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int esc_mods_dma_async_issue_pending(struct mods_client *client,
|
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;
|
struct mods_dma_chan_info *p_mods_chan;
|
||||||
|
|
||||||
LOG_ENT();
|
LOG_ENT();
|
||||||
ret = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
err = mods_get_inuse_chan_by_handle(p_handle, &p_mods_chan);
|
||||||
if (ret != OK)
|
if (err != OK) {
|
||||||
return ret;
|
LOG_EXT();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
cl_debug(DEBUG_TEGRADMA, "issue pending on chan: %p\n",
|
cl_debug(DEBUG_TEGRADMA, "issue pending on chan: %p\n",
|
||||||
p_mods_chan->pch);
|
p_mods_chan->pch);
|
||||||
@@ -389,27 +417,27 @@ int esc_mods_dma_async_issue_pending(struct mods_client *client,
|
|||||||
read_unlock(&(p_mods_chan->lock));
|
read_unlock(&(p_mods_chan->lock));
|
||||||
LOG_EXT();
|
LOG_EXT();
|
||||||
|
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int esc_mods_dma_wait(struct mods_client *client,
|
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();
|
LOG_ENT();
|
||||||
if (p_wait_desc->type == MODS_DMA_SYNC_WAIT)
|
if (p_wait_desc->type == MODS_DMA_SYNC_WAIT)
|
||||||
ret = mods_dma_sync_wait(&p_wait_desc->handle,
|
err = mods_dma_sync_wait(&p_wait_desc->handle,
|
||||||
p_wait_desc->cookie);
|
p_wait_desc->cookie);
|
||||||
else if (p_wait_desc->type == MODS_DMA_ASYNC_WAIT)
|
else if (p_wait_desc->type == MODS_DMA_ASYNC_WAIT)
|
||||||
ret = mods_dma_async_is_tx_complete(&p_wait_desc->handle,
|
err = mods_dma_async_is_tx_complete(&p_wait_desc->handle,
|
||||||
p_wait_desc->cookie,
|
p_wait_desc->cookie,
|
||||||
&p_wait_desc->tx_complete);
|
&p_wait_desc->tx_complete);
|
||||||
else
|
else
|
||||||
ret = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
LOG_EXT();
|
LOG_EXT();
|
||||||
return ret;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int esc_mods_dma_alloc_coherent(struct mods_client *client,
|
int esc_mods_dma_alloc_coherent(struct mods_client *client,
|
||||||
@@ -494,3 +522,66 @@ int esc_mods_dma_copy_to_user(struct mods_client *client,
|
|||||||
|
|
||||||
return retval;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -631,10 +631,12 @@ int esc_mods_oist_status(struct mods_client *client,
|
|||||||
struct MODS_TEGRA_OIST_STATUS *p);
|
struct MODS_TEGRA_OIST_STATUS *p);
|
||||||
|
|
||||||
#ifdef CONFIG_DMA_ENGINE
|
#ifdef CONFIG_DMA_ENGINE
|
||||||
void mods_init_dma(void);
|
int mods_init_dma(void);
|
||||||
void mods_exit_dma(void);
|
void mods_exit_dma(void);
|
||||||
int esc_mods_dma_request_channel(struct mods_client *client,
|
int esc_mods_dma_request_channel(struct mods_client *client,
|
||||||
struct MODS_DMA_HANDLE *p);
|
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,
|
int esc_mods_dma_release_channel(struct mods_client *client,
|
||||||
struct MODS_DMA_HANDLE *p);
|
struct MODS_DMA_HANDLE *p);
|
||||||
int esc_mods_dma_set_config(struct mods_client *client,
|
int esc_mods_dma_set_config(struct mods_client *client,
|
||||||
|
|||||||
@@ -471,7 +471,9 @@ static int __init mods_init_module(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_DMA_ENGINE)
|
#if defined(CONFIG_DMA_ENGINE)
|
||||||
mods_init_dma();
|
rc = mods_init_dma();
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2409,6 +2411,11 @@ static long mods_krnl_ioctl(struct file *fp,
|
|||||||
esc_mods_dma_request_channel,
|
esc_mods_dma_request_channel,
|
||||||
MODS_DMA_HANDLE);
|
MODS_DMA_HANDLE);
|
||||||
break;
|
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:
|
case MODS_ESC_DMA_RELEASE_HANDLE:
|
||||||
MODS_IOCTL_NORETVAL(MODS_ESC_DMA_RELEASE_HANDLE,
|
MODS_IOCTL_NORETVAL(MODS_ESC_DMA_RELEASE_HANDLE,
|
||||||
esc_mods_dma_release_channel,
|
esc_mods_dma_release_channel,
|
||||||
@@ -2430,7 +2437,7 @@ static long mods_krnl_ioctl(struct file *fp,
|
|||||||
MODS_DMA_TX_DESC);
|
MODS_DMA_TX_DESC);
|
||||||
break;
|
break;
|
||||||
case MODS_ESC_DMA_TX_WAIT:
|
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,
|
esc_mods_dma_wait,
|
||||||
MODS_DMA_WAIT_DESC);
|
MODS_DMA_WAIT_DESC);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1616,9 +1616,30 @@ struct MODS_DMA_HANDLE {
|
|||||||
/* IN */
|
/* IN */
|
||||||
__u32 dma_type; /* Indicate the DMA Type*/
|
__u32 dma_type; /* Indicate the DMA Type*/
|
||||||
/* OUT */
|
/* 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 {
|
enum MODS_DMA_TRANSFER_DIRECTION {
|
||||||
MODS_DMA_MEM_TO_MEM,
|
MODS_DMA_MEM_TO_MEM,
|
||||||
MODS_DMA_MEM_TO_DEV,
|
MODS_DMA_MEM_TO_DEV,
|
||||||
@@ -1962,6 +1983,7 @@ struct MODS_TEGRA_OIST_STATUS {
|
|||||||
/* Deprecated */
|
/* Deprecated */
|
||||||
#define MODS_ESC_PCI_UNMAP_RESOURCE MODSIO(W, 79, MODS_PCI_UNMAP_RESOURCE)
|
#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 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_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_SET_CONFIG MODSIO(W, 82, MODS_DMA_CHANNEL_CONFIG)
|
||||||
#define MODS_ESC_DMA_TX_SUBMIT MODSIO(W, 83, MODS_DMA_TX_DESC)
|
#define MODS_ESC_DMA_TX_SUBMIT MODSIO(W, 83, MODS_DMA_TX_DESC)
|
||||||
|
|||||||
Reference in New Issue
Block a user