aboutsummaryrefslogtreecommitdiff
path: root/recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c
diff options
context:
space:
mode:
authorWestergreen, Dalon <dalon.westergreen@intel.com>2017-03-29 15:41:36 -0700
committerWestergreen, Dalon <dalon.westergreen@intel.com>2017-03-30 16:35:30 -0700
commit9a293641b9abf9e4fca34f46a2de781f50847da9 (patch)
tree743a6aaa5f9834987a2e69881ced6eaf9efb3592 /recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c
parent8abd3fefd939f796ae49191d6f5af641f2d624d0 (diff)
downloadmeta-de10-nano-9a293641b9abf9e4fca34f46a2de781f50847da9.tar.xz
Initial commit of de10-nano recipes
Please note that this is purely for development. Only superficial efforts have been made to resolve security concerns, and it should be noted that the board ships with an EMPTY ROOT PASSWORD and support for root login via ssh. This allows passwordless access to the board via ssh. recipes-bsp/u-boot: Contains the uboot 2017.03rc2 recipe and patches to support the de10-nano board recipes-connectivity/avahi: bbappend to remove unwanted packages recipes-connectivity/bluez: bbappend to add --compat to the bluetooth service to support legacy SDP APIs recipes-connectivity/openssh: bbappend to add a custom sshd_config recipes-core/base-files: bbappend to customize fstab and inputrc recipes-core/imagemagick: bbappend to change build configuration for the de10-nano board recipes-core/packagegroups: bbappend to remove an unwanted package recipes-core/webkit: bbappend to remove support for opengl recipes-demo: Various demo applications recipes-devtools: MRAA and UPM recipes recipes-images/angstrom/de10-nano-image.bb: DE10-Nano image definition recipes-kernel/de10-nano-linux-firmware: FPGA related firmware required for fpga configuration and devicetree overlay support recipes-kernel/linux: bbappend to customize configuration of linux kernel as well as patch in the de10-nano devicetree recipes-misc: various initialization and systemd scripts recipes-qt/qt5: bbappend to modify qt build options recipes-support/neon: bbappend to remove unwanted package recipes-support/upower: bbappend to remove unwanted package recipes-webserver: webserver configuration and webcontent for board hostedweb portal recipes-xfce/thunar-volman: bbappend to remove unwanted package recipes-xfce/xfce-pointers: add configuration so that xfce does not use the adxl input as a mouse recipes-xfce/xfce4-settings: bbappend to remove unwanted package Signed-off-by: Westergreen, Dalon <dalon.westergreen@intel.com>
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;
+}