diff options
Diffstat (limited to 'arch/arm/plat-mxc/sdma')
23 files changed, 8119 insertions, 0 deletions
diff --git a/arch/arm/plat-mxc/sdma/Makefile b/arch/arm/plat-mxc/sdma/Makefile new file mode 100644 index 000000000000..59f94b2da7d0 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/Makefile @@ -0,0 +1,18 @@ +ifneq ($(KBUILD_SRC),) +ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \ + -I$(KBUILD_SRC)/include/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +else +ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \ + -Iinclude/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +endif + +obj-y += dma_sdma.o +obj-$(CONFIG_MXC_SDMA_API) += sdma.o +obj-$(CONFIG_MXC_SDMA_API) += iapi/ +obj-$(CONFIG_MXC_SDMA_API) += sdma_malloc.o diff --git a/arch/arm/plat-mxc/sdma/dma_sdma.c b/arch/arm/plat-mxc/sdma/dma_sdma.c new file mode 100644 index 000000000000..156127dbbaeb --- /dev/null +++ b/arch/arm/plat-mxc/sdma/dma_sdma.c @@ -0,0 +1,697 @@ +/* + * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/dma_sdma.c + * @brief Front-end to the DMA handling. This handles the allocation/freeing + * of DMA channels, and provides a unified interface to the machines + * DMA facilities. This file contains functions for Smart DMA. + * + * @ingroup SDMA + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <mach/dma.h> +#include <mach/hardware.h> + +#ifdef CONFIG_MXC_SDMA_API + +static mxc_dma_channel_t mxc_sdma_channels[MAX_DMA_CHANNELS]; +static mxc_dma_channel_private_t mxc_sdma_private[MAX_DMA_CHANNELS]; + +extern struct clk *mxc_sdma_ahb_clk, *mxc_sdma_ipg_clk; + +/*! + * Tasket to handle processing the channel buffers + * + * @param arg channel id + */ +static void mxc_sdma_channeltasklet(unsigned long arg) +{ + dma_request_t request_t; + dma_channel_params chnl_param; + mxc_dma_channel_t *chnl_info; + mxc_dma_channel_private_t *data_priv; + int bd_intr = 0, error = MXC_DMA_DONE; + + chnl_info = &mxc_sdma_channels[arg]; + data_priv = chnl_info->private; + chnl_param = + mxc_sdma_get_channel_params(chnl_info->channel)->chnl_params; + + mxc_dma_get_config(arg, &request_t, data_priv->buf_tail); + + while (request_t.bd_done == 0) { + bd_intr = mxc_dma_get_bd_intr(arg, data_priv->buf_tail); + data_priv->buf_tail += 1; + if (data_priv->buf_tail >= chnl_param.bd_number) { + data_priv->buf_tail = 0; + } + chnl_info->active = 0; + if (request_t.bd_error) { + error = MXC_DMA_TRANSFER_ERROR; + } + + if (bd_intr != 0) { + chnl_info->cb_fn(chnl_info->cb_args, error, + request_t.count); + error = MXC_DMA_DONE; + } + + if (data_priv->buf_tail == chnl_info->curr_buf) { + break; + } + memset(&request_t, 0, sizeof(dma_request_t)); + mxc_dma_get_config(arg, &request_t, data_priv->buf_tail); + } +} + +/*! + * This function is generally called by the driver at open time. + * The DMA driver would do any initialization steps that is required + * to get the channel ready for data transfer. + * + * @param channel_id a pre-defined id. The peripheral driver would specify + * the id associated with its peripheral. This would be + * used by the DMA driver to identify the peripheral + * requesting DMA and do the necessary setup on the + * channel associated with the particular peripheral. + * The DMA driver could use static or dynamic DMA channel + * allocation. + * @param dev_name module name or device name + * @return returns a negative number on error if request for a DMA channel did not + * succeed, returns the channel number to be used on success. + */ +int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name, + struct dma_channel_info *info) +{ + mxc_sdma_channel_params_t *chnl; + mxc_dma_channel_private_t *data_priv; + int ret = 0, i = 0, channel_num = 0; + mxc_sdma_channel_ext_params_t *p; + + chnl = mxc_sdma_get_channel_params(channel_id); + if (chnl == NULL) { + return -EINVAL; + } + + if (info) { + if (!chnl->chnl_params.ext) + return -EINVAL; + p = (mxc_sdma_channel_ext_params_t *)chnl; + memcpy(&p->chnl_ext_params.info, info, sizeof(info)); + } + + + /* Enable the SDMA clock */ + clk_enable(mxc_sdma_ahb_clk); + clk_enable(mxc_sdma_ipg_clk); + + channel_num = chnl->channel_num; + if (chnl->channel_num == MXC_DMA_DYNAMIC_CHANNEL) { + /* Get the first free channel */ + for (i = (MAX_DMA_CHANNELS - 1); i > 0; i--) { + /* See if channel is available */ + if ((mxc_sdma_channels[i].dynamic != 1) + || (mxc_sdma_channels[i].lock != 0)) { + continue; + } + channel_num = i; + /* Check to see if we can get this channel */ + ret = mxc_request_dma(&channel_num, dev_name); + if (ret == 0) { + break; + } else { + continue; + } + } + if (ret != 0) { + /* No free channel */ + goto err_ret; + } + } else { + if (mxc_sdma_channels[chnl->channel_num].lock == 1) { + ret = -ENODEV; + goto err_ret; + } + ret = mxc_request_dma(&channel_num, dev_name); + if (ret != 0) { + goto err_ret; + } + } + + ret = mxc_dma_setup_channel(channel_num, &chnl->chnl_params); + + if (ret == 0) { + if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) { + ret = + mxc_dma_set_channel_priority(channel_num, + chnl->chnl_priority); + if (ret != 0) { + pr_info("Failed to set channel prority,\ + continue with the existing \ + priority\n"); + goto err_ret; + } + } + mxc_sdma_channels[channel_num].lock = 1; + if ((chnl->chnl_params.transfer_type == per_2_emi) + || (chnl->chnl_params.transfer_type == dsp_2_emi)) { + mxc_sdma_channels[channel_num].mode = MXC_DMA_MODE_READ; + } else { + mxc_sdma_channels[channel_num].mode = + MXC_DMA_MODE_WRITE; + } + mxc_sdma_channels[channel_num].channel = channel_id; + data_priv = mxc_sdma_channels[channel_num].private; + tasklet_init(&data_priv->chnl_tasklet, + mxc_sdma_channeltasklet, channel_num); + if ((channel_id == MXC_DMA_ATA_RX) + || (channel_id == MXC_DMA_ATA_TX)) { + data_priv->intr_after_every_bd = 0; + } else { + data_priv->intr_after_every_bd = 1; + } + } + err_ret: + if (ret != 0) { + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + channel_num = -ENODEV; + } + + return channel_num; +} + +/*! + * This function is generally called by the driver at close time. The DMA + * driver would do any cleanup associated with this channel. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_free(int channel_num) +{ + mxc_dma_channel_private_t *data_priv; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_free_dma(channel_num); + + /* Disable the SDMA clock */ + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + + mxc_sdma_channels[channel_num].lock = 0; + mxc_sdma_channels[channel_num].active = 0; + mxc_sdma_channels[channel_num].curr_buf = 0; + data_priv = mxc_sdma_channels[channel_num].private; + data_priv->buf_tail = 0; + tasklet_kill(&data_priv->chnl_tasklet); + + return 0; +} + +/*! + * Callback function called from the SDMA Interrupt routine + * + * @param arg driver specific argument that was registered + */ +static void mxc_dma_chnl_callback(void *arg) +{ + int priv; + mxc_dma_channel_private_t *data_priv; + + priv = (int)arg; + data_priv = mxc_sdma_channels[priv].private; + /* Process the buffers in a tasklet */ + tasklet_schedule(&data_priv->chnl_tasklet); +} + +/*! + * This function would just configure the buffers specified by the user into + * dma channel. The caller must call mxc_dma_enable to start this transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param dma_buf an array of physical addresses to the user defined + * buffers. The caller must guarantee the dma_buf is + * available until the transfer is completed. + * @param num_buf number of buffers in the array + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not be + * added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf, + int num_buf, mxc_dma_mode_t mode) +{ + int ret = 0, i = 0, prev_buf; + mxc_dma_channel_t *chnl_info; + mxc_dma_channel_private_t *data_priv; + mxc_sdma_channel_params_t *chnl; + dma_channel_params chnl_param; + dma_request_t request_t; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (num_buf <= 0) { + return -EINVAL; + } + + chnl_info = &mxc_sdma_channels[channel_num]; + data_priv = chnl_info->private; + if (chnl_info->lock != 1) { + return -ENODEV; + } + + /* Check to see if all buffers are taken */ + if (chnl_info->active == 1) { + return -EBUSY; + } + + chnl = mxc_sdma_get_channel_params(chnl_info->channel); + chnl_param = chnl->chnl_params; + + /* Re-setup the SDMA channel if the transfer direction is changed */ + if ((chnl_param.peripheral_type != MEMORY) && (mode != chnl_info->mode)) { + if (chnl_param.peripheral_type == DSP) { + if (mode == MXC_DMA_MODE_READ) { + chnl_param.transfer_type = dsp_2_emi; + } else { + chnl_param.transfer_type = emi_2_dsp; + } + } else if (chnl_param.peripheral_type == FIFO_MEMORY) { + if (mode == MXC_DMA_MODE_READ) + chnl_param.per_address = MXC_FIFO_MEM_SRC_FIXED; + else + chnl_param.per_address = + MXC_FIFO_MEM_DEST_FIXED; + } else { + if (mode == MXC_DMA_MODE_READ) { + chnl_param.transfer_type = per_2_emi; + } else { + chnl_param.transfer_type = emi_2_per; + } + } + chnl_param.callback = mxc_dma_chnl_callback; + chnl_param.arg = (void *)channel_num; + ret = mxc_dma_setup_channel(channel_num, &chnl_param); + if (ret != 0) { + return ret; + } + if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) { + ret = + mxc_dma_set_channel_priority(channel_num, + chnl->chnl_priority); + if (ret != 0) { + pr_info("Failed to set channel prority,\ + continue with the existing \ + priority\n"); + } + } + chnl_info->mode = mode; + } + + for (i = 0; i < num_buf; i++, dma_buf++) { + /* Check to see if all buffers are taken */ + if (chnl_info->active == 1) { + break; + } + request_t.destAddr = (__u8 *) dma_buf->dst_addr; + request_t.sourceAddr = (__u8 *) dma_buf->src_addr; + request_t.count = dma_buf->num_of_bytes; + request_t.bd_cont = 1; + ret = mxc_dma_set_config(channel_num, &request_t, + chnl_info->curr_buf); + if (ret != 0) { + break; + } + if (data_priv->intr_after_every_bd == 0) { + if (i == num_buf - 1) { + mxc_dma_set_bd_intr(channel_num, + chnl_info->curr_buf, 1); + } else { + mxc_dma_set_bd_intr(channel_num, + chnl_info->curr_buf, 0); + } + } + + prev_buf = chnl_info->curr_buf; + chnl_info->curr_buf += 1; + if (chnl_info->curr_buf >= chnl_param.bd_number) { + chnl_info->curr_buf = 0; + } + if (chnl_info->curr_buf == data_priv->buf_tail) { + if ((data_priv->intr_after_every_bd == 0) + && (i != num_buf - 1)) { + /* + * Set the BD_INTR flag on the last BD that + * was queued + */ + mxc_dma_set_bd_intr(channel_num, prev_buf, 1); + } + chnl_info->active = 1; + } + } + + if (i == 0) { + return -EBUSY; + } + return 0; +} + +/*! + * This function would just configure the scatterlist specified by the + * user into dma channel. This is a slight variation of mxc_dma_config(), + * it is provided for the convenience of drivers that have a scatterlist + * passed into them. It is the calling driver's responsibility to have the + * correct physical address filled in the "dma_address" field of the + * scatterlist. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param sg a scatterlist of buffers. The caller must guarantee + * the dma_buf is available until the transfer is + * completed. + * @param num_buf number of buffers in the array + * @param num_of_bytes total number of bytes to transfer. If set to 0, this + * would imply to use the length field of the scatterlist + * for each DMA transfer. Else it would calculate the size + * for each DMA transfer. + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not + * be added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, mxc_dma_mode_t mode) +{ + int ret = 0, i = 0; + mxc_dma_requestbuf_t *dma_buf; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + dma_buf = + (mxc_dma_requestbuf_t *) kmalloc(num_buf * + sizeof(mxc_dma_requestbuf_t), + GFP_KERNEL); + + if (dma_buf == NULL) { + return -EFAULT; + } + + for (i = 0; i < num_buf; i++) { + if (mode == MXC_DMA_MODE_READ) { + (dma_buf + i)->dst_addr = sg->dma_address; + } else { + (dma_buf + i)->src_addr = sg->dma_address; + } + + if ((num_of_bytes > sg->length) || (num_of_bytes == 0)) { + (dma_buf + i)->num_of_bytes = sg->length; + } else { + (dma_buf + i)->num_of_bytes = num_of_bytes; + } + sg++; + num_of_bytes -= (dma_buf + i)->num_of_bytes; + } + + ret = mxc_dma_config(channel_num, dma_buf, num_buf, mode); + kfree(dma_buf); + return ret; +} + +/*! + * This function is provided if the driver would like to set/change its + * callback function. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param callback a callback function to provide notification on transfer + * completion, user could specify NULL if he does not wish + * to be notified + * @param arg an argument that gets passed in to the callback + * function, used by the user to do any driver specific + * operations. + * @return this function returns a negative number on error if the callback + * could not be set for the channel or 0 on success + */ +int mxc_dma_callback_set(int channel_num, + mxc_dma_callback_t callback, void *arg) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_sdma_channels[channel_num].cb_fn = callback; + mxc_sdma_channels[channel_num].cb_args = arg; + + mxc_dma_set_callback(channel_num, mxc_dma_chnl_callback, + (void *)channel_num); + + return 0; +} + +/*! + * This stops the DMA channel and any ongoing transfers. Subsequent use of + * mxc_dma_enable() will restart the channel and restart the transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_disable(int channel_num) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_dma_stop(channel_num); + return 0; +} + +/*! + * This starts DMA transfer. Or it restarts DMA on a stopped channel + * previously stopped with mxc_dma_disable(). + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_enable(int channel_num) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_dma_start(channel_num); + return 0; +} + +/*! + * Initializes dma structure with dma_operations + * + * @param dma dma structure + * @return returns 0 on success + */ +static int __init mxc_dma_init(void) +{ + int i; + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + mxc_sdma_channels[i].active = 0; + mxc_sdma_channels[i].lock = 0; + mxc_sdma_channels[i].curr_buf = 0; + mxc_sdma_channels[i].dynamic = 1; + mxc_sdma_private[i].buf_tail = 0; + mxc_sdma_channels[i].private = &mxc_sdma_private[i]; + } + /* + * Make statically allocated channels unavailable for dynamic channel + * requests + */ + mxc_get_static_channels(mxc_sdma_channels); + + return 0; +} + +arch_initcall(mxc_dma_init); + +#else +int mxc_request_dma(int *channel, const char *devicename) +{ + return -ENODEV; +} + +int mxc_dma_setup_channel(int channel, dma_channel_params *p) +{ + return -ENODEV; +} + +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority) +{ + return -ENODEV; +} + +int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index) +{ + return -ENODEV; +} + +int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index) +{ + return -ENODEV; +} + +int mxc_dma_start(int channel) +{ + return -ENODEV; +} + +int mxc_dma_stop(int channel) +{ + return -ENODEV; +} + +void mxc_free_dma(int channel) +{ +} + +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg) +{ +} + +void *sdma_malloc(size_t size) +{ + return 0; +} + +void sdma_free(void *buf) +{ +} + +void *sdma_phys_to_virt(unsigned long buf) +{ + return 0; +} + +unsigned long sdma_virt_to_phys(void *buf) +{ + return 0; +} + +int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name) +{ + return -ENODEV; +} + +int mxc_dma_free(int channel_num) +{ + return -ENODEV; +} + +int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf, + int num_buf, mxc_dma_mode_t mode) +{ + return -ENODEV; +} + +int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, mxc_dma_mode_t mode) +{ + return -ENODEV; +} + +int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback, + void *arg) +{ + return -ENODEV; +} + +int mxc_dma_disable(int channel_num) +{ + return -ENODEV; +} + +int mxc_dma_enable(int channel_num) +{ + return -ENODEV; +} + +EXPORT_SYMBOL(mxc_request_dma); +EXPORT_SYMBOL(mxc_dma_setup_channel); +EXPORT_SYMBOL(mxc_dma_set_channel_priority); +EXPORT_SYMBOL(mxc_dma_set_config); +EXPORT_SYMBOL(mxc_dma_get_config); +EXPORT_SYMBOL(mxc_dma_start); +EXPORT_SYMBOL(mxc_dma_stop); +EXPORT_SYMBOL(mxc_free_dma); +EXPORT_SYMBOL(mxc_dma_set_callback); +EXPORT_SYMBOL(sdma_malloc); +EXPORT_SYMBOL(sdma_free); +EXPORT_SYMBOL(sdma_phys_to_virt); +EXPORT_SYMBOL(sdma_virt_to_phys); + +#endif + +EXPORT_SYMBOL(mxc_dma_request_ext); +EXPORT_SYMBOL(mxc_dma_free); +EXPORT_SYMBOL(mxc_dma_config); +EXPORT_SYMBOL(mxc_dma_sg_config); +EXPORT_SYMBOL(mxc_dma_callback_set); +EXPORT_SYMBOL(mxc_dma_disable); +EXPORT_SYMBOL(mxc_dma_enable); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/sdma/iapi/Makefile b/arch/arm/plat-mxc/sdma/iapi/Makefile new file mode 100644 index 000000000000..b6a5d6aebda0 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for I.API sources. +# + +obj-y := src/
\ No newline at end of file diff --git a/arch/arm/plat-mxc/sdma/iapi/include/epm.h b/arch/arm/plat-mxc/sdma/iapi/include/epm.h new file mode 100644 index 000000000000..8d190e242909 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/epm.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_SDMA_REGS_H__ +#define __ASM_ARCH_MXC_SDMA_REGS_H__ + +#include <mach/hardware.h> + +/* SDMA Reg definition */ +extern void __iomem *sdma_base; +#define SDMA_BASE_IO_ADDR (sdma_base) + +#define SDMA_H_STATSTOP_ADDR (SDMA_BASE_IO_ADDR + 0x008) +#define SDMA_H_START_ADDR (SDMA_BASE_IO_ADDR + 0x00C) + +#define SDMA_H_C0PTR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x000))) +#define SDMA_H_INTR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x004))) +#define SDMA_H_STATSTOP (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x008))) +#define SDMA_H_START (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x00C))) +#define SDMA_H_EVTOVR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x010))) +#define SDMA_H_DSPOVR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x014))) +#define SDMA_H_HOSTOVR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x018))) +#define SDMA_H_EVTPEND (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x01C))) +#define SDMA_H_DSPENBL (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x020))) +#define SDMA_H_RESET (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x024))) +#define SDMA_H_EVTERR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x028))) +#define SDMA_H_INTRMSK (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x02C))) +#define SDMA_H_PSW (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x030))) +#define SDMA_H_EVTERRDBG (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x034))) +#define SDMA_H_CONFIG (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x038))) +#define SDMA_ONCE_ENB (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x040))) +#define SDMA_ONCE_DATA (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x044))) +#define SDMA_ONCE_INSTR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x048))) +#define SDMA_ONCE_STAT (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x04C))) +#define SDMA_ONCE_CMD (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x050))) +#define SDMA_EVT_MIRROR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x054))) +#define SDMA_ILLINSTADDR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x058))) +#define SDMA_CHN0ADDR (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x05C))) +#define SDMA_ONCE_RTB (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x060))) +#define SDMA_XTRIG_CONF1 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x070))) +#define SDMA_XTRIG_CONF2 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x074))) + +#ifdef MXC_SDMA_V2 +#define SDMA_CHNENBL_0 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x200))) +#define SDMA_CHNENBL_1 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x204))) +#define SDMA_CHNENBL_2 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x208))) +#define SDMA_CHNENBL_3 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x20C))) +#define SDMA_CHNENBL_4 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x210))) +#define SDMA_CHNENBL_5 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x214))) +#define SDMA_CHNENBL_6 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x218))) +#define SDMA_CHNENBL_7 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x21C))) +#define SDMA_CHNENBL_8 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x220))) +#define SDMA_CHNENBL_9 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x224))) +#define SDMA_CHNENBL_10 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x228))) +#define SDMA_CHNENBL_11 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x22C))) +#define SDMA_CHNENBL_12 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x230))) +#define SDMA_CHNENBL_13 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x234))) +#define SDMA_CHNENBL_14 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x238))) +#define SDMA_CHNENBL_15 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x23C))) +#define SDMA_CHNENBL_16 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x240))) +#define SDMA_CHNENBL_17 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x244))) +#define SDMA_CHNENBL_18 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x248))) +#define SDMA_CHNENBL_19 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x24C))) +#define SDMA_CHNENBL_20 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x250))) +#define SDMA_CHNENBL_21 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x254))) +#define SDMA_CHNENBL_22 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x258))) +#define SDMA_CHNENBL_23 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x25C))) +#define SDMA_CHNENBL_24 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x260))) +#define SDMA_CHNENBL_25 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x264))) +#define SDMA_CHNENBL_26 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x268))) +#define SDMA_CHNENBL_27 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x26C))) +#define SDMA_CHNENBL_28 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x270))) +#define SDMA_CHNENBL_29 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x274))) +#define SDMA_CHNENBL_30 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x278))) +#define SDMA_CHNENBL_31 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x27C))) +#define SDMA_CHNENBL_32 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x280))) +#define SDMA_CHNENBL_33 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x284))) +#define SDMA_CHNENBL_34 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x288))) +#define SDMA_CHNENBL_35 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x28C))) +#define SDMA_CHNENBL_36 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x290))) +#define SDMA_CHNENBL_37 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x294))) +#define SDMA_CHNENBL_38 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x298))) +#define SDMA_CHNENBL_39 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x29C))) +#define SDMA_CHNENBL_40 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A0))) +#define SDMA_CHNENBL_41 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A4))) +#define SDMA_CHNENBL_42 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A8))) +#define SDMA_CHNENBL_43 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2AC))) +#define SDMA_CHNENBL_44 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B0))) +#define SDMA_CHNENBL_45 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B4))) +#define SDMA_CHNENBL_46 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B8))) +#define SDMA_CHNENBL_47 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2BC))) + +#define SDMA_ONCE_COUNT (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x300))) +#define SDMA_ONCE_ECTL (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x304))) +#define SDMA_ONCE_EAA (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x308))) +#define SDMA_ONCE_EAB (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x30C))) +#define SDMA_ONCE_EAM (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x310))) +#define SDMA_ONCE_ED (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x314))) +#define SDMA_ONCE_EDM (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x318))) +#define SDMA_ONCE_PCMATCH (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x31C))) + +#else + +#define SDMA_CHNENBL_0 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x080))) +#define SDMA_CHNENBL_1 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x084))) +#define SDMA_CHNENBL_2 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x088))) +#define SDMA_CHNENBL_3 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x08C))) +#define SDMA_CHNENBL_4 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x090))) +#define SDMA_CHNENBL_5 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x094))) +#define SDMA_CHNENBL_6 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x098))) +#define SDMA_CHNENBL_7 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x09C))) +#define SDMA_CHNENBL_8 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A0))) +#define SDMA_CHNENBL_9 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A4))) +#define SDMA_CHNENBL_10 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A8))) +#define SDMA_CHNENBL_11 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0AC))) +#define SDMA_CHNENBL_12 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B0))) +#define SDMA_CHNENBL_13 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B4))) +#define SDMA_CHNENBL_14 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B8))) +#define SDMA_CHNENBL_15 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0BC))) +#define SDMA_CHNENBL_16 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C0))) +#define SDMA_CHNENBL_17 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C4))) +#define SDMA_CHNENBL_18 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C8))) +#define SDMA_CHNENBL_19 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0CC))) +#define SDMA_CHNENBL_20 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D0))) +#define SDMA_CHNENBL_21 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D4))) +#define SDMA_CHNENBL_22 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D8))) +#define SDMA_CHNENBL_23 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0DC))) +#define SDMA_CHNENBL_24 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E0))) +#define SDMA_CHNENBL_25 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E4))) +#define SDMA_CHNENBL_26 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E8))) +#define SDMA_CHNENBL_27 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0EC))) +#define SDMA_CHNENBL_28 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F0))) +#define SDMA_CHNENBL_29 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F4))) +#define SDMA_CHNENBL_30 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F8))) +#define SDMA_CHNENBL_31 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0FC))) + +#define SDMA_ONCE_COUNT (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x200))) +#define SDMA_ONCE_ECTL (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x204))) +#define SDMA_ONCE_EAA (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x208))) +#define SDMA_ONCE_EAB (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x20C))) +#define SDMA_ONCE_EAM (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x210))) +#define SDMA_ONCE_ED (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x214))) +#define SDMA_ONCE_EDM (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x218))) +#define SDMA_ONCE_PCMATCH (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x21C))) + +#endif /* MXC_SDMA_V2 */ + +#define SDMA_CHNPRI_0 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x100))) +#define SDMA_CHNPRI_1 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x104))) +#define SDMA_CHNPRI_2 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x108))) +#define SDMA_CHNPRI_3 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x10C))) +#define SDMA_CHNPRI_4 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x110))) +#define SDMA_CHNPRI_5 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x114))) +#define SDMA_CHNPRI_6 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x118))) +#define SDMA_CHNPRI_7 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x11C))) +#define SDMA_CHNPRI_8 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x120))) +#define SDMA_CHNPRI_9 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x124))) +#define SDMA_CHNPRI_10 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x128))) +#define SDMA_CHNPRI_11 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x12C))) +#define SDMA_CHNPRI_12 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x130))) +#define SDMA_CHNPRI_13 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x134))) +#define SDMA_CHNPRI_14 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x138))) +#define SDMA_CHNPRI_15 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x13C))) +#define SDMA_CHNPRI_16 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x140))) +#define SDMA_CHNPRI_17 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x144))) +#define SDMA_CHNPRI_18 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x148))) +#define SDMA_CHNPRI_19 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x14C))) +#define SDMA_CHNPRI_20 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x150))) +#define SDMA_CHNPRI_21 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x154))) +#define SDMA_CHNPRI_22 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x158))) +#define SDMA_CHNPRI_23 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x15C))) +#define SDMA_CHNPRI_24 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x160))) +#define SDMA_CHNPRI_25 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x164))) +#define SDMA_CHNPRI_26 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x168))) +#define SDMA_CHNPRI_27 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x16C))) +#define SDMA_CHNPRI_28 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x170))) +#define SDMA_CHNPRI_29 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x174))) +#define SDMA_CHNPRI_30 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x178))) +#define SDMA_CHNPRI_31 (*((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x17C))) + +#endif /* _mcuEpm_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapi.h b/arch/arm/plat-mxc/sdma/iapi/include/iapi.h new file mode 100644 index 000000000000..7bb4915f7868 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapi.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapi.h + * + * $Id iapi.h $ + * + * Description: + * Unique include for the whole IAPI library. + * + * + * http//compass.mot.com/go/115342679 + * + * $Log iapi.h $ + * + * ***************************************************************************/ + +#ifndef _iapi_h +#define _iapi_h + +/* **************************************************************************** + * Include File Section + * ***************************************************************************/ + +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#include "iapiLow.h" +#include "iapiMiddle.h" +#include "iapiHigh.h" + +#ifdef MCU +#include "iapiLowMcu.h" +#include "iapiMiddleMcu.h" +#endif /* MCU */ + +#endif /* _iapi_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h new file mode 100644 index 000000000000..6ce00b8da5bb --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiDefaults.h + * + * $Id iapiDefaults.h $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * + * + * + * + * $Log iapiDefaults.h $ + * + *****************************************************************************/ + +#ifndef _iapi_defaults_h +#define _iapi_defaults_h + +/****************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "sdmaStruct.h" + +/* **************************************************************************** + * Macro-command Section + * ***************************************************************************/ + +/** + * Error codes + * lower 5 bits free to include channel number when available + * and bit number 6 must be set when channel number is available + * + * Note : + * 1) Abbreviations / naming convention : + * - BD : Buffer Descriptor + * - CC : Channel Context + * - CCB : Channel Control Block + * - CD : Channel Descriptor + * - B : Buffer + * - CH : Channel + * + */ +#define IAPI_SUCCESS 0 +#define IAPI_FAILURE -1 +#define IAPI_ERR_CH_AVAILABLE 0x00020 +#define IAPI_ERR_NO_ERROR 0x00000 +#define IAPI_ERR_NO_CCB_DEFINED 0x01000 +#define IAPI_ERR_BD_UNINITIALIZED 0x02000 +#define IAPI_ERR_BD_ALLOCATED 0x03000 +#define IAPI_ERR_BD_ALLOCATION 0x04000 +#define IAPI_ERR_CCB_ALLOC_FAILED 0x05000 +#define IAPI_ERR_CCB_UNINITIALIZED 0x06000 +#define IAPI_ERR_CC_ALREADY_DEFINED 0x07000 +#define IAPI_ERR_CC_ALLOC_FAILED 0x08000 +#define IAPI_ERR_CD_ALREADY_DEFINED 0x09000 +#define IAPI_ERR_CD_ALLOC_FAILED 0x0A000 +#define IAPI_ERR_CD_CHANGE_CH_NUMBER 0x0B000 +#define IAPI_ERR_CD_CHANGE_CCB_PTR 0x0C000 +#define IAPI_ERR_CD_CHANGE_UNKNOWN 0x0D000 +#define IAPI_ERR_CD_CHANGE 0x0E000 +#define IAPI_ERR_CD_UNINITIALIZED 0x0F000 +#define IAPI_ERR_CLOSE 0x10000 +#define IAPI_ERR_B_ALLOC_FAILED 0x11000 +#define IAPI_ERR_CONFIG_OVERRIDE 0x12000 +#define IAPI_ERR_CH_IN_USE 0x13000 +#define IAPI_ERR_CALLBACKSYNCH_UNKNOWN 0x14000 +#define IAPI_ERR_INVALID_PARAMETER 0x15000 +#define IAPI_ERR_TRUST 0x16000 +#define IAPI_ERR_CHANNEL_UNINITIALIZED 0x17000 +#define IAPI_ERR_RROR_BIT_READ 0x18000 +#define IAPI_ERR_RROR_BIT_WRITE 0x19000 +#define IAPI_ERR_NOT_ALLOWED 0x1A000 +#define IAPI_ERR_NO_OS_FN 0x1B000 + +/* + * Global Variable Section + */ + +/* + * Table to hold pointers to the callback functions registered by the users of + *I.API + */ +extern void (*callbackIsrTable[CH_NUM]) (channelDescriptor * cd_p, void *arg); + +/* + * Table to hold user registered data pointers, to be privided in the callback + *function + */ +extern void *userArgTable[CH_NUM]; + +/* channelDescriptor data structure filled with default data*/ +extern channelDescriptor iapi_ChannelDefaults; + +/* Global variable to hold the last error encountered in I.API operations*/ +extern unsigned int iapi_errno; + +/* Used in synchronization, to mark started channels*/ +extern volatile unsigned long iapi_SDMAIntr; + +/* Hold a pointer to the start of the CCB array, to be used in the IRQ routine + *to find the channel descriptor for the channed sending the interrupt to the + *core. + */ +extern channelControlBlock *iapi_CCBHead; + +/* configs_data structure filled with default data*/ +extern configs_data iapi_ConfigDefaults; + +#endif /* iapiDefaults_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h new file mode 100644 index 000000000000..999a89872f80 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiHigh.h + * + * $Id iapiHigh.h $ + * + * Description: + * prototypes for high level function of I.API + * + * + * http://venerque.sps.mot.com/pjt/sfs/www/iapi/softsim_api.pdf + * + * $Log iapiHigh.h + * + * ***************************************************************************/ + +#ifndef _iapiHigh_h +#define _iapiHigh_h + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" + +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ +enum { + IAPI_CHANGE_CHANDESC, + IAPI_CHANGE_BDNUM, + IAPI_CHANGE_BUFFSIZE, + IAPI_CHANGE_CHANBLOCK, + IAPI_CHANGE_INSTANCE, + IAPI_CHANGE_OWNERSHIP, + IAPI_CHANGE_SYNCH, + IAPI_CHANGE_TRUST, + IAPI_CHANGE_CALLBACKFUNC, + IAPI_CHANGE_CHANCCB, + IAPI_CHANGE_PRIORITY, + IAPI_CHANGE_BDWRAP, + IAPI_CHANGE_WATERMARK, + IAPI_CHANGE_SET_BDCONT, + IAPI_CHANGE_UNSET_BDCONT, + IAPI_CHANGE_SET_BDEXTD, + IAPI_CHANGE_UNSET_BDEXTD, + IAPI_CHANGE_EVTMASK1, + IAPI_CHANGE_EVTMASK2, + IAPI_CHANGE_PERIPHADDR, + IAPI_CHANGE_SET_BDINTR, + IAPI_CHANGE_UNSET_BDINTR, + IAPI_CHANGE_SET_TRANSFER_CD, + IAPI_CHANGE_FORCE_CLOSE, + IAPI_CHANGE_SET_TRANSFER, + IAPI_CHANGE_USER_ARG, + IAPI_CHANGE_SET_BUFFERADDR, + IAPI_CHANGE_SET_EXTDBUFFERADDR, + IAPI_CHANGE_SET_COMMAND, + IAPI_CHANGE_SET_COUNT, + IAPI_CHANGE_SET_STATUS, + IAPI_CHANGE_GET_BUFFERADDR, + IAPI_CHANGE_GET_EXTDBUFFERADDR, + IAPI_CHANGE_GET_COMMAND, + IAPI_CHANGE_GET_COUNT, + IAPI_CHANGE_GET_STATUS, + IAPI_CHANGE_SET_ENDIANNESS +}; + +/* + * Public Function Prototype Section + */ +int iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber); +int iapi_Close(channelDescriptor *cd_p); +int iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte); +int iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte); +int iapi_MemCopy(channelDescriptor *cd_p, void *dest, void *src, + unsigned long size); +int iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest, + unsigned long param); + +int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2); + +int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2); + +#ifdef MCU +int iapi_Init(channelDescriptor *cd_p, configs_data *config_p, + unsigned short *ram_image, unsigned short code_size, + unsigned long start_addr); +#endif /* MCU */ +#ifdef DSP +int iapi_Init(channelDescriptor *cd_p); +#endif /* DSP */ + +int iapi_StartChannel(unsigned char channel); +int iapi_StopChannel(unsigned char channel); +int iapi_SynchChannel(unsigned char channel); + +int iapi_GetChannelNumber(channelDescriptor *cd_p); +unsigned long iapi_GetError(channelDescriptor *cd_p); +int iapi_GetCount(channelDescriptor *cd_p); +int iapi_GetCountAll(channelDescriptor *cd_p); + +#ifndef IRQ_KEYWORD +#define IRQ_KEYWORD +#endif /* IRQ_KEYWORD */ + +IRQ_KEYWORD void IRQ_Handler(void); + +#ifdef MCU +int iapi_GetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address); +int iapi_GetContext(channelDescriptor *cd_p, void *buf, unsigned char channel); +int iapi_SetScript(channelDescriptor *cd_p, void *buf, unsigned short nbyte, + unsigned long destAddr); +int iapi_SetContext(channelDescriptor *cd_p, void *buf, unsigned char channel); +int iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p); + +int iapi_SetChannelEventMapping(unsigned char event, unsigned long channel_map); +#endif /* MCU */ + +#endif /* _iapiHigh_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h new file mode 100644 index 000000000000..82a2e2d4be3a --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLow.h + * + * $Id iapiLow.h $ + * + * Description: + * prototypes for low level function of I.API + * + * + * + * + * $Log iapiLow.h + * + * ***************************************************************************/ + +#ifndef _iapiLow_h +#define _iapiLow_h + +/* **************************************************************************** + * Boolean identifiers + *****************************************************************************/ +#define NO_OS 0 +#define LINUX 1 +#define SYMBIAN 2 +#define WINCE 3 + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#include "iapiOS.h" +#ifdef MCU +#include "iapiLowMcu.h" +#endif /*MCU*/ +#if OS == NO_OS +#include <stdlib.h> +#elif OS == LINUX +#include <linux/types.h> +#endif +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ +#define GOTO_SLEEP(x) (iapi_GotoSleep)(x) +#define INIT_SLEEP(x) (iapi_InitSleep)(x) +/* **************************************************************************** + * Public Function Prototype Section + *****************************************************************************/ +void iapi_lowStartChannel(unsigned char channel); +void iapi_lowStopChannel(unsigned char channel); +void iapi_AttachCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, + void *arg)); +void iapi_DetachCallbackISR(channelDescriptor *cd_p); +void iapi_ChangeCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, + void *arg)); +void iapi_lowSynchChannel(unsigned char channel); +void iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command, + unsigned char status, unsigned short count, + void *buffAddr, void *extBufferAddr); + +#endif /* _iapiLow_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h new file mode 100644 index 000000000000..a228003b1f5a --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowMcu.h + * + * $Id iapiLowMcu.h $ + * + * Description: + * prototypes for low level function of I.API of MCU side only + * + * + * + * + * $Log iapiLowMcu.h $ + * + * ***************************************************************************/ + +#ifndef _iapiLowMcu_h +#define _iapiLowMcu_h + +/****************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" + +/* **************************************************************************** + * Public Function Prototype Section + * ***************************************************************************/ + +void iapi_InitChannelTables(void); +int iapi_ChannelConfig(unsigned char channel, unsigned eventOverride, + unsigned mcuOverride, unsigned dspOverride); +int iapi_Channel0Command(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned char command); +void iapi_lowGetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address); +void iapi_lowGetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel); +void iapi_lowSetScript(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned long destAddr); +void iapi_lowSetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel); +int iapi_lowAssignScript(channelDescriptor *cd_p, script_data *data_p); + +int iapi_lowSetChannelEventMapping(unsigned char event, + unsigned long channel_map); + +#endif /* _iapiLowMcu_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h new file mode 100644 index 000000000000..33529ba064d5 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddle.h + * + * $Id iapiMiddle.h $ + * + * Description: + * prototypes for middle level function of I.API + * + * + * + * + * $Log iapiMiddle.h + * + * ***************************************************************************/ + +#ifndef _iapiMiddle_h +#define _iapiMiddle_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "sdmaStruct.h" +#ifdef MCU +#include "iapiMiddleMcu.h" +#endif /* MCU */ + +/* **************************************************************************** + * Public Function Prototype Section + ******************************************************************************/ +bufferDescriptor *iapi_AllocBD(channelControlBlock *ccb_p); +int iapi_AllocContext(contextData **ctxd_p, unsigned char channel); +int iapi_AllocChannelDesc(channelDescriptor **cd_p, unsigned char channel); +int iapi_ChangeChannelDesc(channelDescriptor *cd_p, + unsigned char whatToChange, unsigned long newval); +void iapi_InitializeCallbackISR(void (*func_p) (channelDescriptor *cd_p, + void *arg)); +int iapi_InitializeMemory(channelControlBlock *ccb_p); + +#endif /* iapiMiddle_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h new file mode 100644 index 000000000000..7f6dd27686b2 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddleMcu.h + * + * $Id iapiMiddleMcu.h $ + * + * Description: + * prototypes for middle level function of I.API + * + * + * + * + * $Log iapiMiddleMcu.h + * + * ***************************************************************************/ + +#ifndef _iapiMiddleMcu_h +#define _iapiMiddleMcu_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "sdmaStruct.h" + +/* **************************************************************************** + * Public Function Prototype Section + ******************************************************************************/ + +#endif /* iapiMiddleMcu_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h new file mode 100644 index 000000000000..bec4941b4bd4 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h @@ -0,0 +1,92 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiOS.h + * + * $Id iapiOS.h $ + * + * Description: + * prototypes for OS level function of I.API + * + * + * + * + * $Log iapiOS.h + * + * ***************************************************************************/ + +#ifndef _iapiOS_h +#define _iapiOS_h + +/* **************************************************************************** + * Boolean identifiers + *****************************************************************************/ +#define NO_OS 0 +#define LINUX 1 +#define SYMBIAN 2 +#define WINCE 3 + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#ifdef MCU +#include "iapiLowMcu.h" +#endif /*MCU*/ +#if OS == NO_OS +#include <stdlib.h> +#elif OS == LINUX +#include <linux/types.h> +#endif +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ +#define SDMA_ERAM 0 +#define SDMA_IRAM 1 +#ifdef CONFIG_SDMA_IRAM +#define MALLOC(x, s) (s == SDMA_ERAM) ? (*iapi_Malloc)(x) : (*iapi_iram_Malloc)(x) +#else /*CONFIG_SDMA_IRAM */ +#define MALLOC(x, s) (*iapi_Malloc)(x) +#endif /*CONFIG_SDMA_IRAM */ +#define FREE(x) if (x != NULL) (*iapi_Free)(x) +#define GOTO_SLEEP(x) (iapi_GotoSleep)(x) +#define INIT_SLEEP(x) (iapi_InitSleep)(x) +/* **************************************************************************** + * Public Function Prototype Section + *****************************************************************************/ +#ifdef CONFIG_SDMA_IRAM +extern void *(*iapi_iram_Malloc) (size_t size); +#endif /*CONFIG_SDMA_IRAM */ + +extern void *(*iapi_Malloc) (size_t size); +extern void (*iapi_Free) (void *ptr); + +extern void *(*iapi_Virt2Phys) (void *ptr); +extern void *(*iapi_Phys2Virt) (void *ptr); + +extern void (*iapi_WakeUp) (int); +extern void (*iapi_GotoSleep) (int); +extern void (*iapi_InitSleep) (int); + +extern void *(*iapi_memcpy) (void *dest, const void *src, size_t count); +extern void *(*iapi_memset) (void *dest, int c, size_t count); + +extern void (*iapi_EnableInterrupts) (void); +extern void (*iapi_DisableInterrupts) (void); + +extern int (*iapi_GetChannel) (int); +extern int (*iapi_ReleaseChannel) (int); + +#endif /* _iapiOS_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h new file mode 100644 index 000000000000..02ed065af2fa --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h @@ -0,0 +1,509 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: sdmaStruct.h + * + * $Id sdmaStruct.h $ + * + * Description: provides necessary definitions and inclusion for ipcmStruct.c + * + * $Log $ + * + *****************************************************************************/ +#ifndef _sdmaStruct_h +#define _sdmaStruct_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ + +/* **************************************************************************** + * Macro-command Section + ******************************************************************************/ + +/** + * Identifier NULL + */ +#ifndef NULL +#define NULL 0 +#endif + +/** + * Boolean identifiers + */ +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/** + * Number of channels + */ +#define CH_NUM 32 +/** + * Number of events + */ +#ifdef MXC_SDMA_V2 +#define EVENTS_NUM 48 +#else +#define EVENTS_NUM 32 +#endif +/** + * Channel configuration + */ +#define DONT_OWN_CHANNEL 0 +#define OWN_CHANNEL 1 + +/** + * Ownership (value defined to computed decimal value) + */ +#define CH_OWNSHP_OFFSET_EVT 0 +#define CH_OWNSHP_OFFSET_MCU 1 +#define CH_OWNSHP_OFFSET_DSP 2 +/** + * Indexof the greg which holds address to start a script from when channel + * becomes current. + */ +#define SDMA_NUMBER_GREGS 8 + +/** + * Channel contexts management + */ + +#define CHANNEL_CONTEXT_BASE_ADDRESS 0x800 +/** + * Buffer descriptor status values. + */ +#define BD_DONE 0x01 +#define BD_WRAP 0x02 +#define BD_CONT 0x04 +#define BD_INTR 0x08 +#define BD_RROR 0x10 +#define BD_LAST 0x20 +#define BD_EXTD 0x80 + +/** + * Data Node descriptor status values. + */ +#define DND_END_OF_FRAME 0x80 +#define DND_END_OF_XFER 0x40 +#define DND_DONE 0x20 +#define DND_UNUSED 0x01 + +/** + * IPCV2 descriptor status values. + */ +#define BD_IPCV2_END_OF_FRAME 0x40 + +#define IPCV2_MAX_NODES 50 +/** + * Error bit set in the CCB status field by the SDMA, + * in setbd routine, in case of a transfer error + */ +#define DATA_ERROR 0x10000000 + +/** + * Buffer descriptor commands. + */ +#define C0_ADDR 0x01 +#define C0_LOAD 0x02 +#define C0_DUMP 0x03 +#define C0_SETCTX 0x07 +#define C0_GETCTX 0x03 +#define C0_SETDM 0x01 +#define C0_SETPM 0x04 +#define C0_GETDM 0x02 +#define C0_GETPM 0x08 +/** + * Transfer types, encoded in the BD command field + */ +#define TRANSFER_32BIT 0x00 +#define TRANSFER_8BIT 0x01 +#define TRANSFER_16BIT 0x02 +#define TRANSFER_24BIT 0x03 +/** + * Change endianness indicator in the BD command field + */ +#define CHANGE_ENDIANNESS 0x80 +/** + * Size in bytes + */ +#define SDMA_BD_SIZE 8 +#define SDMA_EXTENDED_BD_SIZE 12 +#define BD_NUMBER 4 +/** + * Channel interrupt policy + */ +#define DEFAULT_POLL 0 +#define CALLBACK_ISR 1 +/** + * Channel status + */ +#define UNINITIALIZED 0 +#define INITIALIZED 1 + +/** + * IoCtl particular values + */ +#define SET_BIT_ALL 0xFFFFFFFF +#define BD_NUM_OFFSET 16 +#define BD_NUM_MASK 0xFFFF0000 + +/** + * Maximum values for IoCtl calls, used in high or middle level calls + */ +#define MAX_BD_NUM 256 +#define MAX_BD_SIZE 65536 +#define MAX_BLOCKING 2 +#define MAX_SYNCH 2 +#define MAX_OWNERSHIP 8 +#define MAX_CH_PRIORITY 8 +#define MAX_TRUST 2 +#define MAX_WML 256 + +/** + * Access to channelDescriptor fields + */ +enum { + IAPI_CHANNELNUMBER, + IAPI_BUFFERDESCNUMBER, + IAPI_BUFFERSIZE, + IAPI_BLOCKING, + IAPI_CALLBACKSYNCH, + IAPI_OWNERSHIP, + IAPI_PRIORITY, + IAPI_TRUST, + IAPI_UNUSED, + IAPI_CALLBACKISR_PTR, + IAPI_CCB_PTR, + IAPI_BDWRAP, + IAPI_WML +}; + +/** + * Default values for channel descriptor - nobody ownes the channel + */ +#define CD_DEFAULT_OWNERSHIP 7 + +/** + * User Type Section + */ + +/** + * Command/Mode/Count of buffer descriptors + */ + +#if (ENDIANNESS == B_I_G_ENDIAN) +typedef struct iapi_modeCount_ipcv2 { + unsigned long status:8; + /**< L, E , D bits stored here */ + unsigned long reserved:8; + unsigned long count:16; + /**< <size of the buffer pointed by this BD */ +} modeCount_ipcv2; +#else +typedef struct iapi_modeCount_ipcv2 { + unsigned long count:16; + /**<size of the buffer pointed by this BD */ + unsigned long reserved:8; + /**Reserved*/ + unsigned long status:8; + /**< L, E , D bits stored here */ +} modeCount_ipcv2; +#endif +/** + * Data Node descriptor - IPCv2 + * (differentiated between evolutions of SDMA) + */ +typedef struct iapi_dataNodeDescriptor { + modeCount_ipcv2 mode; /**<command, status and count */ + void *bufferAddr; + /**<address of the buffer described */ +} dataNodeDescriptor; + +#if (ENDIANNESS == B_I_G_ENDIAN) +typedef struct iapi_modeCount_ipcv1_v2 { + unsigned long endianness:1; + unsigned long reserved:7; + unsigned long status:8; + /**< E,R,I,C,W,D status bits stored here */ + unsigned long count:16; + /**< size of the buffer pointed by this BD */ +} modeCount_ipcv1_v2; +#else +typedef struct iapi_modeCount_ipcv1_v2 { + unsigned long count:16; + /**<size of the buffer pointed by this BD */ + unsigned long status:8; + /**< E,R,I,C,W,D status bits stored here */ + unsigned long reserved:7; + unsigned long endianness:1; +} modeCount_ipcv1_v2; +#endif +/** + * Buffer descriptor + * (differentiated between evolutions of SDMA) + */ +typedef struct iapi_bufferDescriptor_ipcv1_v2 { + modeCount_ipcv1_v2 mode; + /**<command, status and count */ + void *bufferAddr; /**<address of the buffer described */ + void *extBufferAddr;/**<extended buffer address */ +} bufferDescriptor_ipcv1_v2; + +/** + * Mode/Count of data node descriptors - IPCv2 + */ + +#if (ENDIANNESS == B_I_G_ENDIAN) +typedef struct iapi_modeCount { + unsigned long command:8; + /**< command mostlky used for channel 0 */ + unsigned long status:8; + /**< E,R,I,C,W,D status bits stored here */ + unsigned long count:16; + /**< size of the buffer pointed by this BD */ +} modeCount; +#else +typedef struct iapi_modeCount { + unsigned long count:16; + /**<size of the buffer pointed by this BD */ + unsigned long status:8; + /**< E,R,I,C,W,D status bits stored here */ + unsigned long command:8; + /**< command mostlky used for channel 0 */ +} modeCount; +#endif + +/** + * Buffer descriptor + * (differentiated between evolutions of SDMA) + */ +typedef struct iapi_bufferDescriptor { + modeCount mode; /**<command, status and count */ + void *bufferAddr; + /**<address of the buffer described */ + void *extBufferAddr; + /**<extended buffer address */ +} bufferDescriptor; + +struct iapi_channelControlBlock; +struct iapi_channelDescriptor; +/** + * Channel Descriptor + */ +typedef struct iapi_channelDescriptor { + unsigned char channelNumber; + /**<stores the channel number */ + unsigned char bufferDescNumber; + /**<number of BD's automatically allocated for this channel */ + unsigned short bufferSize; /**<size (in bytes) of buffer descriptors */ + unsigned long blocking:3; + /**<blocking / non blocking feature selection */ + unsigned long callbackSynch:1; + /**<polling/ callback method selection */ + unsigned long ownership:3; + /**<ownership of the channel (host+dedicated+event)*/ + unsigned long priority:3; + /**<reflects the SDMA channel priority register */ + unsigned long trust:1; + /**<trusted buffers or kernel allocated */ + unsigned long useDataSize:1; + /**<indicates if the dataSize field is meaningfull */ + unsigned long dataSize:2; + /**<data transfer size - 8,16,24 or 32 bits*/ + unsigned long forceClose:1; + /**<if TRUE, close channel even with BD owned by SDMA*/ + unsigned long scriptId:7; + /**<number of the script */ + unsigned long watermarkLevel:10; + /**<Watermark level for the peripheral access*/ + unsigned long eventMask1; /**<First Event mask */ + unsigned long eventMask2; /**<Second Event mask */ + unsigned long peripheralAddr; + /**<Address of the peripheral or its fifo when needed */ + void (*callbackISR_ptr) (struct iapi_channelDescriptor *, void *); + /**<pointer to the callback function (or NULL) */ + struct iapi_channelControlBlock *ccb_ptr; + /**<pointer to the channel control block associated to this channel */ +} channelDescriptor; + +/** + * Channel Status + */ +typedef struct iapi_channelStatus { + unsigned long unused:29; + /**<*/ + unsigned long openedInit:1; + /**<channel is initialized or not */ + unsigned long stateDirection:1; + /**<sdma is reading/writing (as seen from channel owner core) */ + unsigned long execute:1; + /**<channel is being processed (started) or not */ +} channelStatus; + +/** + * Channel control Block + */ +typedef struct iapi_channelControlBlock { + bufferDescriptor *currentBDptr;/**<current buffer descriptor processed */ + bufferDescriptor *baseBDptr; /**<first element of buffer descriptor array */ + channelDescriptor *channelDescriptor; + /**<pointer to the channel descriptor */ + channelStatus status; /**<open/close ; started/stopped ; read/write */ +} channelControlBlock; + +/** + * Context structure. + */ +#if (ENDIANNESS == B_I_G_ENDIAN) +typedef struct iapi_stateRegisters { + unsigned long sf:1; + /**<source falut while loading data */ + unsigned long unused0:1; + /**<*/ + unsigned long rpc:14; + /**<return program counter */ + unsigned long t:1; + /**<test bit:status of arithmetic & test instruction*/ + unsigned long unused1:1; + /**<*/ + unsigned long pc:14; + /**<program counter */ + unsigned long lm:2; + /**<loop mode */ + unsigned long epc:14; + /**<loop end program counter */ + unsigned long df:1; + /**<destiantion falut while storing data */ + unsigned long unused2:1; + /**<*/ + unsigned long spc:14; + /**<loop start program counter */ +} stateRegiters; +#else +typedef struct iapi_stateRegisters { + unsigned long pc:14; + /**<program counter */ + unsigned long unused1:1; + /**<*/ + unsigned long t:1; + /**<test bit: status of arithmetic & test instruction*/ + unsigned long rpc:14; + /**<return program counter */ + unsigned long unused0:1; + /**<*/ + unsigned long sf:1; + /**<source falut while loading data */ + unsigned long spc:14; + /**<loop start program counter */ + unsigned long unused2:1; + /**<*/ + unsigned long df:1; + /**<destiantion falut while storing data */ + unsigned long epc:14; + /**<loop end program counter */ + unsigned long lm:2; + /**<loop mode */ +} stateRegiters; +#endif + +/** + * This is SDMA version of SDMA + */ +typedef struct iapi_contextData { + stateRegiters channelState; /**<channel state bits */ + unsigned long gReg[SDMA_NUMBER_GREGS]; + /**<general registers */ + unsigned long mda; + /**<burst dma destination address register */ + unsigned long msa; + /**<burst dma source address register */ + unsigned long ms; + /**<burst dma status register */ + unsigned long md; + /**<burst dma data register */ + unsigned long pda; + /**<peripheral dma destination address register */ + unsigned long psa; + /**<peripheral dma source address register */ + unsigned long ps; + /**<peripheral dma status register */ + unsigned long pd; + /**<peripheral dma data register */ + unsigned long ca; + /**<CRC polynomial register */ + unsigned long cs; + /**<CRC accumulator register */ + unsigned long dda; + /**<dedicated core destination address register */ + unsigned long dsa; + /**<dedicated core source address register */ + unsigned long ds; + /**<dedicated core status register */ + unsigned long dd; + /**<dedicated core data register */ + unsigned long scratch0; + /**<scratch */ + unsigned long scratch1; + /**<scratch */ + unsigned long scratch2; + /**<scratch */ + unsigned long scratch3; + /**<scratch */ + unsigned long scratch4; + /**<scratch */ + unsigned long scratch5; + /**<scratch */ + unsigned long scratch6; + /**<scratch */ + unsigned long scratch7; + /**<scratch */ + +} contextData; + +/** + *This structure holds the necessary data for the assignment in the + * dynamic channel-script association + */ +typedef struct iapi_script_data { + unsigned short load_address; + /**<start address of the script*/ + unsigned long wml; /**<parameters for the channel descriptor*/ + unsigned long shp_addr; + /**<shared peripheral base address*/ + unsigned long per_addr; + /**<peripheral base address for p2p source*/ + unsigned long event_mask1; + /**<First Event mask */ + unsigned long event_mask2; + /**<Second Event mask */ +} script_data; + +/** + *This structure holds the the useful bits of the CONFIG register + */ +typedef struct iapi_configs_data { + unsigned long dspdma:1; /*indicates if the DSPDMA is used */ + unsigned long rtdobs:1; /*indicates if Real-Time Debug pins are enabled */ + unsigned long acr:1; + /**indicates if AHB freq /core freq = 2 or 1 */ + unsigned long csm:2; + /**indicates which context switch mode is selected*/ +} configs_data; + +#endif /* _sdmaStruct_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/Makefile b/arch/arm/plat-mxc/sdma/iapi/src/Makefile new file mode 100644 index 000000000000..4c112bf22384 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for I.API sources. +# +ifneq ($(KBUILD_SRC),) +ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \ + -I$(KBUILD_SRC)/include/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +else +ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \ + -Iinclude/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +endif + +obj-y += iapiLow.o iapiLowMcu.o iapiMiddle.o iapiMiddleMcu.o iapiHigh.o iapiDefaults.o iapiOS.o diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c new file mode 100644 index 000000000000..d7e75b543d8d --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c @@ -0,0 +1,110 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiDefaults.c + * + * $Id iapiDefaults.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * + * Usage: + * + * Files: + * + * +* / + * + * $Log iapiDefaults.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "iapiDefaults.h" + +/* **************************************************************************** + * Global Variable Section + ******************************************************************************/ + +/** + * @brief System Call-back ISRs Table + */ +void (*callbackIsrTable[CH_NUM]) (channelDescriptor *cd_p, void *arg); + +/** + * @brief User registered pointers table + */ +void *userArgTable[CH_NUM]; + +/** + * @brief Pointer to the first CCB in the CCB array + */ +channelControlBlock *iapi_CCBHead; + +/**Default channel description. + * + * Initialization values are:\n + * - channelNumber = 0 + * - bufferDescNumber = 1 + * - bufferSize = 8 + * - blocking = 0 + * - callbackSynch = DEFAULT_POLL + * - ownership = CD_DEFAULT_OWNERSHIP + * - priority = 1 + * - trust = TRUE + * - useDataSize = 0 + * - dataSize = 0 + * - forceClose = 0 + * - scriptId = 0 + * - watermarkLevel = 0 + * - eventMask1 = 0 + * - eventMask2 = 0 + * - peripheralAddr = NULL + * - callbackISR_ptr = NULL + * - iapi_channelControlBlock = NULL + */ +channelDescriptor iapi_ChannelDefaults = { 0, 1, 8, 0, DEFAULT_POLL, + CD_DEFAULT_OWNERSHIP, 1, TRUE, 0, 0, 0, 0, + 0, 0x00, 0x00, 0x00, NULL, NULL +}; + +/** + * Integrated error management + */ +unsigned int iapi_errno; +volatile unsigned long iapi_SDMAIntr; + +/* Default config register. + * Initialization values are: + * dspdma used + * Real-Time Debug pins disabled + * AHB freq / core freq = 2 + * dynamic context switch +*/ +configs_data iapi_ConfigDefaults = { 1, 0, 0, 3 }; + +#ifdef SDMA_SKYE +/* Default sdma State : UNDEF + *possible value are UNDEF, OPEN, LOCK, CLOSED, CLOSE_LOCK + */ + +sdmaState iapi_SdmaState = UNDEF; +#endif + +/* ***************************************************************************/ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c new file mode 100644 index 000000000000..f14d19d1bd60 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c @@ -0,0 +1,2750 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiHigh.c + * + * $Id iapiHigh.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the HIGH level functions of the I.API. + * + * + * / + * + * $Log iapiHigh.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <stdarg.h> +#include <string.h> + +#include "epm.h" +#include "iapi.h" + +/* **************************************************************************** + * External Reference Section (for compatibility with already developed code) + *****************************************************************************/ +static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, + void *data); + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ +#define MAX_CHANNEL 32 + +static dataNodeDescriptor *dnd_read_control_struct[MAX_CHANNEL]; + +/* MASK to get Nullify all the bits of Status in Data Node descriptor apart from L, E and D*/ + +#define GET_LED_MASK 0xE0 + +/*Table defines mapping of Data Node Descriptor to Buffer Descriptor status*/ + +static unsigned char dnd_2_bd_status[] = { + 0x85, /*00 L = 0, E = 0, D = 0 */ + 0x00, /*01 */ + 0x00, /*02 */ + 0x00, /*03 */ + 0x00, /*04 */ + 0x00, /*05 */ + 0x00, /*06 */ + 0x00, /*07 */ + 0x00, /*08 */ + 0x00, /*09 */ + 0x00, /*0A */ + 0x00, /*0B */ + 0x00, /*0C */ + 0x00, /*0D */ + 0x00, /*0E */ + 0x00, /*0F */ + 0x00, /*10 */ + 0x00, /*11 */ + 0x00, /*12 */ + 0x00, /*13 */ + 0x00, /*14 */ + 0x00, /*15 */ + 0x00, /*16 */ + 0x00, /*17 */ + 0x00, /*18 */ + 0x00, /*19 */ + 0x00, /*1A */ + 0x00, /*1B */ + 0x00, /*1C */ + 0x00, /*1D */ + 0x00, /*1E */ + 0x00, /*1F */ + 0x84, /*20 L = 0, E = 0, D = 1 */ + 0x00, /*21 */ + 0x00, /*22 */ + 0x00, /*23 */ + 0x00, /*24 */ + 0x00, /*25 */ + 0x00, /*26 */ + 0x00, /*27 */ + 0x00, /*28 */ + 0x00, /*29 */ + 0x00, /*2A */ + 0x00, /*2B */ + 0x00, /*2C */ + 0x00, /*2D */ + 0x00, /*2E */ + 0x00, /*2F */ + 0x00, /*30 */ + 0x00, /*31 */ + 0x00, /*32 */ + 0x00, /*33 */ + 0x00, /*34 */ + 0x00, /*35 */ + 0x00, /*36 */ + 0x00, /*37 */ + 0x00, /*38 */ + 0x00, /*39 */ + 0x00, /*3A */ + 0x00, /*3B */ + 0x00, /*3C */ + 0x00, /*3D */ + 0x00, /*3E */ + 0x00, /*3F */ + 0xAB, /*40 L = 0, E = 1, D = 0 */ + 0x00, /*41 */ + 0x00, /*42 */ + 0x00, /*43 */ + 0x00, /*44 */ + 0x00, /*45 */ + 0x00, /*46 */ + 0x00, /*47 */ + 0x00, /*48 */ + 0x00, /*49 */ + 0x00, /*4A */ + 0x00, /*4B */ + 0x00, /*4C */ + 0x00, /*4D */ + 0x00, /*4E */ + 0x00, /*4F */ + 0x00, /*50 */ + 0x00, /*51 */ + 0x00, /*52 */ + 0x00, /*53 */ + 0x00, /*54 */ + 0x00, /*55 */ + 0x00, /*56 */ + 0x00, /*57 */ + 0x00, /*58 */ + 0x00, /*59 */ + 0x00, /*5A */ + 0x00, /*5B */ + 0x00, /*5C */ + 0x00, /*5D */ + 0x00, /*5E */ + 0x00, /*5F */ + 0xAA, /*60 L = 0, E = 1, D = 1 */ + 0x00, /*61 */ + 0x00, /*62 */ + 0x00, /*63 */ + 0x00, /*64 */ + 0x00, /*65 */ + 0x00, /*66 */ + 0x00, /*67 */ + 0x00, /*68 */ + 0x00, /*69 */ + 0x00, /*6A */ + 0x00, /*6B */ + 0x00, /*6C */ + 0x00, /*6D */ + 0x00, /*6E */ + 0x00, /*6F */ + 0x00, /*70 */ + 0x00, /*71 */ + 0x00, /*72 */ + 0x00, /*73 */ + 0x00, /*74 */ + 0x00, /*75 */ + 0x00, /*76 */ + 0x00, /*77 */ + 0x00, /*78 */ + 0x00, /*79 */ + 0x00, /*7A */ + 0x00, /*7B */ + 0x00, /*7C */ + 0x00, /*7D */ + 0x00, /*7E */ + 0x00, /*7F */ + 0xC5, /*80 L = 1, E = 0, D = 0 */ + 0x00, /*81 */ + 0x00, /*82 */ + 0x00, /*83 */ + 0x00, /*84 */ + 0x00, /*85 */ + 0x00, /*86 */ + 0x00, /*87 */ + 0x00, /*88 */ + 0x00, /*89 */ + 0x00, /*8A */ + 0x00, /*8B */ + 0x00, /*8C */ + 0x00, /*8D */ + 0x00, /*8E */ + 0x00, /*8F */ + 0x00, /*90 */ + 0x00, /*91 */ + 0x00, /*92 */ + 0x00, /*93 */ + 0x00, /*94 */ + 0x00, /*95 */ + 0x00, /*96 */ + 0x00, /*97 */ + 0x00, /*98 */ + 0x00, /*99 */ + 0x00, /*9A */ + 0x00, /*9B */ + 0x00, /*9C */ + 0x00, /*9D */ + 0x00, /*9E */ + 0x00, /*9F */ + 0xC4, /*A0 L = 1, E = 0, D = 1 */ + 0x00, /*A1 */ + 0x00, /*A2 */ + 0x00, /*A3 */ + 0x00, /*A4 */ + 0x00, /*A5 */ + 0x00, /*A6 */ + 0x00, /*A7 */ + 0x00, /*A8 */ + 0x00, /*A9 */ + 0x00, /*AA*/ 0x00, /*AB*/ 0x00, /*AC*/ 0x00, /*AD*/ 0x00, /*AE*/ 0x00, /*AF*/ 0x00, /*B0 */ + 0x00, /*B1 */ + 0x00, /*B2 */ + 0x00, /*B3 */ + 0x00, /*B4 */ + 0x00, /*B5 */ + 0x00, /*B6 */ + 0x00, /*B7 */ + 0x00, /*B8 */ + 0x00, /*B9 */ + 0x00, /*BA*/ 0x00, /*BB*/ 0x00, /*BC*/ 0x00, /*BD*/ 0x00, /*BE*/ 0x00, /*BF*/ 0xEB, /*C0 L = 1, E = 1, D = 0 */ + 0x00, /*C1 */ + 0x00, /*C2 */ + 0x00, /*C3 */ + 0x00, /*C4 */ + 0x00, /*C5 */ + 0x00, /*C6 */ + 0x00, /*C7 */ + 0x00, /*C8 */ + 0x00, /*C9 */ + 0x00, /*CA*/ 0x00, /*CB*/ 0x00, /*CC*/ 0x00, /*CD*/ 0x00, /*CE*/ 0x00, /*CF*/ 0x00, /*D0 */ + 0x00, /*D1 */ + 0x00, /*D2 */ + 0x00, /*D3 */ + 0x00, /*D4 */ + 0x00, /*D5 */ + 0x00, /*D6 */ + 0x00, /*D7 */ + 0x00, /*D8 */ + 0x00, /*D9 */ + 0x00, /*DA*/ 0x00, /*DB*/ 0x00, /*DC*/ 0x00, /*DD*/ 0x00, /*DE*/ 0x00, /*DF*/ 0xEA, /*E0 L = 1, E = 1, D = 1 */ + 0x00, /*E1 */ + 0x00, /*E2 */ + 0x00, /*E3 */ + 0x00, /*E4 */ + 0x00, /*E5 */ + 0x00, /*E6 */ + 0x00, /*E7 */ + 0x00, /*E8 */ + 0x00, /*E9 */ + 0x00, /*EA*/ 0x00, /*EB*/ 0x00, /*EC*/ 0x00, /*ED*/ 0x00, /*EE*/ 0x00, /*EF*/ 0x00, /*F0 */ + 0x00, /*F1 */ + 0x00, /*F2 */ + 0x00, /*F3 */ + 0x00, /*F4 */ + 0x00, /*F5 */ + 0x00, /*F6 */ + 0x00, /*F7 */ + 0x00, /*F8 */ + 0x00, /*F9 */ + 0x00, /*FA*/ + 0x00, /*FB*/ 0x00, /*FC*/ 0x00, /*FD*/ 0x00, /*FE*/ 0x00 /*FF*/ +}; + +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Opens an SDMA channel to be used by the library. + * + * <b>Algorithm:</b>\n + * + * - Check if initialization is necessary. + * - Check that user initialized OS dependant functions. + * - Test validity of input parameters + * - Check whole channel control block data structure + * - Finish initializations (tables with default values) + * - Initialize channel 0 is dedicated to communications with SDMA + * - Check channel control block definition + * - if the channel descriptor is not initialized, initialize it with + * the default value + * - If buffer descriptor already allocated, exit with iapi_errno filled + * complete the lowest bits with the number of 'D' bits set + * - Buffer Descriptors allocation + * - Channel's configuration properties (mcu side only) + * - read/write direction => enable/disable channel setting + * + * @param *cd_p -If channelNumber is 0, it is pointer to channel descriptor for the channnel 0 to be opened and + * has default values. + * For other channels,this function should be called after channel 0 has been opened, and it is channel descriptor for + * channel 0.Must be allocated. + * @param channelNumber channel to be opened + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed, return negated value of iapi_errno + */ +int iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber) +{ + channelControlBlock *ccb_p; + channelControlBlock *local_ccb_p; + channelDescriptor *local_cd_p; + bufferDescriptor *bd_p; + unsigned char index = 0; + int result = IAPI_SUCCESS; +#ifdef MCU + volatile unsigned long *channelPriorityMatx; +#endif /* MCU */ + + /* + * 1. Check if initialization is necessary + */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + return -result; + } + + /* Verify these functions every time */ + if ((iapi_GetChannel == NULL) || (iapi_ReleaseChannel == NULL)) { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + return -result; + } + + /* Try to aquire channel */ + if (iapi_GetChannel(channelNumber) != 0) { + result = IAPI_ERR_CH_IN_USE | channelNumber; + iapi_errno = result; + return -result; + } + + if (channelNumber == 0 && cd_p->ccb_ptr == NULL) { + /* Verify that the user initialized all OS dependant functions required + * by the library. + */ + if ((iapi_Malloc == NULL) || (iapi_Free == NULL) + || (iapi_Virt2Phys == NULL) || (iapi_Phys2Virt == NULL) + || (iapi_GotoSleep == NULL) || (iapi_WakeUp == NULL) + || (iapi_InitSleep == NULL) || (iapi_memset == NULL) + || (iapi_memcpy == NULL)) { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Whole channel control block data structure */ + ccb_p = (channelControlBlock *) + MALLOC(CH_NUM * sizeof(channelControlBlock), SDMA_IRAM); + if (ccb_p == NULL) { + result = IAPI_ERR_CCB_ALLOC_FAILED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Zero-out the CCB structures array just allocated */ + iapi_memset(ccb_p, 0x00, CH_NUM * sizeof(channelControlBlock)); + /* Save the address of the CCB structures array */ + iapi_CCBHead = ccb_p; + + cd_p->ccb_ptr = (struct iapi_channelControlBlock *)ccb_p; + ccb_p->channelDescriptor = cd_p; +#ifdef MCU + /* finish initializations */ + iapi_InitChannelTables(); +#endif /* MCU */ + /* Channel 0 is dedicated to communications with SDMA */ + cd_p->ownership = ((DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + cd_p->bufferDescNumber = 1; + } + + /* + * 2. Check channel control block + */ + ccb_p = cd_p->ccb_ptr; + if (ccb_p == NULL) { + result = + IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE | + channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + local_ccb_p = &ccb_p[channelNumber]; + local_cd_p = ccb_p[channelNumber].channelDescriptor; + + /* If the channel is not initialized, initialize it with the default value */ + if (local_cd_p == NULL) { + result = iapi_AllocChannelDesc(&local_cd_p, channelNumber); + if (result != IAPI_SUCCESS) { + iapi_ReleaseChannel(channelNumber); + /* is allready negated from iapi_AllocChannelDesc */ + return result; + } + + local_cd_p->ccb_ptr = + (struct iapi_channelControlBlock *)local_ccb_p; + local_ccb_p->channelDescriptor = local_cd_p; + } + + /* + * 3. If buffer descriptor already allocated, exit with iapi_errno filled + */ + if (local_ccb_p->baseBDptr != NULL) { + bd_p = + (bufferDescriptor *) iapi_Phys2Virt(local_ccb_p->baseBDptr); + result = IAPI_ERR_BD_ALLOCATED; + for (index = 1; index < local_cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.status & BD_DONE) == BD_DONE) { + /* complete the lowest bits with the number of 'D' bits set */ + result++; + } + bd_p++; + } + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* + * 4. Buffer Descriptors allocation + */ + iapi_InitializeMemory(local_ccb_p); + +#ifdef MCU + /* + * 5. Channel's configuration properties (mcu side only) + */ + iapi_ChannelConfig(channelNumber, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_EVT) & + 1UL, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_MCU) & + 1UL, + (local_cd_p->ownership >> CH_OWNSHP_OFFSET_DSP) & + 1UL); +#endif /* MCU */ + + /* Setting interrupt handling */ + iapi_ChangeCallbackISR(local_cd_p, local_cd_p->callbackISR_ptr); + + /* Call initialization fn for polling synch on this channel */ + INIT_SLEEP(channelNumber); + + /* No user arg pointer yet */ + userArgTable[cd_p->channelNumber] = NULL; + + /* + * 6. read/write direction => enable/disable channel + */ +#ifdef MCU + channelPriorityMatx = &SDMA_CHNPRI_0; + channelPriorityMatx[channelNumber] = 1; +#endif /* MCU */ + + local_ccb_p->status.openedInit = TRUE; + iapi_ReleaseChannel(channelNumber); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Attempts to read nbyte from the data buffer descriptor associated with the + * channel channelNumber, into the user's data buffer pointed to by buf. + * + * <b>Algorithm:</b>\n + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Control block & Descriptor associated with the channel being worked on + * - Check initialization has been done for trusted channels + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Set the 'D' done bits on all buffer descriptors + * - Starting of the channel + * - Synchronization mechanism handling: + * - for callback: just exit function + * - for polling: call the synchronization function then read data from + * buffer until either nbyte parameter is reached or all buffer descriptors + * have been processed. + * + * <b>Notes:</b>\n + * 1) Virtual DMA SDMA channels are unidirectional, an iapi_Read authorized + * on a channel means that we are expecting to receive from the SDMA. The + * meaning of an interrupt received from the SDMA is therefore that the + * data has been copied from the SDMA to the host's data buffers and is + * already passed on upper layers of the application.\n + * + * @param *cd_p chanenl descriptor for the channel to read from + * @param *buf buffer to receive the data + * @param nbyte number of bytes to read from channel + * + * @return + * - number of bytes read + * - -iapi_errno : in case of failure return negated value of iapi_errno + */ +int iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte) +{ + int index = 0; + int readBytes; + int toRead; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + int bufsize; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + unsigned char *local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Check if channel is already opened/initialized */ + if (ccb_p->status.openedInit == FALSE) { + result = + IAPI_ERR_CHANNEL_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | + chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->bufferAddr == NULL) + || (bd_p->mode.count == 0)) { + result = + IAPI_ERR_BD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required read length is + * divisible by transfer data size expressed in bytes + */ + if (cd_p->useDataSize) { + /*Check for divisibility only if data size different then 8bit */ + if (cd_p->dataSize != TRANSFER_8BIT) { + switch (cd_p->dataSize) { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default */ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested */ + if ((nbyte % div) != 0) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.count % div) != 0) { + result = + IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Set the 'D' done bits on all buffer descriptors + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + bd_p->mode.status |= BD_DONE; + bd_p++; + } + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel(chNum); + ccb_p->status.execute = TRUE; + readBytes = 0; + + /* + * 4. Synchronization mechanism handling + */ + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_SynchChannel(chNum); + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + toRead = nbyte; + copyFinished = FALSE; + local_buf = (unsigned char *)buf; + + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if (bd_p->mode.status & BD_RROR) { + result = IAPI_ERR_RROR_BIT_READ | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + + /* + * 5. Read loop + */ + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + while (!copyFinished) { + if (!(bd_p->mode.status & BD_DONE)) { + if (cd_p->trust == FALSE) { + bufsize = cd_p->bufferSize; + } else { + bufsize = bd_p->mode.count; + } + /*if L bit is set, read only "count" bytes and exit the loop */ + if (bd_p->mode.status & BD_LAST) { + bufsize = bd_p->mode.count; + copyFinished = TRUE; + } + if (toRead > bufsize) { + if (cd_p->trust == FALSE) { + iapi_memcpy(local_buf, + iapi_Phys2Virt + (bd_p->bufferAddr), + bufsize); + local_buf += bufsize; + } + readBytes += bufsize; + toRead -= bufsize; + /*advance bd_p only if bit L is not set. The loop will exit anyway. */ + if (!(bd_p->mode.status & BD_LAST)) { + if (bd_p->mode.status & BD_WRAP) { + bd_p = + (bufferDescriptor *) + iapi_Phys2Virt + (ccb_p->baseBDptr); + } else if (((bufferDescriptor *) + iapi_Phys2Virt + (ccb_p->baseBDptr) + + + (cd_p->bufferDescNumber + - + 1) * + sizeof + (bufferDescriptor)) + != bd_p) { + bd_p++; + } else { + /* finished here : end of buffer descriptors */ + copyFinished = TRUE; + } + } + } else { + if (cd_p->trust == FALSE) { + iapi_memcpy(local_buf, + iapi_Phys2Virt + (bd_p->bufferAddr), + toRead); + local_buf += toRead; + } + readBytes += toRead; + toRead = 0; + /* finished successfully : readBytes = nbytes */ + copyFinished = TRUE; + } + } else { + /* finished here : buffer not already done */ + copyFinished = TRUE; + } + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return readBytes; +} + +/* ***************************************************************************/ +/*Attempts to write nbyte from the buffer pointed to by buf to the channel + * data buffers associated with the opened channel number channelNumber + * + * <b>Algorithm:</b>\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - Buffer descriptor validity + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Write loop\n + * Write occurs in the buffer acceded form buffer descriptor and continues + * to the "next" buffer which can be:\n + * -# the last BD of the ring so re-start from beginning\n + * -# the last BD of the BD array but no ring so finish\n + * -# (general case) the next BD in the BD array\n + * And copy continues until data fit in the current buffer or the nbyte + * parameter is reached. + * - Starting of the channel + * + * <b>Notes:</b>\n + * 1) Virtual DMA SDMA channels are unidirectionnal, an iapi_Write authorized + * on a channel means that we are expecting to send to the SDMA. The + * meaning of an interrupt received from the SDMA is therfore that the + * data has been delivered to the SDMA. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *buf buffer with data to be written + * @param nbyte number of bytes to write to channel + * + * @return + * - number of bytes written + * - -iapi_errno if failure + */ +int iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte) +{ + unsigned int writtenBytes = 0; + unsigned int toWrite; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + unsigned int buffsize; + unsigned int index = 0; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + unsigned char *local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->bufferAddr == NULL) + || (bd_p->mode.count == 0)) { + result = + IAPI_ERR_BD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required write length is + * divisible by transfer data size expressed in bytes + */ + if (cd_p->useDataSize) { + /*Check for divisibility only if data size different then 8bit */ + if (cd_p->dataSize != TRANSFER_8BIT) { + switch (cd_p->dataSize) { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default */ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested */ + if ((nbyte % div) != 0) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD */ + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if ((bd_p->mode.count % div) != 0) { + result = + IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Write loop + */ + + local_buf = (unsigned char *)buf; + toWrite = nbyte; + copyFinished = FALSE; + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + + while (!copyFinished) { + + /* variable buffsize contains the nb of bytes that the SDMA will transfer at each pass of the while loop */ + + /* in NON trusted mode, buffsize is copied from Channel descriptor bufferSize (same size for all transfers) */ + if (cd_p->trust == FALSE) { + buffsize = cd_p->bufferSize; + } + /* in TRUSTED mode, it's up to the user to specify the size of each buffer thru an IoCtl call */ + /* This IoCtl has directly modified the bd_p->mode.count */ + /* therefore, buffersize is copied from the bd_p->mode.count */ + else { + buffsize = bd_p->mode.count; + } + + /* in any mode (trusted or non trusted), the transfer size must be overridden by */ + /* "toWrite" when there is less remaining bytes to transfer than the current buffer size */ + if (toWrite < buffsize) { + buffsize = toWrite; + } + + if (!(bd_p->mode.status & BD_DONE)) { + /* More data to write than a single buffer can contain */ + if (cd_p->trust == FALSE) { + iapi_memcpy(iapi_Phys2Virt(bd_p->bufferAddr), + local_buf, buffsize); + local_buf += buffsize; + } + + /* update the BD count that will be used by the SDMA to transfer the proper nb of bytes */ + bd_p->mode.count = buffsize; + + bd_p->mode.status |= BD_DONE; + writtenBytes += buffsize; + toWrite -= buffsize; + /* Prepares access to the "next" buffer */ + /* - case 1 - finished successfully : writtenBytes = nbytes */ + if (toWrite == 0) { + copyFinished = TRUE; + } + /* - case 2 - Last BD and WRAP bit set so re-start from beginning */ + /*else if ((bd_p->mode.status & BD_WRAP)){ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + } */ + /* - case 3 - Last BD of the BD but nor ring */ + else if (((bufferDescriptor *) + iapi_Phys2Virt(ccb_p->baseBDptr) + + (cd_p->bufferDescNumber - + 1) * sizeof(bufferDescriptor)) == bd_p) { + copyFinished = TRUE; + } + /* - case 4 - general : next BD in the BD array */ + else { + bd_p++; + } + + } else { + /* finished here : buffer not already done */ + copyFinished = TRUE; + } + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel(chNum); + ccb_p->status.execute = TRUE; + + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_SynchChannel(chNum); + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = 0; index < cd_p->bufferDescNumber; index++) { + if (bd_p->mode.status & BD_RROR) { + result = IAPI_ERR_RROR_BIT_WRITE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return writtenBytes; +} + +/* ***************************************************************************/ +/* This function is used to receive data from the SDMA. + * + * <b>Algorithm:</b>\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * + * <b>Notes:</b>\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to receive from + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * @return + * - IAPI_SUCCESS on success, IAPI_ERROR otherwise + * + *- -iapi_errno if failure + */ + +int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2) +{ + channelControlBlock *ccb_p; + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = + (dataNodeDescriptor *) data_control_struct_ipcv2; + + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if (ccb_p->baseBDptr == NULL) { + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* Copy the data Node descriptor information to new BDs */ + bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->baseBDptr); + + while (1) { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = + dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) { + /* Break the loop at End of Transfer */ + break; + + } + bd_ipcv2_p++; + dnd_p++; + + } + /* + * Store the buffer address + */ + dnd_read_control_struct[cd_p->channelNumber] = + (dataNodeDescriptor *) data_control_struct_ipcv2; + /* + * Register the Call Back + */ + + iapi_AttachCallbackISR(cd_p, iapi_read_ipcv2_callback); + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/* + * The function is used send a group of buffers to SDMA. + * <b>Algorithm:</b>\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * <b>Notes:</b>\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * + * + * @return + * - iapi sucess on success. + * - -iapi_errno if failure + */ + +int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2) +{ + + channelControlBlock *ccb_p; + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = + (dataNodeDescriptor *) data_control_struct_ipcv2; + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if (ccb_p->baseBDptr == NULL) { + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->currentBDptr); + /* Copy the data Node descriptor information to new BDs */ + while (1) { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; + +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = + dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) { + /* Break the loop at End of Transfer */ + break; + } + bd_ipcv2_p++; + dnd_p++; + + } + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/** Call back ISR for the IPCv2 Receive. + * + * <b>Algorithm:</b>\n + * - This would copy back the informationfrom IPCv1 BD to IPCv2 BD on + * the receiving processor + * + * @return + * - void + */ + +void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, void *data) +{ + /*cd_p->ccb_ptr->channelDNDBuffer; */ + dataNodeDescriptor *dnd_p = dnd_read_control_struct[cd_p->channelNumber]; + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p = + (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + int index = MAX_BD_NUM - 1; + + do { + dnd_p->mode.status = 0; + dnd_p->mode.count = bd_ipcv2_p->mode.count; + + dnd_p->mode.status |= + bd_ipcv2_p->mode.status & BD_DONE ? 0x00 : DND_DONE; + dnd_p->mode.status |= + bd_ipcv2_p-> + mode.status & BD_IPCV2_END_OF_FRAME ? DND_END_OF_FRAME : + 0x00; + dnd_p->mode.status |= + bd_ipcv2_p->mode.status & BD_LAST ? DND_END_OF_XFER : 0x00; + cd_p->ccb_ptr->currentBDptr = + (bufferDescriptor *) iapi_Virt2Phys(bd_ipcv2_p); + + if ((bd_ipcv2_p->mode.status & BD_LAST) != 0 || + (bd_ipcv2_p->mode.status & BD_CONT) == 0) + break; + dnd_p++; + bd_ipcv2_p++; + + } while (index--); + + /*Call back the Original ISR */ + cd_p->callbackISR_ptr(cd_p, data); +} + +/* ***************************************************************************/ +/**Terminates a channel. + * + * <b>Algorithm:</b>\n + * - Check input parameters ans data structures + * - Check that all buffes have been processed (test all 'D' bits) + * - Stop the channel execution + * - Free alocated memory structures + * - Re-instantiate default interrupt handling + * + * @param *cd_p chanenl descriptor for the channel to close + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed + */ +int iapi_Close(channelDescriptor *cd_p) +{ + int index = 0; + int result = IAPI_SUCCESS; + unsigned char chNum; + bufferDescriptor *bd_p; + channelControlBlock *ccb_p; + + /* + * 1. Check input parameters ans data structures + */ + if (cd_p != NULL) { + if (cd_p->ccb_ptr != NULL) { + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + } else { + result = + IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + } else { + result = IAPI_ERR_CD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + /* Try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Check that all buffes have been processed (test all 'D' bits), + * only if the forceClose bit in channel descriptor is set to FALSE + */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL) { + result = + IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + if (cd_p->forceClose == FALSE) { + for (index = cd_p->bufferDescNumber; index > 0; index--) { + if (bd_p->mode.status & BD_DONE) { + result = + IAPI_ERR_CLOSE | IAPI_ERR_CH_AVAILABLE | + chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + /*if the closing is forced,mark channel unused,set BD ownership to processor */ + else { + ccb_p->status.execute = FALSE; + for (index = cd_p->bufferDescNumber; index > 0; index--) { + bd_p->mode.status &= ~BD_DONE; + bd_p++; + } + } + + /* + * 3. Stop the channel execution + */ + iapi_lowStopChannel(chNum); + + /* + * 4. Free alocated memory structures + */ + if (cd_p->trust == FALSE) { + bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr); + for (index = cd_p->bufferDescNumber; index > 0; index--) { + FREE(iapi_Phys2Virt(bd_p->bufferAddr)); + bd_p++; + } + } + + /* + * 5. Re-instantiate default interrupt handling + */ + iapi_DetachCallbackISR(cd_p); + FREE((bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr)); + FREE(cd_p); + ccb_p->baseBDptr = NULL; + ccb_p->currentBDptr = NULL; + ccb_p->channelDescriptor = NULL; + ccb_p->status.openedInit = FALSE; + + iapi_ReleaseChannel(chNum); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**The request argument selects the control function to be performed. + * + * <b>Algorithm:</b>\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - The ctlRequest parameter contains in the lower 16 bits the control code of + * the change to be performed, and in the upper 16 bits, the BD to be + * modified if the change affects a BD od the channel. + * - Selection of the parameter to change and appropriate sanity checks: + * - Channel Descriptor: changes the pointer to the channel descriptor + * structure, the pointer to the new channel descriptor is given in the third + * argument call + * - Buffer Descriptor Number: changes the number of buffer descriptor for the + * channel + * - Buffer size: changes the size of the data buffers pointed to by the + * buffer descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain + * - Blocking policy: changes the blocking policy for the read and write calls + * - Ownership: changes direction: turnaround + * - Synchronization method: changes the callback type, default or user. The* + * callback function table is set accordingly + * - Trust property: trust can only be changed through ChangeChannelDesc first + * request, this guarantees the close/open sequence for the channel + * - Callback Interrupt service routine pointer: changes the callback function + * pointer, when this method is used, to replace it with a new one + * - Channel control block pointer: not available + * - Priority: changes the channel priority directly in SDMA register + * - Watermark level: changes the value of the peripheral watermark level that + * passed to the script. The new value is passed in the third parameter call. + * - Wrap bit: changes to set to 1 the Wrap bit of the last buffer descriptor + * + * @param *cd_p channel descriptor for the channel to modify + * @param ctlRequest request control code and, if tha case, number of BD to be + * changed + * @param param parameter for the modification + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed + */ +int +iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest, + unsigned long param) +{ + int retvalue; + int result = IAPI_SUCCESS; + unsigned char chNum; + unsigned long clean_ctlRequest; /* lower 16 bits of the ctlRequest */ + unsigned long bd_num; /* upper 16 bits of the ctlRequest */ + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + + /* Remove, if exists, BD number specified in upper bits of ctlRequest */ + clean_ctlRequest = ctlRequest & (~BD_NUM_MASK); + + /* Extract, if exists, BD number specified in upper bits of ctlRequest */ + bd_num = (ctlRequest & BD_NUM_MASK) >> BD_NUM_OFFSET; + + /* Check that the bd_num is valid */ + if (bd_num > cd_p->bufferDescNumber) { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + return -result; + } + + /*All checks OK, try to aquire channel */ + if (iapi_GetChannel(chNum) != 0) { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Selection of the parameter to change and appropriate sanity checks + */ + switch (clean_ctlRequest) { + + /* + * Channel Descriptor + * --- Changes the pointer to the channel descriptor structure: the pointer + * to the new channel descriptor is given in the third argument call. + */ + case IAPI_CHANGE_CHANDESC: + if ((void *)param == NULL) { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } else { + channelDescriptor *chParam = + (channelDescriptor *) param; + if (chParam->channelNumber != chNum) { + /* Release ch so it can be aquired by the Close fn */ + iapi_ReleaseChannel(chNum); + result = iapi_Close(cd_p); + if (result == IAPI_SUCCESS) { + FREE((void *)cd_p); + iapi_AllocChannelDesc(&cd_p, + chParam->channelNumber); + iapi_memcpy((void *)cd_p, + (void *)chParam, + sizeof(channelDescriptor)); + /* Channel is released allready, so Open can get the channel */ + result = + iapi_Open(cd_p, + chParam->channelNumber); + if (result != IAPI_SUCCESS) { + return result; /* error code already set in iapi_Open */ + } + } else { + return result; /* error code already set in iapi_Close */ + } + } else { + result = + IAPI_ERR_CD_CHANGE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_ReleaseChannel(chNum); + iapi_errno = result; + return -result; + } + return IAPI_SUCCESS; + } + + /* + * Buffer Descriptor Number + * --- Changes the number of buffer descriptor for the channel. + */ + case IAPI_CHANGE_BDNUM: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Buffer size + * --- Changes the size of the data buffers pointed to by the buffer + * descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain. + */ + case IAPI_CHANGE_BUFFSIZE: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Blocking policy + * --- Changes the blocking policy for the read and write calls. + */ + case IAPI_CHANGE_CHANBLOCK: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BLOCKING, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Ownership + * --- Changes direction: turnaround + */ + case IAPI_CHANGE_OWNERSHIP: + result = iapi_ChangeChannelDesc(cd_p, IAPI_OWNERSHIP, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Synchronization method + * --- Changes the callback type, default or user. The callback function + * table is set accordingly. + */ + case IAPI_CHANGE_SYNCH: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKSYNCH, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Trust property + * --- trust can only be changed through ChangeChannelDesc first request, + * this guarantees the close/open sequence for the channel. + */ + case IAPI_CHANGE_TRUST: + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Callback Interrupt service routine pointer + * --- Cahnges the callback function pointer, when this method is used, to + * replace it with a new one. + */ + case IAPI_CHANGE_CALLBACKFUNC: + result = + iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKISR_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Channel control block pointer + * --- NA + */ + case IAPI_CHANGE_CHANCCB: + result = iapi_ChangeChannelDesc(cd_p, IAPI_CCB_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + +#ifdef MCU + /* + * Priority + * --- Changes the channel priority directly in SDMA register + */ + case IAPI_CHANGE_PRIORITY: + { + volatile unsigned long *ChannelPriorities = + &SDMA_CHNPRI_0; + if (param < MAX_CH_PRIORITY) { + ChannelPriorities[cd_p->channelNumber] = param; + } else { + iapi_ReleaseChannel(chNum); + return IAPI_FAILURE; + } + } + break; +#endif /* MCU */ + + /* + * Wrap + * --- Set to 1 the wrap bit of the last buffer descriptor of the array. + * it provides the possibility to have a circular buffer structure. + */ + case IAPI_CHANGE_BDWRAP: + { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BDWRAP, param); + iapi_ReleaseChannel(chNum); + return result; + } + + /* + * Watermark + * --- Changes the value of the peripheral watermark level that triggers + * a DMA request. It impacts context of the channel, therefore channel 0 + * must be started to update the context with this new value. + */ + case IAPI_CHANGE_WATERMARK: + { + result = iapi_ChangeChannelDesc(cd_p, IAPI_WML, param); + iapi_ReleaseChannel(chNum); + return result; + } + /* + * INTR + * --- Set the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDINTR: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_INTR; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_INTR; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * INTR + * --- Unset the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDINTR: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_INTR; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_INTR; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +/* + * EventMask1 + * --- Changes the value of the eventMask1 + */ + case IAPI_CHANGE_EVTMASK1: + { + cd_p->eventMask1 = param; + } + break; + /* + * EventMask2 + * --- Changes the value of the eventMask2 + */ + case IAPI_CHANGE_EVTMASK2: + { + cd_p->eventMask2 = param; + } + break; + /* + * Peripheral Address + * --- Changes the value of the peripheralAddr + */ + case IAPI_CHANGE_PERIPHADDR: + { + cd_p->peripheralAddr = param; + } + break; + /* + * Cont + * --- Set the CONT bit on specified BD on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDCONT: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_CONT; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_CONT; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * Cont + * --- Unset the CONT bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDCONT: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_CONT; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_CONT; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * EXTD + * --- Set the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDEXTD: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status |= BD_EXTD; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_EXTD; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTD + * --- Unset the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDEXTD: + { + bufferDescriptor *bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.status &= ~BD_EXTD; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_EXTD; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * TRANSFER SIZE to be used for this channel + * --- Set the transfer size used indicator and code for transfer size in + * the CD + */ + case IAPI_CHANGE_SET_TRANSFER_CD: + { + bufferDescriptor *bde_p; + int j = 0; + retvalue = IAPI_SUCCESS; + if ((param == TRANSFER_8BIT) + || (param == TRANSFER_16BIT) + || (param == TRANSFER_24BIT) + || (param == TRANSFER_32BIT)) { + cd_p->useDataSize = TRUE; + cd_p->dataSize = param; + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = param; + bde_p++; + } + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * USER_ARG + * --- Set the user selectable pointer to be received by the callback + * function, if IRQ synch is used + */ + case IAPI_CHANGE_USER_ARG: + { + userArgTable[cd_p->channelNumber] = (void *)param; + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; + } + /* + * FORCE_CLOSE + * --- Set the forceClose bit in channelDescriptor to value passed in param. + * If this bit is TRUE, the channel in closed even if some BD are still + * owned by the SDMA. + */ + case IAPI_CHANGE_FORCE_CLOSE: + { + retvalue = IAPI_SUCCESS; + if ((param == TRUE) || (param == FALSE)) { + cd_p->forceClose = param; + } else { + iapi_errno = + IAPI_ERR_INVALID_PARAMETER | + cd_p->channelNumber; + retvalue = -iapi_errno; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * TRANSFER type + * --- Set the last 2 bits in the command field of the BD to specify the + * transfer type 8, 16, 24, or 32 bits on all BD's, allready set in the CD + */ + case IAPI_CHANGE_SET_TRANSFER: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if ((param == TRANSFER_8BIT) + || (param == TRANSFER_16BIT) + || (param == TRANSFER_24BIT) + || (param == TRANSFER_32BIT)) { + bde_p = cd_p->ccb_ptr->baseBDptr; + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = param; + bde_p++; + } + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Change buffer address in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_BUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to physical */ + bde_p->bufferAddr = (void *)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Get the buffer address from the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_BUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Translate to virtual */ + *((unsigned long *)param) = + (unsigned long)bde_p->bufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Change extended buffer address in BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_SET_EXTDBUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to physical. The user might want something else + *here + */ + bde_p->extBufferAddr = (void *)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Get extended buffer address from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_EXTDBUFFERADDR: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + + /* DO NOT translate address to vitual - user knows what is here. + */ + *((unsigned long *)param) = + (unsigned long)bde_p->extBufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Change command field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COMMAND: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update command field */ + bde_p->mode.command = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Get the command field from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_COMMAND: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Get the command field */ + *((unsigned long *)param) = bde_p->mode.command; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Change count field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COUNT: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update count field */ + bde_p->mode.count = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Get the count field of the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_COUNT: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update count field */ + *((unsigned long *)param) = bde_p->mode.count; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Change status field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_STATUS: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update status field */ + bde_p->mode.status = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Get the status field of the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_STATUS: + { + bufferDescriptor *bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change */ + bde_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bde_p += bd_num; + /* Update status field */ + *((unsigned long *)param) = bde_p->mode.status; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + +#ifdef MCU + /* + * Endianness + * --- Set the ENDIANNESS indicator in the command filed of the specified BD + * or on all BD's if SET_BIT_ALL is passed as parameter. + */ + case IAPI_CHANGE_SET_ENDIANNESS: + { + bufferDescriptor *bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if (param == SET_BIT_ALL) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (j = 0; j < cd_p->bufferDescNumber; j++) { + bde_p->mode.command = CHANGE_ENDIANNESS; + bde_p++; + } + } else if (param < cd_p->bufferDescNumber) { + bde_p = + (bufferDescriptor *) + iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.command = CHANGE_ENDIANNESS; + } else { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +#endif + +#ifdef SDMA_SKYE +#ifdef MCU + + /* + * SDMA State + * --- Enter the SDMA into LOCK Mode. No RAM updation allowed except same Context + * update with same PC Value. + */ + case IAPI_ENTER_LOCK_MODE: + { + if (param == RESET_CLEAR_LOCK) { + SDMA_SDMA_LOCK = (1 << RESET_CLR_BIT_OFFSET); + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } else if (param == RESET_NOCLEAR_LOCK) { + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } + + } + break; + +#endif +#endif + default: + retvalue = + IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = retvalue; + iapi_ReleaseChannel(chNum); + return -retvalue; + } + + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Initialization of the SDMA - opening of channel 0, download RAM image. + * + * <b>Algorithm:</b>\n + * - open channel 0 + * - if ram_image pointer passed is not NULL, download RAM image to SDMA + * + * @param + * - cd_p channel descriptor pointer for channel 0 + * - ram_image pointer to RAM image to download, or NULL if this operation + * is not required + * - code_size size of the RAM image, in bytes + * - start_addr start address for the RAM image + * + * @return + * - IAPI_SUCCESS if all operations were successful + * - negated I.API error code if any operation failed + */ +#ifdef MCU +int +iapi_Init(channelDescriptor *cd_p, configs_data *config_p, + unsigned short *ram_image, unsigned short code_size, + unsigned long start_addr) +{ +#endif +#ifdef DSP + int + iapi_Init(channelDescriptor *cd_p) { +#endif + + int retvalue = IAPI_SUCCESS; /* Variable to store the results from I.API calls */ + + /* Check initialization not allredy done */ + if (iapi_CCBHead != NULL) { + retvalue = IAPI_ERR_NOT_ALLOWED; + iapi_errno = retvalue; + return -retvalue; + } + /* Be sure SDMA has not started yet */ +#ifdef MCU + SDMA_H_C0PTR = 0x0; +#endif +#ifdef DSP + SDMA_D_C0PTR = 0x0; +#endif + + /*Try to open channel 0 */ + retvalue = iapi_Open(cd_p, 0); + if (retvalue != IAPI_SUCCESS) { + return retvalue; + } +#ifdef MCU + /* Set Command Channel (Channel Zero) */ + SDMA_CHN0ADDR = 0x4050; + + /* Set bits of CONFIG register but with static context switching */ + SDMA_H_CONFIG = + (config_p-> + dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr + << 4) | (0); + + /* Send the address for the host channel table to the SDMA */ + SDMA_H_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); + /* If required, download the RAM image for SDMA */ + if (ram_image != NULL) { + retvalue = + iapi_SetScript(cd_p, (void *)ram_image, code_size, + start_addr); + } + + /* Set bits of CONFIG register with given context switching mode */ + SDMA_H_CONFIG = + (config_p-> + dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr + << 4) | + (config_p->csm); + +#endif +#ifdef DSP + /* Send the address for the host channel table to the SDMA */ + SDMA_D_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); +#endif + +#ifdef SDMA_SKYE + iapi_SdmaState = OPEN; +#endif + + return retvalue; + } + +/* ***************************************************************************/ +/**High layer interface for starting a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for starting a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_StartChannel(unsigned char channel) +{ + iapi_lowStartChannel(channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for stopping a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_StopChannel(unsigned char channel) +{ + iapi_lowStopChannel(channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for synchronising a channel + * + * <b>Algorithm:</b>\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SynchChannel(unsigned char channel) +{ + iapi_lowSynchChannel(channel); + return IAPI_SUCCESS; +} + +#ifdef MCU +/* ***************************************************************************/ +/**High layer interface for getting program memory data from SDMA + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_GetScript(channelDescriptor *cd_p, void *buf, + unsigned short size, unsigned long address) +{ + iapi_lowGetScript(cd_p, buf, size, address); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for getting data memory from SDMA + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_GetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel) +{ + iapi_lowGetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set program memory data to SDMA - e.g. scripts + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetScript(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned long destAddr) +{ + iapi_lowSetScript(cd_p, buf, nbyte, destAddr); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set data memory to SDMA - e.g. contexts. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetContext(channelDescriptor *cd_p, void *buf, + unsigned char channel) +{ + iapi_lowSetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p) +{ + /* VERIFY THAT THE CHANNEL IT IS OPENED !!!! */ + return iapi_lowAssignScript(cd_p, data_p); +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * <b>Algorithm:</b>\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SetChannelEventMapping(unsigned char event, + unsigned long channel_map) +{ + return iapi_lowSetChannelEventMapping(event, channel_map); +} +#endif + +#ifdef DSP +#define SDMA_DI SDMA_D_INTR + void IRQ_Handler(); +#pragma interrupt IRQ_Handler +#endif + +#ifdef MCU +#define SDMA_DI SDMA_H_INTR +#endif + +#ifndef IRQ_KEYWORD +#define IRQ_KEYWORD +#endif /* IRQ_KEYWORD */ + +/* ***************************************************************************/ +/** + *@brief Find the first set bit in data parameter. + * + * Find the first set bit in unsigned integer parameter data. Data is scanned + * from MSB to LSB, searching for the set bit. The value returned is the + * offset from the most significant bit of data. If bit 31 is set, the value + * returned is zero. If no bits are set, a value of 32 is returned. This is compliant + * with the MCore FF1 instruction. + * + * + * + * @param + * - data: variable to check + * + * @return + * - the offset of the most significant bit set from the MSB + */ +unsigned int quartz_FF1(unsigned int data) +{ + register unsigned int result = 0; + while ((result <= 31) && !(data & 0x80000000U)) { + data <<= 1U; + result++; + } + + return result; +} + +IRQ_KEYWORD void IRQ_Handler(void) +{ + unsigned int intrReg; /* interrupt register mask for clearing the interrupt bit */ + unsigned char chNum; /* SDMA channel number generating the a IRQ */ + + /* Disable interrupts */ + iapi_DisableInterrupts(); + /* + * Clear interrupt in SDMA DI register => ACK to the SDMA the IT request. + * Get each interrupt number, clear them one after the other. + */ + if (SDMA_DI != 0) { + chNum = + (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } else { + chNum = 32; + intrReg = 0; + } + + while (intrReg != 0) { + SDMA_DI &= intrReg; + iapi_SDMAIntr |= intrReg; + iapi_WakeUp(chNum); + if (callbackIsrTable[chNum] != NULL) { + /* release channel before callback, so IoCtl's are available */ + iapi_ReleaseChannel(chNum); + callbackIsrTable[chNum] (iapi_CCBHead + [chNum].channelDescriptor, + userArgTable[chNum]); + } + + chNum = + (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } + + /* Enable interrupts */ + iapi_EnableInterrupts(); +} + +/* ***************************************************************************/ +/** + *@brief Perform a memory copy operation, in the memory of the same processor + * + * Size bytes are copied from the src address to dest address. It is used + * the channel pointed by cd_p, which must be configured prior to this call: + * opened, associated with the script to perform the operation - DSP_2_DSP, + * or MCU_2_MCU - and have the synchronization option set. + * + * + * + * @param + * - cd_p: channel configured to perform DSP_2_DSP or MCU_2_MCU transfers + * - dest: destination memory address + * - src : source memory address + * - size: number of bytes to copy from src to dest + * + * @return + * - the offset of the most significant bit set from the MSB + */ + +int iapi_MemCopy(channelDescriptor *cd_p, void *dest, void *src, + unsigned long size) +{ + int result = IAPI_SUCCESS; + bufferDescriptor *bd_p; + + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Check and set correct parameter */ + if (cd_p->trust != TRUE) { + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, TRUE); + } + + if (cd_p->bufferDescNumber != 1) { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, + 1); + if (result != IAPI_SUCCESS) { + return result; + } + } + + if (cd_p->bufferSize != size) { + result = + iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, size); + if (result != IAPI_SUCCESS) { + return result; + } + } + /* Set addresses */ + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + bd_p->bufferAddr = iapi_Virt2Phys(src); + bd_p->extBufferAddr = iapi_Virt2Phys(dest); + + /* Set mode */ + bd_p->mode.count = size; + bd_p->mode.command = 0x00; + bd_p->mode.status = BD_INTR | BD_EXTD | BD_DONE | BD_WRAP; + + /*Decide if we sleep or not */ + if (cd_p->callbackSynch == DEFAULT_POLL) { + iapi_StartChannel(cd_p->channelNumber); + /* Call synchronization routine */ + iapi_SynchChannel(cd_p->channelNumber); + } else { + /* Just start the channel */ + iapi_StartChannel(cd_p->channelNumber); + } + + return result; +} + +/* ***************************************************************************/ +/**Return the channel number from the channel descriptor + * + * @param cd_p pointer to channel descriptor to obtain the channel number + * + * @return + * - the channel number + * + */ +int iapi_GetChannelNumber(channelDescriptor *cd_p) +{ + return cd_p->channelNumber; +} + +/* ***************************************************************************/ +/**Return the error bit from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - 0 if no error detected + * - BD_RROR | DATA_ERROR if error detected + * + */ +unsigned long iapi_GetError(channelDescriptor *cd_p) +{ + return (cd_p->ccb_ptr->currentBDptr->mode.status & BD_RROR) | + (*(unsigned long *)&cd_p->ccb_ptr->status & DATA_ERROR); +} + +/* ***************************************************************************/ +/**Return the count from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - count field of the current BD for the channel + * + */ +int iapi_GetCount(channelDescriptor *cd_p) +{ + return (int)(cd_p->ccb_ptr->currentBDptr->mode.count); +} + +/* ***************************************************************************/ +/**Return the sum of counts for all the BD's owned by the processor for + * the channel specified by the received parameter. + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - sum of count fields + * + */ +int iapi_GetCountAll(channelDescriptor *cd_p) +{ + int retval = 0; + int i = 0; + bufferDescriptor *bd_p; + + bd_p = cd_p->ccb_ptr->baseBDptr; + + while ((i < cd_p->bufferDescNumber) + && ((bd_p->mode.status & BD_DONE) == 0)) { + retval += bd_p->mode.count; + i++; + bd_p++; + } + return retval; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c new file mode 100644 index 000000000000..47611fe52743 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLow.c + * + * $Id iapiLow.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API. + * + * + * / + * + * $Log iapiLow.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <linux/preempt.h> +#include <linux/hardirq.h> +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ + +/* ***************************************************************************/ +/**Records an ISR callback function pointer into the ISR callback + * function table + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_AttachCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + if (cd_p->callbackSynch == CALLBACK_ISR) { + iapi_DisableInterrupts(); + callbackIsrTable[cd_p->channelNumber] = func_p; + iapi_EnableInterrupts(); + } else if (cd_p->callbackSynch == DEFAULT_POLL) { + callbackIsrTable[cd_p->channelNumber] = NULL; + } else { + iapi_errno = + IAPI_ERR_CALLBACKSYNCH_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + } +} + +/* ***************************************************************************/ +/**Detaches (removes) an ISR callback function pointer from the ISR callback + * function table + * + * <b>Algorithm:</b>\n + * - Attach a null function to replace the original one. + * + * @param cd_p channel descriptor to detach callback from + * + * @return none + */ +void iapi_DetachCallbackISR(channelDescriptor *cd_p) +{ + iapi_AttachCallbackISR(cd_p, NULL); +} + +/* ***************************************************************************/ +/**Updates an ISR callback function pointer into the ISR callback function + * table + * + * <b>Algorithm:</b>\n + * - Detach the old function pointer (if any) and attach the new one + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_ChangeCallbackISR(channelDescriptor *cd_p, + void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + iapi_DetachCallbackISR(cd_p); + iapi_AttachCallbackISR(cd_p, func_p); +} + +/* ***************************************************************************/ +/**Loop while the channel is not done on the SDMA + * + * <b>Algorithm:</b>\n + * - Loop doing nothing but checking the I.API global variable to indicate + * that the channel has been completed (interrupt from SDMA) + * + * <b>Notes:</b>\n + * - The ISR must update the I.API global variable iapi_SDMAIntr. + * + * @param channel channel number to poll on + * + * @return none + */ +void iapi_lowSynchChannel(unsigned char channel) +{ + if (preempt_count() || in_interrupt()) { + while (!((1UL << channel) & iapi_SDMAIntr)) + ; + } else + GOTO_SLEEP(channel); + + iapi_SDMAIntr &= ~(1UL << channel); +} + +/* ***************************************************************************/ +/**Fill the buffer descriptor with the values given in parameter. + * + * @return none + */ +void +iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command, + unsigned char status, unsigned short count, + void *buffAddr, void *extBufferAddr) +{ + bd_p->mode.command = command; + bd_p->mode.status = status; + bd_p->mode.count = count; + if (buffAddr != NULL) { + bd_p->bufferAddr = iapi_Virt2Phys(buffAddr); + } else { + bd_p->bufferAddr = buffAddr; + } + bd_p->extBufferAddr = extBufferAddr; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c new file mode 100644 index 000000000000..345d36433cf3 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c @@ -0,0 +1,503 @@ +/****************************************************************************** + * + * Copyright 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowMcu.c + * + * $Id iapiLowMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API specific to MCU. + * + * + * http://compass/mot.com/go/115342679 + * + * $Log iapiLowMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include <string.h> +#include <io.h> + +#include "epm.h" +#include "iapiLow.h" + +/* **************************************************************************** + * Function Section + *****************************************************************************/ +#ifdef MCU + +/* ***************************************************************************/ +/**Send a command on SDMA's channel zero. + * Check if buffer descriptor is already used by the sdma, if yes return + * an error as c0BDNum is wrong. + * + * <b>Notes</b>\n + * There is an upgrade in the script on the Context load command and + * the fact that the context structure has a fixed length of 20 or 24 + * depending on SDMA versions. + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if failure + */ +int +iapi_Channel0Command(channelDescriptor *cd_p, void *buf, + unsigned short nbyte, unsigned char command) +{ + channelControlBlock *ccb_p; + bufferDescriptor *bd_p; + int result = IAPI_SUCCESS; + unsigned char chNum; + + /* + * Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Is channel already in use ? */ + if (ccb_p->baseBDptr != NULL) { + result = IAPI_ERR_BD_ALLOCATED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Allocation of buffer descriptors */ + bd_p = (bufferDescriptor *) MALLOC(sizeof(bufferDescriptor), SDMA_ERAM); + if (bd_p != NULL) { + ccb_p->baseBDptr = (bufferDescriptor *) iapi_Virt2Phys(bd_p); + } else { + result = IAPI_ERR_BD_ALLOCATION | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor setting */ + iapi_SetBufferDescriptor(bd_p, command, BD_WRAP | BD_DONE | BD_INTR, + nbyte, buf, NULL); + + /* Actually the transfer */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); + + /* Cleaning of allocation */ + FREE(bd_p); + ccb_p->baseBDptr = NULL; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/**Starts the channel (core specific register) + * + * <b>Algorithm:</b>\n + * - Bit numbered "channel" of HostEnStartReg register is set + * + * @param channel channel to start + * + * @return none + */ +void iapi_lowStartChannel(unsigned char channel) +{ + /* HSTART is a 'write-ones' register */ + writel(1UL << channel, SDMA_H_START_ADDR); +} + +/* ***************************************************************************/ +/**Stops the channel (core specific register) + * + * <b>Algorithm:</b> + * - Bit numbered "channel" of HostEnStopReg register is cleared + * + * <b>Notes:</b>\n + * - This is a write one to clear register + * + * @param channel channel to stop + * + * @return none + */ +void iapi_lowStopChannel(unsigned char channel) +{ + /* Another 'write-ones' register */ + writel(1UL << channel, SDMA_H_STATSTOP_ADDR); +} + +/* ***************************************************************************/ +/**Initialize the initial priority of registers and channel enable + * RAM from the MCU side. No channels are enabled, all priorities are set to 0. + * + * @return none + */ +void iapi_InitChannelTables(void) +{ + + /* No channel is enabled */ + iapi_memset((void *)&SDMA_CHNENBL_0, 0x00, + sizeof(unsigned long) * EVENTS_NUM); + /* All channels have priority 0 */ + iapi_memset((void *)&SDMA_CHNPRI_0, 0x00, + sizeof(unsigned long) * CH_NUM); +} + +/* ***************************************************************************/ +/** The host enable (HE), hosts override (HO), dsp enable (DE), dsp override + * (DO) registers are involved here. + * Host and Dsp enable registers are here to signify that the MCU or DSP side + * have prepared the appropriate buffers and are now ready. If the channel is + * owned by the MCU the override bit for that channel needs to be cleared : + * the host allows the channel to be used.\n + * + * Then the override bits can define (mcuOverride dspOverride):\n + * - 0 0 channel is public: transfer to/from MCU to DSP + * - 0 1 channel if owned by DSP + * - 1 0 channel if owned by MCU + * - 1 1 channel zero config + * + * See also :\n + * IAPI Table 1.1 "Channel configuration properties" + * + * @param channel channel to configure + * @param eventOverride event ownership + * @param mcuOverride ARM ownership + * @param dspOverride DSP ownership + * + * @return + * - -iapi_errno if the 3 override parameters are all set + * - IAPI_SUCCESS in other cases (valid cases) + */ +int +iapi_ChannelConfig(unsigned char channel, unsigned eventOverride, + unsigned mcuOverride, unsigned dspOverride) +{ + int result = IAPI_SUCCESS; + + if ((eventOverride == 1) && (mcuOverride == 1) && (dspOverride == 1)) { + result = IAPI_ERR_CONFIG_OVERRIDE; + iapi_errno = result; + return -result; + } else { + /* + * DSP side + */ + if (dspOverride) { + SDMA_H_DSPOVR &= ~(1 << channel); + } else { + SDMA_H_DSPOVR |= (1 << channel); + } + /* + * Event + */ + if (eventOverride) { + SDMA_H_EVTOVR &= ~(1 << channel); + } else { + SDMA_H_EVTOVR |= (1 << channel); + } + /* + * MCU side + */ + if (mcuOverride) { + SDMA_H_HOSTOVR &= ~(1 << channel); + } else { + SDMA_H_HOSTOVR |= (1 << channel); + } + } + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Load the context data of a channel from SDMA + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters + * - Start channel + * - Poll for answer + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive context data + * @param channel channel for which the context data is requested + * + * @return none + */ +void +iapi_lowGetContext(channelDescriptor *cd_p, void *buf, unsigned char channel) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], + C0_GETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | + BD_EXTD), + (unsigned short)sizeof(contextData) / 4, buf, + (void *)(CHANNEL_CONTEXT_BASE_ADDRESS + + (sizeof(contextData) * channel / 4))); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Read "size" byte /2 at SDMA address (address) and write them in buf + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters (C0_GETPM) + * - Start channel + * - Poll for answer + * + * <b>Notes</b>\n + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be loaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive the data + * @param size number of bytes to read + * @param address address in SDMA RAM to start reading from + * + * @return none + */ +void +iapi_lowGetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], C0_GETPM, (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), (unsigned short)size / 2, /*count in shorts */ + buf, (void *)address); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Load a SDMA script to SDMA + * + * <b>Algorithm:</b>\n + * - Setup BD with appropiate parameters (C0_SETPM) + * - Start channel + * - Poll for answer + * + * <b>Notes</b>\b + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be uploaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to the script + * @param size size of the script, in bytes + * @param address address in SDMA RAM to place the script + * + * @return none + */ +void +iapi_lowSetScript(channelDescriptor *cd_p, void *buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor *bd_p; + + bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command */ + iapi_SetBufferDescriptor(&bd_p[0], C0_SETPM, (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), (unsigned short)size / 2, /*count in shorts */ + buf, (void *)(address)); + /* Receive, polling method */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Load the context for a channel to SDMA + * + * <b>Algorithm:</b>\n + * - Send context and poll for answer. + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to context data + * @param channel channel to place the context for + * + * @return none + */ +void +iapi_lowSetContext(channelDescriptor *cd_p, void *buf, unsigned char channel) +{ + + bufferDescriptor *local_bd_p; +#ifdef SDMA_SKYE + + unsigned char command = 0; + + local_bd_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + command = channel << 3; + command = command | C0_SETCTX; + iapi_SetBufferDescriptor(&local_bd_p[0], + command, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP), + (unsigned short)(sizeof(contextData) / 4), + buf, NULL); +#else + + local_bd_p = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + iapi_SetBufferDescriptor(&local_bd_p[0], + C0_SETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | + BD_EXTD), + (unsigned short)(sizeof(contextData) / 4), buf, + (void *)(2048 + + (sizeof(contextData) / 4) * channel)); +#endif + /* Send */ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); + +} + +/* ***************************************************************************/ +/**Associate specified channel with the script starting at the + * specified address. Channel 0 command is used to load the set-up context + * for the channel. The address used must be generated by the GUI tool + * used to create RAM images for SDMA. + * + * <b>Algorithm:</b>\n + * - Set-up and load the context. + * + * @param *cd_p pointer to the channel descriptor of the channel + * @param *data_p: pointer to the data identifying the script to be associated + * with the channel + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ + +int iapi_lowAssignScript(channelDescriptor *cd_p, script_data * data_p) +{ + contextData *chContext; /* context to be loaded for the channel */ + channelDescriptor *cd0_p; /* pointer to channel descriptor of channel 0 */ + int result = IAPI_SUCCESS; + + /*Verify passed data */ + if (cd_p == NULL || data_p == NULL) { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + return -result; + } + + /* Allocate context and initialize PC to required script start adress */ + chContext = (contextData *) MALLOC(sizeof(contextData), SDMA_ERAM); + if (chContext == NULL) { + result = IAPI_ERR_B_ALLOC_FAILED | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + iapi_memset(chContext, 0x00, sizeof(contextData)); + chContext->channelState.pc = data_p->load_address; + + /* Send by context the event mask,base address for peripheral + * and watermark level + */ + chContext->gReg[0] = data_p->event_mask2; + chContext->gReg[1] = data_p->event_mask1; + chContext->gReg[6] = data_p->shp_addr; + chContext->gReg[7] = data_p->wml; + if (data_p->per_addr) + chContext->gReg[2] = data_p->per_addr; + + /* Set transmited data to the CD */ + cd_p->watermarkLevel = data_p->wml; + cd_p->eventMask1 = data_p->event_mask1; + cd_p->eventMask2 = data_p->event_mask2; + + /* Get the cd0_p */ + cd0_p = (cd_p->ccb_ptr - cd_p->channelNumber)->channelDescriptor; + + /*load the context */ + iapi_lowSetContext(cd0_p, chContext, cd_p->channelNumber); + + /* release allocated memory */ + FREE(chContext); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Set the channels to be triggered by an event. The for every channel that + *must be triggered by the event, the corresponding bit from channel_map + *parameter must be set to 1. (e.g. for the event to trigger channels 31 and + *0 one must pass 0x80000001) + * + * + * <b>Algorithm:</b>\n + * - Update the register from Channel Enable RAM with the channel_map + * + * @param event event for which to set the channel association + * @param channel_map channels to be triggered by event. Put the corresponding + * bit from this 32-bit value to 1 for every channel that should be + * triggered by the event. + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ +int +iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map) +{ + volatile unsigned long *channelEnableMatx; + int result = IAPI_SUCCESS; + + /* Check validity of event */ + if (event < EVENTS_NUM) { + channelEnableMatx = &SDMA_CHNENBL_0; + channelEnableMatx[event] |= channel_map; + return result; + } else { + result = IAPI_ERR_INVALID_PARAMETER | event; + iapi_errno = result; + return -result; + } +} + +#endif /* MCU */ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c new file mode 100644 index 000000000000..185489295523 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c @@ -0,0 +1,644 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddle.c + * + * $Id iapiMiddle.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API. + * + * + * + * + * $Log iapiMiddle.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include <string.h> + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Allocates one Buffer Descriptor structure using information present in the + * channel descriptor. + * + * @param *ccb_p channel control block used to get the channel descriptor + * + * @return + * - pointer on the new Buffer Descriptor + * - NULL if allocation failed + * + */ +bufferDescriptor *iapi_AllocBD(channelControlBlock * ccb_p) +{ + bufferDescriptor *ptrBD = NULL; + + if (ccb_p->channelDescriptor->bufferDescNumber != 0) { +#ifdef CONFIG_SDMA_IRAM + channelDescriptor *cd_p = ccb_p->channelDescriptor; + if (cd_p->channelNumber >= MXC_DMA_CHANNEL_IRAM) { + ptrBD = (bufferDescriptor *) + MALLOC(ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_IRAM); + } else +#endif /*CONFIG_SDMA_IRAM */ + { + ptrBD = (bufferDescriptor *) + MALLOC(ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_ERAM); + } + } + if (ptrBD != NULL) { + ptrBD->mode.command = 0; + ptrBD->mode.status = 0; + ptrBD->mode.count = 0; + ptrBD->bufferAddr = NULL; + } + + return ptrBD; +} + +/* ***************************************************************************/ +/**Allocate one channel context data structure. + * + * @param **ctxd_p pointer to context data to be allocated + * @param channel channel number of context data structure + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + */ +int iapi_AllocContext(contextData **ctxd_p, unsigned char channel) +{ + contextData *ctxData; + int result = IAPI_SUCCESS; + + if (*ctxd_p != NULL) { + result = + IAPI_ERR_CC_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | + channel; + iapi_errno = result; + return -result; + } + + ctxData = (contextData *) MALLOC(sizeof(contextData), SDMA_ERAM); + + if (ctxData != NULL) { + *ctxd_p = ctxData; + return IAPI_SUCCESS; + + } else { + *ctxd_p = NULL; + result = + IAPI_ERR_CC_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Allocates channel description and fill in with default values. + * + * <b>Algorithm:</b>\n + * - Check channel properties. + * - Then modifies the properties of the channel description with default + * + * @param **cd_p pointer to channel descriptor to be allocated + * @param channel channel number of channel descriptor + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + * + */ +int iapi_AllocChannelDesc(channelDescriptor **cd_p, unsigned char channel) +{ +#ifdef MCU + volatile unsigned long *chPriorities = &SDMA_CHNPRI_0; +#endif /* MCU */ + channelDescriptor *tmpCDptr; + int result = IAPI_SUCCESS; + + if (*cd_p != NULL) { + result = + IAPI_ERR_CD_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | + channel; + iapi_errno = result; + return -result; + } + + tmpCDptr = + (channelDescriptor *) MALLOC(sizeof(channelDescriptor), SDMA_ERAM); + + if (tmpCDptr != NULL) { + iapi_memcpy(tmpCDptr, &iapi_ChannelDefaults, + sizeof(channelDescriptor)); + tmpCDptr->channelNumber = channel; +#ifdef MCU + if (chPriorities[channel] != 0) { + tmpCDptr->priority = chPriorities[channel]; + } else { + chPriorities[channel] = tmpCDptr->priority; + } +#endif + *cd_p = tmpCDptr; + return IAPI_SUCCESS; + } else { + *cd_p = NULL; + result = + IAPI_ERR_CD_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Changes channel description information after performing sanity checks. + * + * <b>Algorithm:</b>\n + * - Check channel properties. + * - Then modifies the properties of the channel description. + * + * @param *cd_p channel descriptor of the channel to change + * @param whatToChange control code indicating the desired change + * @param newval new value + * + * @return + * - IAPI_SUCCESS + * - IAPI_FAILURE if change failed + * + */ +int +iapi_ChangeChannelDesc(channelDescriptor *cd_p, unsigned char whatToChange, + unsigned long newval) +{ + bufferDescriptor *tmpBDptr; + unsigned char index = 0; + int result = IAPI_SUCCESS; + + /* verify parameter validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* verify channel descriptor initialization */ + if (cd_p->ccb_ptr == NULL) { + result = IAPI_ERR_CCB_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* verify channel is not in use */ + tmpBDptr = + (bufferDescriptor *) iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (index = cd_p->bufferDescNumber; index > 0; index--) { + if (tmpBDptr->mode.status & BD_DONE) { + result = IAPI_ERR_CH_IN_USE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + tmpBDptr++; + } + + /* Select the change accorded to the selector given in parameter */ + switch (whatToChange) { + + /* + * Channel Number + */ + case IAPI_CHANNELNUMBER: + /* Channel number can not be changed (description remains attached) */ + result = IAPI_ERR_CD_CHANGE_CH_NUMBER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + + /* + * Buffer Descriptor Number + */ + case IAPI_BUFFERDESCNUMBER: + if (newval < MAX_BD_NUM) { + if (newval != cd_p->bufferDescNumber) { + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL) { + tmpBDptr = (bufferDescriptor *) + iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + for (index = 0; + index < cd_p->bufferDescNumber; + index++) { + if (tmpBDptr->bufferAddr != + NULL) { + if (cd_p->trust == + FALSE) { + FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr)); + } + } + tmpBDptr++; + } + FREE((bufferDescriptor *) + iapi_Phys2Virt((cd_p-> + ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferDescNumber = (unsigned char)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS != + iapi_InitializeMemory(cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Buffer size + */ + case IAPI_BUFFERSIZE: + if (newval < MAX_BD_SIZE) { + if (newval != cd_p->bufferSize) { + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL) { + tmpBDptr = (bufferDescriptor *) + iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + for (index = 0; + index < cd_p->bufferDescNumber; + index++) { + if (cd_p->trust == FALSE) { + FREE(iapi_Phys2Virt + (tmpBDptr->bufferAddr)); + } + tmpBDptr++; + } + FREE((bufferDescriptor *) + iapi_Phys2Virt((cd_p-> + ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferSize = (unsigned short)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS != + iapi_InitializeMemory(cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Blocking / non blocking feature + */ + case IAPI_BLOCKING: + if (newval < MAX_BLOCKING) { + cd_p->blocking = newval; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Synchronization method + */ + case IAPI_CALLBACKSYNCH: + if (newval < MAX_SYNCH) { + cd_p->callbackSynch = newval; + iapi_ChangeCallbackISR(cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Ownership of the channel + */ + case IAPI_OWNERSHIP: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_OWNERSHIP) { + cd_p->ownership = newval; + iapi_ChannelConfig(cd_p->channelNumber, + (newval >> CH_OWNSHP_OFFSET_EVT) & 1, + (newval >> CH_OWNSHP_OFFSET_MCU) & 1, + (newval >> CH_OWNSHP_OFFSET_DSP) & + 1); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + +#endif /* MCU */ + + /* + * Priority + */ + case IAPI_PRIORITY: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ + +#ifdef MCU + if (newval < MAX_CH_PRIORITY) { + volatile unsigned long *ChannelPriorities = + &SDMA_CHNPRI_0; + ChannelPriorities[cd_p->channelNumber] = newval; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + /* + * "Trust" property + */ + case IAPI_TRUST: + if (newval < MAX_TRUST) { + if (cd_p->trust != newval) { + cd_p->trust = newval; + if (newval == FALSE) { + if (IAPI_SUCCESS != + iapi_InitializeMemory + (cd_p->ccb_ptr)) { + result = + IAPI_ERR_BD_ALLOCATION | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + } + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Callback function pointer + */ + case IAPI_CALLBACKISR_PTR: + if ((void *)newval != NULL) { + { + union { + void *voidstar; + void (*funcptr) (channelDescriptor * + cd_p, void *arg); + } value; + value.voidstar = (void *)newval; + cd_p->callbackISR_ptr = value.funcptr; + } + iapi_ChangeCallbackISR(cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Channel Control Block pointer + */ + case IAPI_CCB_PTR: + cd_p->ccb_ptr = (channelControlBlock *) newval; + cd_p->ccb_ptr->channelDescriptor = cd_p; + break; + + /* + * WRAP/UNWRAP + */ + case IAPI_BDWRAP: + /* point to first BD */ + tmpBDptr = + (bufferDescriptor *) iapi_Phys2Virt(cd_p-> + ccb_ptr->baseBDptr); + /* to point to last BD */ + tmpBDptr += cd_p->bufferDescNumber - 1; + if (newval == TRUE) { + /* wrap last BD */ + tmpBDptr->mode.status |= BD_WRAP; + break; + } else if (newval == FALSE) { + /* unwrap last BD */ + tmpBDptr->mode.status &= ~BD_WRAP; + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Watermark level + */ + case IAPI_WML: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_WML) { + if (cd_p->watermarkLevel != newval) { + cd_p->watermarkLevel = newval; + } + break; + } else { + result = + IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + /* + * Detect errors + */ + default: + result = IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**Initialize a table of function pointers that contain the interrupt Service + * Routine callback pointers for the SDMA channels with a default value + * + * <b>Algorithm:</b>\n + * - Loop on each element of the global IAPI variable callbackIsrTable + * + * @param *func_p default callback functon for all SDMA channels + * + * @return none + */ +void +iapi_InitializeCallbackISR(void (*func_p) (channelDescriptor *cd_p, void *arg)) +{ + unsigned long chCnt; + + for (chCnt = 0; chCnt < CH_NUM; chCnt++) { + callbackIsrTable[chCnt] = func_p; + } +} + +/* ***************************************************************************/ +/**For the specified channel control block, attach the array of buffer + * descriptors, the channel description structure and initialize channel's + * status using information in the channel descriptor. + * + * @param *ccb_p pointer to channel control block + * + * @return none + * + */ +int iapi_InitializeMemory(channelControlBlock *ccb_p) +{ + bufferDescriptor *bd_p; + unsigned char index; + int result = IAPI_SUCCESS; + + /* Attach the array of Buffer descriptors */ + bd_p = iapi_AllocBD(ccb_p); + if (bd_p != NULL) { + ccb_p->baseBDptr = (bufferDescriptor *) iapi_Virt2Phys(bd_p); + ccb_p->currentBDptr = ccb_p->baseBDptr; + for (index = 0; + index < ccb_p->channelDescriptor->bufferDescNumber - 1; + index++) { + if (ccb_p->channelDescriptor->trust == TRUE) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, + BD_CONT | BD_EXTD, + ccb_p->channelDescriptor->bufferSize, + NULL, NULL); + } else { + if (ccb_p->channelDescriptor->bufferSize != 0) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, BD_CONT | BD_EXTD, ccb_p->channelDescriptor->bufferSize, MALLOC(ccb_p->channelDescriptor->bufferSize, SDMA_ERAM), NULL); + } + } + bd_p++; + } + + if (ccb_p->channelDescriptor->trust == TRUE) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor-> + dataSize, + BD_EXTD | BD_WRAP | BD_INTR, + ccb_p-> + channelDescriptor->bufferSize, + NULL, NULL); + } else { + if (ccb_p->channelDescriptor->bufferSize != 0) { + iapi_SetBufferDescriptor(bd_p, + (unsigned char) + ccb_p->channelDescriptor->dataSize, + BD_EXTD | BD_WRAP | + BD_INTR, + ccb_p->channelDescriptor->bufferSize, + MALLOC + (ccb_p->channelDescriptor->bufferSize, + SDMA_ERAM), NULL); + } + } + } else { + result = IAPI_ERR_BD_ALLOCATION; + return -result; + } + return result; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c new file mode 100644 index 000000000000..8e7a614fd76a --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddleMcu.c + * + * $Id iapiMiddleMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API specific to MCU. + * + * + * + * + * $Log iapiMiddleMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include <string.h> + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + +/*extern void * __HEAP_START; +extern void * __HEAP_END; +*/ + +/* **************************************************************************** + * Function Section + *****************************************************************************/ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c new file mode 100644 index 000000000000..c188d36eda00 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiOS.c + * + * $Id iapiOS.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the OS level functions of the I.API - are OS dependant and must + * be provided by the user of I.API. + * + * + * / + * + * $Log iapiOS.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ +#ifdef CONFIG_SDMA_IRAM +void *(*iapi_iram_Malloc) (size_t size); +#endif /*CONFIG_SDMA_IRAM */ + +void *(*iapi_Malloc) (size_t size); +void (*iapi_Free) (void *ptr); + +void *(*iapi_Virt2Phys) (void *ptr); +void *(*iapi_Phys2Virt) (void *ptr); + +void (*iapi_WakeUp) (int); +void (*iapi_GotoSleep) (int); +void (*iapi_InitSleep) (int); + +void *(*iapi_memcpy) (void *dest, const void *src, size_t count); +void *(*iapi_memset) (void *dest, int c, size_t count); + +void (*iapi_EnableInterrupts) (void); +void (*iapi_DisableInterrupts) (void); + +int (*iapi_GetChannel) (int); +int (*iapi_ReleaseChannel) (int); diff --git a/arch/arm/plat-mxc/sdma/sdma.c b/arch/arm/plat-mxc/sdma/sdma.c new file mode 100644 index 000000000000..7b3d7ae92eb8 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/sdma.c @@ -0,0 +1,1548 @@ +/* + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/sdma.c + * @brief This file contains functions for Smart DMA API + * + * SDMA (Smart DMA) is used for transferring data between MCU and peripherals + * + * @ingroup SDMA + */ + +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/semaphore.h> +#include <linux/spinlock.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/proc_fs.h> + +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <mach/dma.h> +#include <mach/hardware.h> + +#include "iapi.h" + +#define M3_BASE_ADDRESS CSD0_BASE_ADDR +#define CHAD(ch) sdma_data[0].cd->ccb_ptr[ch].channelDescriptor + +/*! + * SDMA status mutex + */ +static struct semaphore sdma_status_mutex; + +/*! + * SDMA channel sleep queues + */ +static wait_queue_head_t sdma_sleep_queue[MAX_DMA_CHANNELS]; + +/*! + * SDMA channel synchronization + */ +static struct semaphore sdma_synch_mutex[MAX_DMA_CHANNELS]; + +/*! + * SDMA buffers pool initialization function + */ +extern void init_sdma_pool(void); + +/*! + * Flags are save and restored during interrupt handler + */ +unsigned long flags; +struct clk *mxc_sdma_ahb_clk, *mxc_sdma_ipg_clk; +void __iomem *sdma_base; + +/*! + * Structure containing sdma channels information. + */ +typedef struct { + /*! Channel number */ + int channel; + /*! Channel usage name */ + int in_use; + /*! Name of device using the channel */ + char devicename[MAX_DEVNAME_LENGTH]; + /*! Transfer type. Needed for setting SDMA script */ + sdma_transferT transfer_type; + /*! Peripheral type. Needed for setting SDMA script */ + sdma_periphT peripheral_type; + /*! Watermark level of device's fifo */ + __u32 watermark_level; + /*! Peripheral event id */ + int event_id; + /*! Peripheral event id2 (for channels that use 2 events) */ + int event_id2; + /*! Running status (boolean) */ + int running; + /*! buffer descriptors number */ + int bd_number; + /*! callback function */ + dma_callback_t callback; + /*! callback argument */ + void *arg; + /*! SDMA data access word size */ + unsigned long word_size:8; + /*! channel descriptor pointer */ + channelDescriptor *cd; +} sdma_struct; + +/*! + * Used to save the status of channels. + */ +static sdma_struct sdma_data[MAX_DMA_CHANNELS]; + +/*! + * Stores the start address of the SDMA scripts + */ +static sdma_script_start_addrs sdma_script_addrs; + +extern void mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_add); + +/*! + * Init sleep mutex of the channel + * + * @param channel channel number + */ +static void sdma_init_sleep(int channel) +{ + init_waitqueue_head(&sdma_sleep_queue[channel]); +} + +/*! + * Puts channel to sleep + * + * @param channel channel number + */ +static void sdma_sleep_channel(int channel) +{ + while ((iapi_SDMAIntr & (1 << channel)) == 0) { + int timeout = 10; /* timeout 10ms */ + timeout = wait_event_interruptible_timeout( + sdma_sleep_queue[channel], + ((iapi_SDMAIntr & (1 << channel)) != + 0), timeout); + if (!timeout) + printk(KERN_WARNING "sdma channel timeout\n"); + } +} + +/*! + * Wake up channel from sleep + * + * @param channel channel number + */ +static void sdma_wakeup_channel(int channel) +{ + wake_up_interruptible(&sdma_sleep_queue[channel]); +} + +/*! + * Sdma interrupt handler routine. + * Calls channels callback function + * + * @param irq the interrupt number + * @param dev_id driver private data + * @return the function returns \b IRQ_RETVAL(1) - interrupt was handled + */ +static irqreturn_t sdma_int_handler(int irq, void *dev_id) +{ + IRQ_Handler(); + return IRQ_RETVAL(1); +} + +/*! + * I.API channel callback function + * + * @param cd channel descriptor structure + * @param channel_data SDMA struct of the current channel + */ +static void iapi_interrupt_callback(channelDescriptor *cd, + sdma_struct *channel_data) +{ + int channel; + dma_callback_t callback; + void *arg; + + channel = channel_data->channel; + + channel_data->running = 0; + + arg = channel_data->arg; + + if (arg == 0) { + arg = (void *)&channel; + } + + callback = channel_data->callback; + + if (callback != 0) { + callback(arg); + } +} + +/*! + * Returns pc of SDMA script according to peripheral and transfer type + * + * @param peripheral_type peripheral type + * @param transfer_type transfer type + * + * @return PC of SDMA script +*/ +static unsigned short sdma_get_pc(sdma_periphT peripheral_type, + sdma_transferT transfer_type) +{ + int res = 0; + + if (peripheral_type == MEMORY) { + switch (transfer_type) { + case emi_2_int: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + case emi_2_emi: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + case int_2_emi: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == DSP) { + switch (transfer_type) { + case emi_2_dsp: + res = sdma_script_addrs.mxc_sdma_ap_2_bp_addr; + break; + case dsp_2_emi: + res = sdma_script_addrs.mxc_sdma_bp_2_ap_addr; + break; + case dsp_2_emi_loop: + res = + sdma_script_addrs. + mxc_sdma_loopback_on_dsp_side_addr; + break; + case emi_2_dsp_loop: + res = + sdma_script_addrs.mxc_sdma_mcu_interrupt_only_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == FIRI) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_firi_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_firi_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_firi_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_firi_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == UART) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_uart_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_uart_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_app_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == UART_SP) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_uartsh_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_uartsh_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == ATA) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_ata_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ata_addr; + break; + default: + res = -EINVAL; + } +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + } else if (peripheral_type == CSPI || peripheral_type == EXT || + (peripheral_type == SSI && + !(cpu_is_mx51() || cpu_is_mx53()))) { +#else + } else if (peripheral_type == CSPI || peripheral_type == EXT || + peripheral_type == SSI) { +#endif + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_app_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_app_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_app_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; + break; + default: + res = -EINVAL; + } +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + } else if (peripheral_type == MMC || peripheral_type == SDHC || + peripheral_type == CSPI_SP || peripheral_type == ESAI || + peripheral_type == MSHC_SP || + (peripheral_type == SSI_SP && + !(cpu_is_mx51() || cpu_is_mx53()))) { +#else + } else if (peripheral_type == SSI_SP || peripheral_type == MMC || + peripheral_type == SDHC || peripheral_type == CSPI_SP || + peripheral_type == ESAI || peripheral_type == MSHC_SP) { +#endif + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_shp_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == ASRC) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; + break; + case per_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_per_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == MSHC) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_mshc_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_mshc_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == CCM) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_dptc_dvfs_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == FIFO_MEMORY) { + res = sdma_script_addrs.mxc_sdma_ap_2_ap_fixed_addr; + } else if (peripheral_type == SPDIF) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_spdif_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_spdif_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == IPU_MEMORY) { + if (transfer_type == emi_2_per) { + res = sdma_script_addrs.mxc_sdma_ext_mem_2_ipu_addr; + } else { + res = -EINVAL; + } +#ifdef CONFIG_MXC_SSI_DUAL_FIFO + } else if (peripheral_type == SSI) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_ssiapp_2_mcu_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_ssiapp_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ssiapp_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ssiapp_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == SSI_SP) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_ssish_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ssish_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_ssish_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ssish_addr; + break; + default: + res = -EINVAL; + } +#endif + } + + if (res < 0) { + printk(KERN_ERR "SDMA script not found\n"); + } + + return res; + +} + +static inline int sdma_asrc_set_info(dma_channel_params *p, + script_data *pcontext, int eflags) +{ + dma_channel_ext_params *ep = (dma_channel_ext_params *) p; + unsigned int wml, tmp, wml1, wml2; + struct dma_channel_asrc_info *info = &(ep->info.asrc); + wml = 0; + if (p->transfer_type == per_2_per) { + if (!p->ext) + return wml; + wml1 = p->watermark_level; + wml2 = ep->watermark_level2; + if (info->channs) { + wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << + SDMA_ASRC_INFO_N_OFF; + if (ep->p2p_dir) + wml2 *= info->channs & SDMA_ASRC_INFO_N_MASK; + else + wml1 *= info->channs & SDMA_ASRC_INFO_N_MASK; + } + if (info->channs & 1) { + if (ep->p2p_dir) + wml |= SDMA_ASRC_P2P_INFO_PS; + else + wml |= SDMA_ASRC_P2P_INFO_PA; + } + if (wml1 > wml2) { + tmp = wml2 & SDMA_ASRC_P2P_INFO_LWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; + tmp = wml1 & SDMA_ASRC_P2P_INFO_HWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; + if (eflags & (1 << 31)) + wml |= SDMA_ASRC_P2P_INFO_LWE; + if (eflags & (1 << 30)) + wml |= SDMA_ASRC_P2P_INFO_HWE; + } else { + tmp = wml1 & SDMA_ASRC_P2P_INFO_LWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; + tmp = wml2 & SDMA_ASRC_P2P_INFO_HWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; + wml |= eflags >> 2; + tmp = pcontext->event_mask2; + pcontext->event_mask2 = pcontext->event_mask1; + pcontext->event_mask1 = tmp; + } + } else { + if (p->ext && info->channs) { + wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << + SDMA_ASRC_INFO_N_OFF; + tmp = (info->channs * p->watermark_level) & + SDMA_ASRC_INFO_WML_MASK; + wml |= tmp << SDMA_ASRC_INFO_WML_OFF; + } else { + tmp = (p->watermark_level & SDMA_ASRC_INFO_WML_MASK); + wml |= tmp << SDMA_ASRC_INFO_WML_OFF; + } + + if (p->transfer_type == per_2_emi) + wml |= SDMA_ASRC_INFO_TXFR_DIR; + + if (p->ext && (info->channs & 1)) { + if (p->transfer_type == per_2_emi) + wml |= SDMA_ASRC_INFO_PS; + else + wml |= SDMA_ASRC_INFO_PA; + } + wml |= eflags; + } + return wml; +} + +/*! + * Downloads channel context according to channel parameters + * + * @param channel channel number + * @param p channel parameters + */ +static int sdma_load_context(int channel, dma_channel_params *p) +{ + script_data context; + int res; + int event1_greater_than_32; + int event2_greater_than_32; + dma_channel_ext_params *ep = (dma_channel_ext_params *) p; + + res = 0; + + memset(&context, 0, sizeof(script_data)); + context.load_address = sdma_get_pc(p->peripheral_type, + p->transfer_type); + + if (context.load_address > 0) { + if ((p->peripheral_type != MEMORY) + && (p->peripheral_type != DSP)) { + /* Handle multiple event channels differently */ + if (p->event_id2) { + if (p->event_id2 < 32) { + context.event_mask2 = + 0x1 << p->event_id2; + event2_greater_than_32 = 0; + } else { + context.event_mask2 = + 0x1 << (p->event_id2 - 32); + event2_greater_than_32 = 1 << 31; + } + if (p->event_id < 32) { + context.event_mask1 = + 0x1 << p->event_id; + event1_greater_than_32 = 0; + } else { + context.event_mask1 = + 0x1 << (p->event_id - 32); + event1_greater_than_32 = 1 << 30; + } + } else { + event1_greater_than_32 = 0; + event2_greater_than_32 = 0; + if (p->event_id < 32) { + context.event_mask1 = + 0x1 << p->event_id; + context.event_mask2 = 0; + } else { + context.event_mask1 = 0; + context.event_mask2 = + 0x1 << (p->event_id - 32); + } + } + + if (p->ext) + context.wml = ep->info_bits; + /* Watermark Level */ + context.wml |= event2_greater_than_32 | + event1_greater_than_32 | p->watermark_level; + + /* Address */ + context.shp_addr = (unsigned long)(p->per_address); + if (p->ext) + context.per_addr = ep->per_address2; + iapi_IoCtl(sdma_data[channel].cd, + IAPI_CHANGE_PERIPHADDR, p->per_address); + } else { + BUG(); /* Need a real address, not the beginning of RAM + context.wml = M3_BASE_ADDRESS; */ + } + + sdma_data[channel].transfer_type = p->transfer_type; + sdma_data[channel].peripheral_type = p->peripheral_type; + sdma_data[channel].watermark_level = p->watermark_level; + iapi_AssignScript(sdma_data[channel].cd, &context); + } else { + res = context.load_address; + } + + return res; +} + +/*! + * Setup channel according to parameters. Must be called once after mxc_request_dma() + * + * @param channel channel number + * @param p channel parameters pointer + * @return 0 on success, error code on fail + */ +int mxc_dma_setup_channel(int channel, dma_channel_params *p) +{ + int err = 0; + int i; + + mxc_dma_stop(channel); + + for (i = 0; i < sdma_data[channel].bd_number; i++) { + iapi_IoCtl(sdma_data[channel].cd, + (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, (unsigned long)0); + } + + sdma_data[channel].bd_number = (p->bd_number <= 0) ? 1 : p->bd_number; + + sdma_data[channel].word_size = p->word_size; + + sdma_data[channel].event_id = p->event_id; + sdma_data[channel].event_id2 = p->event_id2; + + sdma_data[channel].callback = p->callback; + + sdma_data[channel].arg = p->arg; + + err = iapi_IoCtl(sdma_data[channel].cd, + IAPI_CHANGE_BDNUM, sdma_data[channel].bd_number); + + if (err < 0) { + printk(KERN_ERR "Failed allocating buffer \ +descriptors (0x%x)\n", err); + err = -ENOMEM; + goto setup_channel_fail; + } + + if (channel != 0) { + switch (p->transfer_type) { + case dsp_2_per: + break; + case emi_2_per: + case int_2_per: + case per_2_int: + case per_2_emi: + case per_2_per: + /* + * Peripheral <------> Memory + * evtOvr = 0 dspOvr = 1 + */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + if (p->event_id) { + err = iapi_SetChannelEventMapping(p->event_id, + 0x1 << + channel); + } + if (!err && p->event_id2) { + err = iapi_SetChannelEventMapping(p->event_id2, + 0x1 << + channel); + } + break; + case emi_2_dsp: + case int_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + /* + * DSP <-----------> Memory + * evtOvr = 1 dspOvr = 0 + */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + case emi_2_dsp_loop: + case dsp_2_emi_loop: + /* evtOvr = 1 dspOvr = 1 */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + break; + case per_2_dsp: + /* evtOvr = 0 dspOvr = 0 */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + err = iapi_SetChannelEventMapping(p->event_id, + 0x1 << channel); + break; + default: + break; + printk(KERN_ERR "Wrong SDMA transfer type\n"); + err = -EINVAL; + } + if (err == 0) { + err = sdma_load_context(channel, p); + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, + MXC_SDMA_DEFAULT_PRIORITY); + } + } + setup_channel_fail: + return err; +} + +/*! + * Setup the channel priority. This can be used to change the default priority + * for the channel. + * + * @param channel channel number + * @param priority priority to be set for the channel + * + * @return 0 on success, error code on failure + */ +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority) +{ + if (priority < MXC_SDMA_MIN_PRIORITY + || priority > MXC_SDMA_MAX_PRIORITY) { + return -EINVAL; + } + return iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, + priority); +} + +/*! + * Allocates dma channel. + * If channel's value is 0, then the function allocates a free channel + * dynamically and sets its value to channel. + * Else allocates requested channel if it is free. + * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned. + * + * @param channel pointer to channel number + * @param devicename device name + * @return 0 on success, error code on fail + */ +int mxc_request_dma(int *channel, const char *devicename) +{ + int i, res; + + res = 0; + + down(&sdma_status_mutex); + + /* Dynamic allocation */ + if (*channel == 0) { + for (i = MAX_DMA_CHANNELS - 1; i > 0; i--) { +#ifdef CONFIG_SDMA_IRAM + /*TODO:It will be removed after DPTC used UDMA interface */ + if (i >= MXC_DMA_CHANNEL_IRAM) + continue; +#endif /*CONFIG_SDMA_IRAM */ + if (!sdma_data[i].in_use) { + *channel = i; + break; + } + } + } + + if (*channel > 0 && *channel < MAX_DMA_CHANNELS && + sdma_data[*channel].in_use == 0) { + res = iapi_Open(sdma_data[0].cd, *channel); + + if (res < 0) { + printk(KERN_ERR "Failed iapi_Open channel %d, 0x%x\n", + *channel, res); + } else { + sdma_data[*channel].in_use = 1; + strcpy(sdma_data[*channel].devicename, devicename); + sdma_data[*channel].cd = CHAD(*channel); + + iapi_IoCtl(sdma_data[*channel].cd, IAPI_CHANGE_SYNCH, + CALLBACK_ISR); + iapi_IoCtl(sdma_data[*channel].cd, + IAPI_CHANGE_CALLBACKFUNC, + (unsigned long)iapi_interrupt_callback); + iapi_IoCtl(sdma_data[*channel].cd, + IAPI_CHANGE_USER_ARG, + (unsigned long)&(sdma_data[*channel])); + } + } else { + res = -EBUSY; + } + + up(&sdma_status_mutex); + + return res; +} + +/*! + * Configures request parameters. Can be called multiple times after + * mxc_request_dma() and mxc_dma_setup_channel(). + * + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to set + * @return 0 on success, error code on fail + */ +int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index) +{ + unsigned char param; + + if (!sdma_data[channel].in_use) { + return -EINVAL; + } + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_TRANSFER_CD, sdma_data[channel].word_size); + + param = BD_DONE | BD_INTR | BD_EXTD; + + if (sdma_data[channel].bd_number > 1 && p->bd_cont == 1) { + param |= BD_CONT; + } + + if (bd_index == sdma_data[channel].bd_number - 1) { + param |= BD_WRAP; + } + + switch (sdma_data[channel].transfer_type) { + case emi_2_per: + case dsp_2_per: + case int_2_per: + case emi_2_dsp: + case int_2_dsp: + case emi_2_dsp_loop: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->sourceAddr); + break; + case per_2_int: + case per_2_emi: + case per_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + case dsp_2_emi_loop: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->destAddr); + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->sourceAddr); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_EXTDBUFFERADDR, + (unsigned long)p->destAddr); + break; + default: + break; + } + + /* Change the endianness for DSP to MCU Data transfers */ + if (sdma_data[channel].transfer_type == dsp_2_emi || + sdma_data[channel].transfer_type == emi_2_dsp) { + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_SET_ENDIANNESS, + SET_BIT_ALL); + } + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_COUNT, p->count); + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param); + + return 0; +} + +/*! + * Configures the BD_INTR bit on a buffer descriptor parameters. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * @param bd_intr flag to set or clear the BD_INTR bit + * @return 0 on success, error code on fail + */ +void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr) +{ + unsigned long param; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); + + if (bd_intr) { + param |= BD_INTR; + } else { + param &= ~BD_INTR; + } + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param); + +} + +/*! + * Gets the BD_INTR bit on a buffer descriptor. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * + * @return returns the BD_INTR bit status + */ +int mxc_dma_get_bd_intr(int channel, int bd_index) +{ + unsigned long bd_status = 0; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); + + return bd_status & BD_INTR; +} + +/*! + * Stop the current transfer + * + * @param channel channel number + * @param buffer_number number of buffers (beginning with 0), + * whose done bits should be reset to 0 + */ +int mxc_dma_reset(int channel, int buffer_number) +{ + unsigned char param = 0; + int i = 0; + + if (!sdma_data[channel].in_use) { + return -EINVAL; + } + + /* clear the BD_DONE bits for all the necessary buffers */ + for (i = 0; i < buffer_number; i++) { + + iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); + + /* clear the BD_DONE bit of the buffer */ + param = param & (~BD_DONE); + + iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, param); + } + + return 0; +} + +/*! + * Returns request parameters. + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to get + * @return 0 on success, error code on fail + */ +int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index) +{ + int err = 0; + unsigned long bd_status; + unsigned long bd_count; + __u8 *sourceAddr; + __u8 *destAddr; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_COUNT, (unsigned long)&bd_count); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_BUFFERADDR, (unsigned long)&sourceAddr); + + switch (sdma_data[channel].transfer_type) { + case emi_2_per: + case dsp_2_per: + case int_2_per: + case emi_2_dsp: + case int_2_dsp: + case emi_2_dsp_loop: + p->sourceAddr = sourceAddr; + break; + case per_2_int: + case per_2_emi: + case per_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + case dsp_2_emi_loop: + p->destAddr = sourceAddr; + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + p->sourceAddr = sourceAddr; + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_EXTDBUFFERADDR, + (unsigned long)&destAddr); + p->destAddr = destAddr; + break; + default: + break; + } + + p->count = bd_count; + p->bd_done = bd_status & BD_DONE; + p->bd_cont = bd_status & BD_CONT; + p->bd_error = bd_status & BD_RROR; + + return err; +} + +/*! + * This function is used by MXC IPC's write_ex2. It passes the pointer to the + * data control structure to iapi_write_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr) +{ + return iapi_Write_ipcv2(sdma_data[channel].cd, ctrl_ptr); +} + +/*! + * This function is used by MXC IPC's read_ex2. It passes the pointer to the + * data control structure to iapi_read_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr) +{ + return iapi_Read_ipcv2(sdma_data[channel].cd, ctrl_ptr); +} + +/*! + * Starts dma channel. + * + * @param channel channel number + */ +int mxc_dma_start(int channel) +{ + if (sdma_data[channel].running == 0) { + sdma_data[channel].running = 1; + iapi_StartChannel(channel); + } + + return 0; +} + +/*! + * Stops dma channel. + * + * @param channel channel number + */ +int mxc_dma_stop(int channel) +{ + iapi_StopChannel(channel); + sdma_data[channel].running = 0; + + return 0; +} + +/*! + * Frees dma channel. + * + * @param channel channel number + */ +void mxc_free_dma(int channel) +{ + int i; + + mxc_dma_stop(channel); + + if (sdma_data[channel].event_id != 0) { + iapi_SetChannelEventMapping(sdma_data[channel].event_id, 0x0); + } + if (sdma_data[channel].event_id2 != 0) { + iapi_SetChannelEventMapping(sdma_data[channel].event_id2, 0x0); + } + + sdma_data[channel].event_id = 0; + + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, 0x0); + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + + for (i = 0; i < sdma_data[channel].bd_number; i++) { + iapi_IoCtl(sdma_data[channel].cd, + (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, (unsigned long)0); + } + + iapi_Close(sdma_data[channel].cd); + + strcpy(sdma_data[channel].devicename, "not used"); + + sdma_data[channel].in_use = 0; +} + +/*! + * Initializes channel's priorities + * + */ +static void __init init_priorities(void) +{ + iapi_IoCtl(sdma_data[0].cd, IAPI_CHANGE_PRIORITY, 0x7); +} + +/*! + * Initializes events table + */ +static void __init init_event_table(void) +{ + int channel; + + for (channel = 0; channel < MAX_DMA_CHANNELS; channel++) { + iapi_SetChannelEventMapping(channel, 0); + } +} + +/*! + * Sets callback function. Used with standard dma api + * for supporting interrupts + * + * @param channel channel number + * @param callback callback function pointer + * @param arg argument for callback function + */ +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg) +{ + sdma_data[channel].callback = callback; + sdma_data[channel].arg = arg; +} + +/*! + * Synchronization function used by I.API + * + * @param channel channel number + */ +static int getChannel(int channel) +{ + if (irqs_disabled() || in_atomic()) { + if (down_trylock(&sdma_synch_mutex[channel])) { + return -EBUSY; + } + } else { + if (down_interruptible(&sdma_synch_mutex[channel])) { + return -EBUSY; + } + } + + return 0; +} + +/*! + * Synchronization function used by I.API + * + * @param channel channel number + */ +static int releaseChannel(int channel) +{ + up(&sdma_synch_mutex[channel]); + return 0; +} + +/*! + * Unmask interrupt function. Used by I.API + * + */ +static void unmask_sdma_interrupt(void) +{ + /* Commented out tp take care of the PREEMPT_RT option + * local_irq_restore(flags); + */ +} + +/*! + * Mask interrupt function. Used by I.API + * + */ +static void mask_sdma_interrupt(void) +{ + /* Commented to take of the PREEMPT_RT option + * local_irq_save(flags); + */ +} + +/*! + * Initializes I.API + */ +static void __init init_iapi_struct(void) +{ + channelDescriptor *cd; + + printk(KERN_INFO "Using SDMA I.API\n"); + + iapi_Malloc = &sdma_malloc; +#ifdef CONFIG_SDMA_IRAM + iapi_iram_Malloc = &sdma_iram_malloc; +#endif /*CONFIG_SDMA_IRAM */ + + iapi_Free = &sdma_free; + iapi_Virt2Phys = (void *(*)(void *))&sdma_virt_to_phys; + iapi_Phys2Virt = (void *(*)(void *))&sdma_phys_to_virt; + iapi_memset = &memset; + iapi_memcpy = &memcpy; + + iapi_GotoSleep = &sdma_sleep_channel; + iapi_WakeUp = &sdma_wakeup_channel; + iapi_InitSleep = &sdma_init_sleep; + iapi_ReleaseChannel = &releaseChannel; + iapi_GetChannel = &getChannel; + + iapi_EnableInterrupts = &unmask_sdma_interrupt; + iapi_DisableInterrupts = &mask_sdma_interrupt; + + cd = kmalloc(sizeof(channelDescriptor), GFP_KERNEL); + + memset(cd, 0, sizeof(channelDescriptor)); + + sdma_data[0].cd = cd; +} + +/*! + * Initializes channel synchronization mutexes + */ +static void __init init_mutexes(void) +{ + int i; + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + init_MUTEX(&sdma_synch_mutex[i]); + } + + init_MUTEX(&sdma_status_mutex); +} + +/*! + * Channels status read proc file system function + * + * @param buf pointer to the buffer the data shuld be written to. + * @param start pointer to the pointer where the new data is + * written to. + * procedure should update the start pointer to point to + * where in the buffer the data was written. + * @param offset offset from start of the file + * @param count number of bytes to read. + * @param eof pointer to eof flag. sould be set to 1 when + * reaching eof. + * @param data driver specific data pointer. + * + * @return number byte read from the log buffer. + */ +static int proc_read_channels(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + char *log; + char *log_ptr; + char tmp[48]; + int i; + + log = kmalloc(4096, GFP_KERNEL); + memset(log, 0, 4096); + log_ptr = log; + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + if (sdma_data[i].in_use == 0) { + continue; + } + + memset(tmp, 0, 48); + sprintf(tmp, "Channel %d: %s\n", i, sdma_data[i].devicename); + + strcpy(log_ptr, tmp); + log_ptr += strlen(tmp); + } + + if (offset > strlen(log)) { + *eof = 1; + count = 0; + } else { + if (offset + count > strlen(log)) { + count = strlen(log) - offset; + *eof = 1; + } else { + *eof = 0; + } + + memcpy(buf, log, count); + *start = buf; + kfree(log); + } + + return count; +} + +/*! + * SDMA proc file system read function + */ +static int __init init_proc_fs(void) +{ + struct proc_dir_entry *sdma_proc_dir; + int res; + + res = 0; + + sdma_proc_dir = proc_mkdir("sdma", NULL); + create_proc_read_entry("channels", 0, sdma_proc_dir, + proc_read_channels, NULL); + + if (res < 0) { + printk(KERN_WARNING "Failed create SDMA proc entry\n"); + } + + return res; +} + +/*! + * Initializes SDMA private data + */ +static void __init init_sdma_data(void) +{ + int i; + + memset(sdma_data, 0, sizeof(sdma_struct) * MAX_DMA_CHANNELS); + sdma_data[0].in_use = 1; + strcpy(sdma_data[0].devicename, "MCU"); + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + sdma_data[i].channel = i; + } +} + +#if defined(CONFIG_MXC_SUPER_GEM) +/*! + * Initialize the Super GEM SDMA channel + * + * @return returns -1 on error, 0 on success. + */ +static int __init init_super_gem(void) +{ + channelDescriptor *cd; + script_data context; + int res = 0; + + res = iapi_Open(sdma_data[0].cd, MXC_DMA_CHANNEL_GEM); + if (res < 0) { + return -1; + } + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 1; + cd = CHAD(MXC_DMA_CHANNEL_GEM); + memset(&context, 0, sizeof(script_data)); + context.load_address = sdma_script_addrs.mxc_sdma_utra_addr; + context.wml = M3_BASE_ADDRESS; + res = iapi_AssignScript(cd, &context); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + res = + iapi_IoCtl(cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + /* Set EP=1, which is required to start SuperGem script the first time */ + /* This can be done only on the AP side */ + SDMA_H_EVTPEND |= 1 << MXC_DMA_CHANNEL_GEM; + + res = + iapi_SetChannelEventMapping(DMA_REQ_GEM, 1 << MXC_DMA_CHANNEL_GEM); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + + return 0; +} +#endif + +int sdma_probe(struct platform_device *pdev) +{ + int res = 0; + int irq; + struct resource *rsrc; + configs_data confreg_data; + + /* Initialize to the default values */ + confreg_data = iapi_ConfigDefaults; + + confreg_data.dspdma = 0; + /* Set ACR bit */ + mxc_sdma_ahb_clk = clk_get(&pdev->dev, "sdma_ahb_clk"); + mxc_sdma_ipg_clk = clk_get(&pdev->dev, "sdma_ipg_clk"); + clk_enable(mxc_sdma_ahb_clk); + clk_enable(mxc_sdma_ipg_clk); + if (clk_get_rate(mxc_sdma_ahb_clk) / clk_get_rate(mxc_sdma_ipg_clk) < 2) { + printk(KERN_INFO "Setting SDMA ACR\n"); + confreg_data.acr = 1; + } + + init_sdma_data(); + + init_sdma_pool(); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + res = -ENODEV; + goto sdma_init_fail; + } + res = request_irq(irq, sdma_int_handler, 0, dev_name(&pdev->dev), 0); + + if (res < 0) { + goto sdma_init_fail; + } + + rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (rsrc < 0) { + res = -ENODEV; + goto sdma_init_fail; + } + sdma_base = ioremap(rsrc->start, SZ_4K); + if (sdma_base == NULL) + goto sdma_init_fail; + + init_mutexes(); + + init_iapi_struct(); + + mxc_sdma_get_script_info(&sdma_script_addrs); + + res = iapi_Init(sdma_data[0].cd, &confreg_data, + sdma_script_addrs.mxc_sdma_start_addr, + sdma_script_addrs.mxc_sdma_ram_code_size * 2, + sdma_script_addrs.mxc_sdma_ram_code_start_addr); + + if (res < 0) { + free_irq(irq, 0); + goto sdma_init_fail; + } + + init_priorities(); + + init_event_table(); + + init_proc_fs(); + + printk(KERN_INFO "MXC DMA API initialized\n"); + + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + return res; + + sdma_init_fail: + printk(KERN_ERR "Error 0x%x in sdma_init\n", res); + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + return res; +} + +static struct platform_driver sdma_driver = { + .driver = { + .name = "mxc_sdma", + }, + .probe = sdma_probe, +}; + +/*! + * Initializes dma + */ +int __init sdma_init(void) +{ + return platform_driver_register(&sdma_driver); +} +arch_initcall(sdma_init); + +EXPORT_SYMBOL(mxc_request_dma); +EXPORT_SYMBOL(mxc_free_dma); +EXPORT_SYMBOL(mxc_dma_setup_channel); +EXPORT_SYMBOL(mxc_dma_set_channel_priority); +EXPORT_SYMBOL(mxc_dma_set_config); +EXPORT_SYMBOL(mxc_dma_get_config); +EXPORT_SYMBOL(mxc_dma_set_bd_intr); +EXPORT_SYMBOL(mxc_dma_get_bd_intr); +EXPORT_SYMBOL(mxc_dma_reset); +EXPORT_SYMBOL(mxc_sdma_write_ipcv2); +EXPORT_SYMBOL(mxc_sdma_read_ipcv2); +EXPORT_SYMBOL(mxc_dma_start); +EXPORT_SYMBOL(mxc_dma_stop); +EXPORT_SYMBOL(sdma_malloc); +EXPORT_SYMBOL(sdma_free); +EXPORT_SYMBOL(mxc_dma_set_callback); +EXPORT_SYMBOL(sdma_virt_to_phys); +EXPORT_SYMBOL(sdma_phys_to_virt); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/sdma/sdma_malloc.c b/arch/arm/plat-mxc/sdma/sdma_malloc.c new file mode 100644 index 000000000000..a9f86b327a98 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/sdma_malloc.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/sdma_malloc.c + * @brief This file contains functions for SDMA non-cacheable buffers allocation + * + * SDMA (Smart DMA) is used for transferring data between MCU and peripherals + * + * @ingroup SDMA + */ + +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/genalloc.h> +#include <linux/iram_alloc.h> +#include <asm/dma.h> +#include <mach/hardware.h> + + +#define DEBUG 0 + +#if DEBUG +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef CONFIG_SDMA_IRAM +#define IRAM_SDMA_SIZE SZ_4K +#endif + +/*! + * Defines SDMA non-cacheable buffers pool + */ +static struct dma_pool *pool; +static struct gen_pool *sdma_iram_pool; + +/*! + * SDMA memory conversion hashing structure + */ +typedef struct { + struct list_head node; + /*! Virtual address */ + void *virt; + /*! Physical address */ + unsigned long phys; + int size; + bool in_iram; +} virt_phys_struct; + +static struct list_head alloc_list; + +/*! + * Defines the size of each buffer in SDMA pool. + * The size must be at least 512 bytes, because + * sdma channel control blocks array size is 512 bytes + */ +#define SDMA_POOL_SIZE 1024 + +#ifdef CONFIG_SDMA_IRAM +static unsigned long iram_paddr; +static void *iram_vaddr; +#define iram_phys_to_virt(p) (iram_vaddr + ((p) - iram_paddr)) +#define iram_virt_to_phys(v) (iram_paddr + ((v) - iram_vaddr)) +#endif + +/*! + * Virtual to physical address conversion functio + * + * @param buf pointer to virtual address + * + * @return physical address + */ +unsigned long sdma_virt_to_phys(void *buf) +{ + u32 offset = (u32) buf & (~PAGE_MASK); + virt_phys_struct *p; + + DPRINTK("searching for vaddr 0x%p\n", buf); + + list_for_each_entry(p, &alloc_list, node) { + if (((u32)p->virt & PAGE_MASK) == ((u32) buf & PAGE_MASK)) { + return (p->phys & PAGE_MASK) | offset; + } + } + + if (virt_addr_valid(buf)) { + return virt_to_phys(buf); + } + + printk(KERN_WARNING + "SDMA malloc: could not translate virt address 0x%p\n", buf); + return 0; +} + +/*! + * Physical to virtual address conversion functio + * + * @param buf pointer to physical address + * + * @return virtual address + */ +void *sdma_phys_to_virt(unsigned long buf) +{ + u32 offset = buf & (~PAGE_MASK); + virt_phys_struct *p; + + DPRINTK("searching for paddr 0x%p\n", buf); + + list_for_each_entry(p, &alloc_list, node) { + if ((p->phys & PAGE_MASK) == (buf & PAGE_MASK)) { + return (void *)(((u32)p->virt & PAGE_MASK) | offset); + } + } + + printk(KERN_WARNING + "SDMA malloc: could not translate phys address 0x%lx\n", buf); + return 0; +} + +/*! + * Allocates uncacheable buffer + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_malloc(size_t size) +{ + void *buf; + dma_addr_t dma_addr; + virt_phys_struct *p; + + if (size > SDMA_POOL_SIZE) { + printk(KERN_WARNING + "size in sdma_malloc is more than %d bytes\n", + SDMA_POOL_SIZE); + return 0; + } + + buf = dma_pool_alloc(pool, GFP_KERNEL, &dma_addr); + if (buf == 0) + return 0; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + p->virt = buf; + p->phys = dma_addr; + list_add_tail(&p->node, &alloc_list); + + DPRINTK("allocated vaddr 0x%p\n", buf); + return buf; +} + +/*! + * Frees uncacheable buffer + * + * @param buf buffer pointer for deletion + */ +void sdma_free(void *buf) +{ + virt_phys_struct *p; + + list_for_each_entry(p, &alloc_list, node) { + if (p->virt == buf) { + if (p->in_iram) + gen_pool_free(sdma_iram_pool, p->phys, p->size); + else + dma_pool_free(pool, p->virt, p->phys); + list_del(&p->node); + kfree(p); + return; + } + } +} + +#ifdef CONFIG_SDMA_IRAM +/*! + * Allocates uncacheable buffer from IRAM + */ +void *sdma_iram_malloc(size_t size) +{ + virt_phys_struct *p = kzalloc(sizeof(*p), GFP_KERNEL); + unsigned long buf; + + buf = gen_pool_alloc(sdma_iram_pool, size); + if (!buf) { + kfree(p); + return NULL; + } + + p->virt = iram_vaddr + (buf - iram_paddr); + p->phys = buf; + p->size = size; + p->in_iram = true; + list_add_tail(&p->node, &alloc_list); + return p->virt; +} +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * SDMA buffers pool initialization function + */ +void __init init_sdma_pool(void) +{ + pool = dma_pool_create("SDMA", NULL, SDMA_POOL_SIZE, 0, 0); + +#ifdef CONFIG_SDMA_IRAM + iram_vaddr = iram_alloc(SZ_4K, &iram_paddr); + sdma_iram_pool = gen_pool_create(6, -1); + gen_pool_add(sdma_iram_pool, iram_paddr, SZ_4K, -1); +#endif + + INIT_LIST_HEAD(&alloc_list); +} + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); |