diff options
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.c | 2159 |
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 + + |