aboutsummaryrefslogtreecommitdiff
path: root/recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c')
-rw-r--r--recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c2159
1 files changed, 2159 insertions, 0 deletions
diff --git a/recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c b/recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c
new file mode 100644
index 0000000..9ef1cb0
--- /dev/null
+++ b/recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c
@@ -0,0 +1,2159 @@
+/*
+ * Copyright (C) 2017 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include "fft_driver.h"
+
+/* globals */
+static struct semaphore g_dev_probe_sem;
+static int g_platform_probe_flag;
+
+/* structures */
+struct fft_samples_struct {
+ short i;
+ short r;
+};
+
+struct raw_samples_struct {
+ long r;
+ long i;
+};
+
+/* fft_dev structure and storage allocation */
+struct fft_dev {
+ struct semaphore sem;
+ uint32_t phys_fft_st_adapter;
+ uint32_t size_fft_st_adapter;
+ void *ioremap_fft_st_adapter;
+ uint32_t phys_fft_data_ram;
+ uint32_t size_fft_data_ram;
+ void *ioremap_fft_data_ram;
+ uint32_t phys_sgdma_from_fft_descriptor;
+ uint32_t size_sgdma_from_fft_descriptor;
+ void *ioremap_sgdma_from_fft_descriptor;
+ uint32_t phys_sgdma_from_fft_csr;
+ uint32_t size_sgdma_from_fft_csr;
+ void *ioremap_sgdma_from_fft_csr;
+ uint32_t phys_sgdma_to_fft_descriptor;
+ uint32_t size_sgdma_to_fft_descriptor;
+ void *ioremap_sgdma_to_fft_descriptor;
+ uint32_t phys_sgdma_to_fft_csr;
+ uint32_t size_sgdma_to_fft_csr;
+ void *ioremap_sgdma_to_fft_csr;
+ uint32_t phys_sgdma_from_ram_descriptor;
+ uint32_t size_sgdma_from_ram_descriptor;
+ void *ioremap_sgdma_from_ram_descriptor;
+ uint32_t phys_sgdma_from_ram_csr;
+ uint32_t size_sgdma_from_ram_csr;
+ void *ioremap_sgdma_from_ram_csr;
+ int fft_open_for_read;
+ int fft_open_for_write;
+ int fft256_open_for_read;
+ int fft256_open_for_write;
+ int fftdma_open_for_read;
+ int fftdma_open_for_write;
+ int fft256dma_open_for_read;
+ int fft256dma_open_for_write;
+ int fft256stream_open_for_read;
+ int fft256stream_open_for_write;
+ int raw256stream_open_for_read;
+ int raw256stream_open_for_write;
+ uint32_t fft256_buffer_read_index;
+ uint32_t fft256_buffer_write_index;
+ uint32_t fft256_buffer_inflight_count;
+ void *dma_buffer;
+ dma_addr_t dma_handle;
+};
+
+static struct fft_dev the_fft_dev = {
+ /*
+ .sem = initialize this at runtime before it is needed
+ */
+};
+
+/* misc device - raw256stream_dev */
+static ssize_t raw256stream_dev_write(struct file *fp,
+ const char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ if (count > (64 * 1024)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* move the input data from the user buffer into the fft data buffer */
+ if (copy_from_user
+ (dev->ioremap_fft_data_ram + DMA_DATA_OFFSET, user_buffer, count)) {
+ up(&dev->sem);
+ pr_info("raw256stream_dev_write copy_from_user exit\n");
+ return -EFAULT;
+ }
+
+ up(&dev->sem);
+ return count;
+}
+
+static ssize_t raw256stream_dev_read(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ uint32_t dma_status;
+ uint32_t dma_desc_fill_level;
+ int this_count = 256;
+ int write_block_count = 0;
+ int read_block_count = 0;
+ int read_count = 0;
+ int next_fft256_buffer_offset;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* validate count request */
+ if (count & ((this_count * 8) - 1)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ if (count > 0)
+ read_block_count = count / (this_count * 8);
+ else
+ read_block_count = 0;
+
+ write_block_count = read_block_count;
+
+ while ((write_block_count > 0) || (read_block_count > 0)) {
+ while (write_block_count > 0) {
+ if (dev->fft256_buffer_inflight_count >= 32)
+ break;
+
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_write_index * this_count * 8;
+
+ /* start the read from RAM DMA */
+ iowrite32(DMA_RAM_DATA_ADDR,
+ dev->ioremap_sgdma_from_ram_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(dev->dma_handle + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_from_ram_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 8,
+ dev->ioremap_sgdma_from_ram_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_FROM_FFT_MASK,
+ dev->ioremap_sgdma_from_ram_descriptor +
+ DESC_CONTROL_REG);
+
+ /* maintain counters and pointers */
+ write_block_count--;
+ dev->fft256_buffer_inflight_count++;
+ dev->fft256_buffer_write_index++;
+ if (dev->fft256_buffer_write_index >= 32)
+ dev->fft256_buffer_write_index = 0;
+ }
+
+ while (read_block_count > 0) {
+ if (dev->fft256_buffer_inflight_count == 0)
+ break;
+
+ if (dev->fft256_buffer_inflight_count >= 2) {
+ /* wait for at least two descriptors to be used
+ */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->
+ ioremap_sgdma_from_ram_csr
+ +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level >
+ (dev->fft256_buffer_inflight_count -
+ 2));
+ } else {
+ /* wait for all descriptors to be used */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->
+ ioremap_sgdma_from_ram_csr
+ +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level > 0);
+
+ /* wait for read from FFT DMA to complete */
+ do {
+ dma_status =
+ ioread32(dev->
+ ioremap_sgdma_from_ram_csr
+ + CSR_STATUS_REG);
+ } while ((dma_status &
+ CSR_BUSY_MASK) != 0);
+ }
+
+ /* move the results buffer into the user buffer */
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_read_index * this_count * 8;
+ if (copy_to_user
+ (user_buffer,
+ dev->dma_buffer + next_fft256_buffer_offset,
+ this_count * 8)) {
+ up(&dev->sem);
+ pr_info
+ ("raw256stream_dev_read copy_to_user exit\n");
+ return -EFAULT;
+ }
+
+ /* maintain counters and pointers */
+ user_buffer += this_count * 8;
+ read_count += this_count * 8;
+ read_block_count--;
+ dev->fft256_buffer_inflight_count--;
+ dev->fft256_buffer_read_index++;
+ if (dev->fft256_buffer_read_index >= 32)
+ dev->fft256_buffer_read_index = 0;
+ }
+ }
+
+ up(&dev->sem);
+ return read_count;
+}
+
+static int raw256stream_dev_open(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = &the_fft_dev;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = -EBUSY;
+ if ((dev->fft256stream_open_for_read != 0) ||
+ (dev->fft256stream_open_for_write != 0) ||
+ (dev->fft_open_for_read != 0) ||
+ (dev->fft_open_for_write != 0) ||
+ (dev->fftdma_open_for_read != 0) ||
+ (dev->fftdma_open_for_write != 0) ||
+ (dev->fft256_open_for_read != 0) ||
+ (dev->fft256_open_for_write != 0))
+ goto do_exit;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ if (dev->raw256stream_open_for_read != 0)
+ goto do_exit;
+ dev->raw256stream_open_for_read = 1;
+ break;
+ case (O_WRONLY):
+ if (dev->raw256stream_open_for_write != 0)
+ goto do_exit;
+ dev->raw256stream_open_for_write = 1;
+ break;
+ case (O_RDWR):
+ if (dev->raw256stream_open_for_read != 0)
+ goto do_exit;
+ if (dev->raw256stream_open_for_write != 0)
+ goto do_exit;
+ dev->raw256stream_open_for_read = 1;
+ dev->raw256stream_open_for_write = 1;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+ ret_val = 0;
+ fp->private_data = dev;
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static int raw256stream_dev_release(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = fp->private_data;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = 0;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ dev->raw256stream_open_for_read = 0;
+ break;
+ case (O_WRONLY):
+ dev->raw256stream_open_for_write = 0;
+ break;
+ case (O_RDWR):
+ dev->raw256stream_open_for_read = 0;
+ dev->raw256stream_open_for_write = 0;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static const struct file_operations raw256stream_dev_fops = {
+ .owner = THIS_MODULE,
+ .open = raw256stream_dev_open,
+ .release = raw256stream_dev_release,
+ .read = raw256stream_dev_read,
+ .write = raw256stream_dev_write,
+};
+
+static struct miscdevice raw256stream_dev_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "raw256stream",
+ .fops = &raw256stream_dev_fops,
+};
+
+/* misc device - fft256stream_dev */
+static ssize_t fft256stream_dev_write(struct file *fp,
+ const char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ if (count > (64 * 1024)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* move the input data from the user buffer into the fft data buffer */
+ if (copy_from_user
+ (dev->ioremap_fft_data_ram + DMA_DATA_OFFSET, user_buffer, count)) {
+ up(&dev->sem);
+ pr_info("fft256stream_dev_write copy_from_user exit\n");
+ return -EFAULT;
+ }
+
+ up(&dev->sem);
+ return count;
+}
+
+static ssize_t fft256stream_dev_read(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ uint32_t dma_status;
+ uint32_t dma_desc_fill_level;
+ int this_count = 256;
+ int write_block_count = 0;
+ int read_block_count = 0;
+ int read_count = 0;
+ int next_fft256_buffer_offset;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* validate count request */
+ if (count & ((this_count * 8) - 1)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ if (count > 0)
+ read_block_count = count / (this_count * 8);
+ else
+ read_block_count = 0;
+
+ write_block_count = read_block_count;
+
+ /* set the FFT length */
+ iowrite32(this_count, dev->ioremap_fft_st_adapter);
+
+ while ((write_block_count > 0) || (read_block_count > 0)) {
+ while (write_block_count > 0) {
+ if (dev->fft256_buffer_inflight_count >= 32)
+ break;
+
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_write_index * this_count * 8;
+
+ /* start the read from FFT DMA */
+ iowrite32(0x0,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(dev->dma_handle + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 8,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_FROM_FFT_MASK,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_CONTROL_REG);
+
+ /* start the write to FFT DMA */
+ iowrite32(DMA_RAM_DATA_ADDR,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(0x0,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 4,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_TO_FFT_MASK,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_CONTROL_REG);
+
+ /* maintain counters and pointers */
+ write_block_count--;
+ dev->fft256_buffer_inflight_count++;
+ dev->fft256_buffer_write_index++;
+ if (dev->fft256_buffer_write_index >= 32)
+ dev->fft256_buffer_write_index = 0;
+ }
+
+ while (read_block_count > 0) {
+ if (dev->fft256_buffer_inflight_count == 0)
+ break;
+
+ if (dev->fft256_buffer_inflight_count >= 2) {
+ /* wait for at least two descriptors to be used
+ */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->
+ ioremap_sgdma_from_fft_csr
+ +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level >
+ (dev->fft256_buffer_inflight_count -
+ 2));
+ } else {
+ /* wait for all descriptors to be used */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->
+ ioremap_sgdma_from_fft_csr
+ +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level > 0);
+
+ /* wait for read from FFT DMA to complete */
+ do {
+ dma_status =
+ ioread32(dev->
+ ioremap_sgdma_from_fft_csr
+ + CSR_STATUS_REG);
+ } while ((dma_status &
+ CSR_BUSY_MASK) != 0);
+ }
+
+ /* move the results buffer into the user buffer */
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_read_index * this_count * 8;
+ if (copy_to_user
+ (user_buffer,
+ dev->dma_buffer + next_fft256_buffer_offset,
+ this_count * 8)) {
+ up(&dev->sem);
+ pr_info
+ ("fft256stream_dev_read copy_to_user exit\n");
+ return -EFAULT;
+ }
+
+ /* maintain counters and pointers */
+ user_buffer += this_count * 8;
+ read_count += this_count * 8;
+ read_block_count--;
+ dev->fft256_buffer_inflight_count--;
+ dev->fft256_buffer_read_index++;
+ if (dev->fft256_buffer_read_index >= 32)
+ dev->fft256_buffer_read_index = 0;
+ }
+ }
+
+ up(&dev->sem);
+ return read_count;
+}
+
+static int fft256stream_dev_open(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = &the_fft_dev;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = -EBUSY;
+ if ((dev->raw256stream_open_for_read != 0) ||
+ (dev->raw256stream_open_for_write != 0) ||
+ (dev->fft_open_for_read != 0) ||
+ (dev->fft_open_for_write != 0) ||
+ (dev->fftdma_open_for_read != 0) ||
+ (dev->fftdma_open_for_write != 0) ||
+ (dev->fft256_open_for_read != 0) ||
+ (dev->fft256_open_for_write != 0))
+ goto do_exit;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ if (dev->fft256stream_open_for_read != 0)
+ goto do_exit;
+ dev->fft256stream_open_for_read = 1;
+ break;
+ case (O_WRONLY):
+ if (dev->fft256stream_open_for_write != 0)
+ goto do_exit;
+ dev->fft256stream_open_for_write = 1;
+ break;
+ case (O_RDWR):
+ if (dev->fft256stream_open_for_read != 0)
+ goto do_exit;
+ if (dev->fft256stream_open_for_write != 0)
+ goto do_exit;
+ dev->fft256stream_open_for_read = 1;
+ dev->fft256stream_open_for_write = 1;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+ ret_val = 0;
+ fp->private_data = dev;
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static int fft256stream_dev_release(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = fp->private_data;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = 0;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ dev->fft256stream_open_for_read = 0;
+ break;
+ case (O_WRONLY):
+ dev->fft256stream_open_for_write = 0;
+ break;
+ case (O_RDWR):
+ dev->fft256stream_open_for_read = 0;
+ dev->fft256stream_open_for_write = 0;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static const struct file_operations fft256stream_dev_fops = {
+ .owner = THIS_MODULE,
+ .open = fft256stream_dev_open,
+ .release = fft256stream_dev_release,
+ .read = fft256stream_dev_read,
+ .write = fft256stream_dev_write,
+};
+
+static struct miscdevice fft256stream_dev_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "fft256stream",
+ .fops = &fft256stream_dev_fops,
+};
+
+/* misc device - fft256dma_dev */
+static ssize_t fft256dma_dev_write(struct file *fp,
+ const char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ int this_count = 256;
+ int write_count = 0;
+ int next_fft256_buffer_offset;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* validate count request */
+ if (count & ((this_count * 4) - 1)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* set the FFT length */
+ iowrite32(this_count, dev->ioremap_fft_st_adapter);
+
+ while (count > 0) {
+ if (dev->fft256_buffer_inflight_count >= 32)
+ break;
+
+ /* move the input data from the user buffer into the fft data
+ buffer */
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_write_index * this_count * 8;
+ if (copy_from_user
+ (dev->dma_buffer + next_fft256_buffer_offset, user_buffer,
+ this_count * 4)) {
+ up(&dev->sem);
+ pr_info("fft256dma_dev_write copy_from_user exit\n");
+ return -EFAULT;
+ }
+
+ /* start the read from FFT DMA */
+ iowrite32(0x0,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(dev->dma_handle + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 8,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_FROM_FFT_MASK,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_CONTROL_REG);
+
+ /* start the write to FFT DMA */
+ iowrite32(dev->dma_handle + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(0x0,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 4,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_TO_FFT_MASK,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_CONTROL_REG);
+
+ /* maintain counters and pointers */
+ user_buffer += this_count * 4;
+ write_count += this_count * 4;
+ count -= this_count * 4;
+ dev->fft256_buffer_inflight_count++;
+ dev->fft256_buffer_write_index++;
+ if (dev->fft256_buffer_write_index >= 32)
+ dev->fft256_buffer_write_index = 0;
+ }
+
+ up(&dev->sem);
+ return write_count;
+}
+
+static ssize_t fft256dma_dev_read(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ uint32_t dma_status;
+ uint32_t dma_desc_fill_level;
+ int this_count = 256;
+ int read_count = 0;
+ int next_fft256_buffer_offset;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* validate count request */
+ if (count & ((this_count * 8) - 1)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ while (count > 0) {
+ if (dev->fft256_buffer_inflight_count == 0)
+ break;
+
+ if (dev->fft256_buffer_inflight_count >= 2) {
+ /* wait for at least two descriptors to be used */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->ioremap_sgdma_from_fft_csr +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level >
+ (dev->fft256_buffer_inflight_count - 2));
+ } else {
+ /* wait for all descriptors to be used */
+ do {
+ dma_desc_fill_level =
+ ioread32(dev->ioremap_sgdma_from_fft_csr +
+ CSR_DESCRIPTOR_FILL_LEVEL_REG);
+ dma_desc_fill_level &=
+ CSR_WRITE_FILL_LEVEL_MASK;
+ dma_desc_fill_level >>=
+ CSR_WRITE_FILL_LEVEL_OFFSET;
+ } while (dma_desc_fill_level > 0);
+
+ /* wait for read from FFT DMA to complete */
+ do {
+ dma_status =
+ ioread32(dev->ioremap_sgdma_from_fft_csr +
+ CSR_STATUS_REG);
+ } while ((dma_status & CSR_BUSY_MASK) !=
+ 0);
+ }
+
+ /* move the results buffer into the user buffer */
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_read_index * this_count * 8;
+ if (copy_to_user
+ (user_buffer, dev->dma_buffer + next_fft256_buffer_offset,
+ this_count * 8)) {
+ up(&dev->sem);
+ pr_info("fft256dma_dev_read copy_to_user exit\n");
+ return -EFAULT;
+ }
+
+ /* maintain counters and pointers */
+ user_buffer += this_count * 8;
+ read_count += this_count * 8;
+ count -= this_count * 8;
+ dev->fft256_buffer_inflight_count--;
+ dev->fft256_buffer_read_index++;
+ if (dev->fft256_buffer_read_index >= 32)
+ dev->fft256_buffer_read_index = 0;
+ }
+
+ up(&dev->sem);
+ return read_count;
+}
+
+static int fft256dma_dev_open(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = &the_fft_dev;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = -EBUSY;
+ if ((dev->raw256stream_open_for_read != 0) ||
+ (dev->raw256stream_open_for_write != 0) ||
+ (dev->fft256stream_open_for_read != 0) ||
+ (dev->fft256stream_open_for_write != 0) ||
+ (dev->fft_open_for_read != 0) ||
+ (dev->fft_open_for_write != 0) ||
+ (dev->fftdma_open_for_read != 0) ||
+ (dev->fftdma_open_for_write != 0) ||
+ (dev->fft256_open_for_read != 0) ||
+ (dev->fft256_open_for_write != 0))
+ goto do_exit;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ if (dev->fft256dma_open_for_read != 0)
+ goto do_exit;
+ dev->fft256dma_open_for_read = 1;
+ break;
+ case (O_WRONLY):
+ if (dev->fft256dma_open_for_write != 0)
+ goto do_exit;
+ dev->fft256dma_open_for_write = 1;
+ break;
+ case (O_RDWR):
+ if (dev->fft256dma_open_for_read != 0)
+ goto do_exit;
+ if (dev->fft256dma_open_for_write != 0)
+ goto do_exit;
+ dev->fft256dma_open_for_read = 1;
+ dev->fft256dma_open_for_write = 1;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+ ret_val = 0;
+ fp->private_data = dev;
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static int fft256dma_dev_release(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = fp->private_data;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = 0;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ dev->fft256dma_open_for_read = 0;
+ break;
+ case (O_WRONLY):
+ dev->fft256dma_open_for_write = 0;
+ break;
+ case (O_RDWR):
+ dev->fft256dma_open_for_read = 0;
+ dev->fft256dma_open_for_write = 0;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static const struct file_operations fft256dma_dev_fops = {
+ .owner = THIS_MODULE,
+ .open = fft256dma_dev_open,
+ .release = fft256dma_dev_release,
+ .read = fft256dma_dev_read,
+ .write = fft256dma_dev_write,
+};
+
+static struct miscdevice fft256dma_dev_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "fft256dma",
+ .fops = &fft256dma_dev_fops,
+};
+
+/* misc device - fftdma_dev */
+static ssize_t fftdma_dev_write(struct file *fp,
+ const char __user *user_buffer, size_t count,
+ loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ uint32_t dma_status;
+ int this_count = 0;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ switch (count) {
+ case (32 * 4):
+ this_count = 32;
+ break;
+ case (64 * 4):
+ this_count = 64;
+ break;
+ case (128 * 4):
+ this_count = 128;
+ break;
+ case (256 * 4):
+ this_count = 256;
+ break;
+ case (512 * 4):
+ this_count = 512;
+ break;
+ case (1024 * 4):
+ this_count = 1024;
+ break;
+ case (2048 * 4):
+ this_count = 2048;
+ break;
+ case (4096 * 4):
+ this_count = 4096;
+ break;
+ default:
+ this_count = 0;
+ break;
+ }
+
+ if (this_count == 0) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* move the input data from the user buffer into the dma buffer */
+ if (copy_from_user
+ (dev->dma_buffer + DMA_DATA_OFFSET, user_buffer, this_count * 4)) {
+ up(&dev->sem);
+ pr_info("fftdma_dev_write copy_from_user exit\n");
+ return -EFAULT;
+ }
+
+ /* set the FFT length */
+ iowrite32(this_count, dev->ioremap_fft_st_adapter);
+
+ /* start the read from FFT DMA */
+ iowrite32(0x0,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(dev->dma_handle + DMA_ACP_OFFSET + DMA_RESULT_OFFSET,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 8,
+ dev->ioremap_sgdma_from_fft_descriptor + DESC_LENGTH_REG);
+ iowrite32(START_DMA_FROM_FFT_MASK,
+ dev->ioremap_sgdma_from_fft_descriptor + DESC_CONTROL_REG);
+
+ /* start the write to FFT DMA */
+ iowrite32(dev->dma_handle + DMA_ACP_OFFSET + DMA_DATA_OFFSET,
+ dev->ioremap_sgdma_to_fft_descriptor + DESC_READ_ADDRESS_REG);
+ iowrite32(0x0,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 4,
+ dev->ioremap_sgdma_to_fft_descriptor + DESC_LENGTH_REG);
+ iowrite32(START_DMA_TO_FFT_MASK,
+ dev->ioremap_sgdma_to_fft_descriptor + DESC_CONTROL_REG);
+
+ /* wait for read from FFT DMA to complete */
+ do {
+ dma_status =
+ ioread32(dev->ioremap_sgdma_from_fft_csr + CSR_STATUS_REG);
+ } while ((dma_status & CSR_BUSY_MASK) != 0);
+
+ up(&dev->sem);
+ return count;
+}
+
+static ssize_t fftdma_dev_read(struct file *fp, char __user *user_buffer,
+ size_t count, loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ int this_count = 0;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ switch (count) {
+ case (32 * 8):
+ this_count = 32;
+ break;
+ case (64 * 8):
+ this_count = 64;
+ break;
+ case (128 * 8):
+ this_count = 128;
+ break;
+ case (256 * 8):
+ this_count = 256;
+ break;
+ case (512 * 8):
+ this_count = 512;
+ break;
+ case (1024 * 8):
+ this_count = 1024;
+ break;
+ case (2048 * 8):
+ this_count = 2048;
+ break;
+ case (4096 * 8):
+ this_count = 4096;
+ break;
+ default:
+ this_count = 0;
+ break;
+ }
+
+ if (this_count == 0) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* move the results buffer into the user buffer */
+ if (copy_to_user
+ (user_buffer, dev->dma_buffer + DMA_RESULT_OFFSET,
+ this_count * 8)) {
+ up(&dev->sem);
+ pr_info("fftdma_dev_read copy_to_user exit\n");
+ return -EFAULT;
+ }
+
+ up(&dev->sem);
+ return count;
+}
+
+static int fftdma_dev_open(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = &the_fft_dev;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = -EBUSY;
+ if ((dev->raw256stream_open_for_read != 0) ||
+ (dev->raw256stream_open_for_write != 0) ||
+ (dev->fft256stream_open_for_read != 0) ||
+ (dev->fft256stream_open_for_write != 0) ||
+ (dev->fft256_open_for_read != 0) ||
+ (dev->fft256_open_for_write != 0) ||
+ (dev->fft_open_for_read != 0) ||
+ (dev->fft_open_for_write != 0) ||
+ (dev->fft256dma_open_for_read != 0) ||
+ (dev->fft256dma_open_for_write != 0))
+ goto do_exit;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ if (dev->fftdma_open_for_read != 0)
+ goto do_exit;
+ dev->fftdma_open_for_read = 1;
+ break;
+ case (O_WRONLY):
+ if (dev->fftdma_open_for_write != 0)
+ goto do_exit;
+ dev->fftdma_open_for_write = 1;
+ break;
+ case (O_RDWR):
+ if (dev->fftdma_open_for_read != 0)
+ goto do_exit;
+ if (dev->fftdma_open_for_write != 0)
+ goto do_exit;
+ dev->fftdma_open_for_read = 1;
+ dev->fftdma_open_for_write = 1;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+ ret_val = 0;
+ fp->private_data = dev;
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static int fftdma_dev_release(struct inode *ip, struct file *fp)
+{
+ struct fft_dev *dev = fp->private_data;
+ int ret_val;
+ uint32_t access_mode;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ ret_val = 0;
+
+ access_mode = fp->f_flags & O_ACCMODE;
+ switch (access_mode) {
+ case (O_RDONLY):
+ dev->fftdma_open_for_read = 0;
+ break;
+ case (O_WRONLY):
+ dev->fftdma_open_for_write = 0;
+ break;
+ case (O_RDWR):
+ dev->fftdma_open_for_read = 0;
+ dev->fftdma_open_for_write = 0;
+ break;
+ default:
+ ret_val = -EINVAL;
+ goto do_exit;
+ }
+
+do_exit:
+ up(&dev->sem);
+ return ret_val;
+}
+
+static const struct file_operations fftdma_dev_fops = {
+ .owner = THIS_MODULE,
+ .open = fftdma_dev_open,
+ .release = fftdma_dev_release,
+ .read = fftdma_dev_read,
+ .write = fftdma_dev_write,
+};
+
+static struct miscdevice fftdma_dev_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "fftdma",
+ .fops = &fftdma_dev_fops,
+};
+
+/* misc device - fft256_dev */
+static ssize_t fft256_dev_write(struct file *fp,
+ const char __user *user_buffer, size_t count,
+ loff_t *offset)
+{
+ struct fft_dev *dev = fp->private_data;
+ int this_count = 256;
+ int write_count = 0;
+ int next_fft256_buffer_offset;
+
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* validate count request */
+ if (count & ((this_count * 4) - 1)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+
+ /* set the FFT length */
+ iowrite32(this_count, dev->ioremap_fft_st_adapter);
+
+ while (count > 0) {
+ if (dev->fft256_buffer_inflight_count >= 32)
+ break;
+
+ /* move the input data from the user buffer into the fft data
+ buffer */
+ next_fft256_buffer_offset =
+ dev->fft256_buffer_write_index * this_count * 8;
+ if (copy_from_user
+ (dev->ioremap_fft_data_ram + next_fft256_buffer_offset,
+ user_buffer, this_count * 4)) {
+ up(&dev->sem);
+ pr_info("fft256_dev_write copy_from_user exit\n");
+ return -EFAULT;
+ }
+
+ /* start the read from FFT DMA */
+ iowrite32(0x0,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(DMA_RAM_DATA_ADDR + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 8,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_FROM_FFT_MASK,
+ dev->ioremap_sgdma_from_fft_descriptor +
+ DESC_CONTROL_REG);
+
+ /* start the write to FFT DMA */
+ iowrite32(DMA_RAM_DATA_ADDR + next_fft256_buffer_offset,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_READ_ADDRESS_REG);
+ iowrite32(0x0,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_WRITE_ADDRESS_REG);
+ iowrite32(this_count * 4,
+ dev->ioremap_sgdma_to_fft_descriptor +
+ DESC_LENGTH_REG);
+ iowrite32(START_DMA_TO_FFT_MASK,
+ dev->ioremap_sgdma_to_fft_descriptor +
+