From 9a293641b9abf9e4fca34f46a2de781f50847da9 Mon Sep 17 00:00:00 2001 From: "Westergreen, Dalon" Date: Wed, 29 Mar 2017 15:41:36 -0700 Subject: 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 --- .../de10-nano-fftdriver-mod/files/fft_driver.c | 2159 ++++++++++++++++++++ 1 file changed, 2159 insertions(+) create mode 100644 recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c (limited to 'recipes-demo/de10-nano-fftdriver-mod/files/fft_driver.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + + 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 fft256_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->ioremap_fft_data_ram + next_fft256_buffer_offset, + this_count * 8)) { + up(&dev->sem); + pr_info("fft256_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 fft256_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->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->fft256_open_for_read != 0) + goto do_exit; + dev->fft256_open_for_read = 1; + break; + case (O_WRONLY): + if (dev->fft256_open_for_write != 0) + goto do_exit; + dev->fft256_open_for_write = 1; + break; + case (O_RDWR): + if (dev->fft256_open_for_read != 0) + goto do_exit; + if (dev->fft256_open_for_write != 0) + goto do_exit; + dev->fft256_open_for_read = 1; + dev->fft256_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 fft256_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->fft256_open_for_read = 0; + break; + case (O_WRONLY): + dev->fft256_open_for_write = 0; + break; + case (O_RDWR): + dev->fft256_open_for_read = 0; + dev->fft256_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 fft256_dev_fops = { + .owner = THIS_MODULE, + .open = fft256_dev_open, + .release = fft256_dev_release, + .read = fft256_dev_read, + .write = fft256_dev_write, +}; + +static struct miscdevice fft256_dev_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "fft256", + .fops = &fft256_dev_fops, +}; + +/* misc device - fft_dev */ +static ssize_t fft_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 fft data buffer */ + if (copy_from_user + (dev->ioremap_fft_data_ram + DMA_DATA_OFFSET, user_buffer, + this_count * 4)) { + up(&dev->sem); + pr_info("fft_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(DMA_RAM_RESULTS_ADDR, + 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); + + /* 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 fft_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->ioremap_fft_data_ram + DMA_RESULT_OFFSET, + this_count * 8)) { + up(&dev->sem); + pr_info("fft_dev_read copy_to_user exit\n"); + return -EFAULT; + } + + up(&dev->sem); + return count; +} + +static int fft_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->fftdma_open_for_read != 0) || + (dev->fftdma_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->fft_open_for_read != 0) + goto do_exit; + dev->fft_open_for_read = 1; + break; + case (O_WRONLY): + if (dev->fft_open_for_write != 0) + goto do_exit; + dev->fft_open_for_write = 1; + break; + case (O_RDWR): + if (dev->fft_open_for_read != 0) + goto do_exit; + if (dev->fft_open_for_write != 0) + goto do_exit; + dev->fft_open_for_read = 1; + dev->fft_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 fft_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->fft_open_for_read = 0; + break; + case (O_WRONLY): + dev->fft_open_for_write = 0; + break; + case (O_RDWR): + dev->fft_open_for_read = 0; + dev->fft_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 fft_dev_fops = { + .owner = THIS_MODULE, + .open = fft_dev_open, + .release = fft_dev_release, + .read = fft_dev_read, + .write = fft_dev_write, +}; + +static struct miscdevice fft_dev_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "fft", + .fops = &fft_dev_fops, +}; + +/* platform driver */ +static int platform_probe(struct platform_device *pdev) +{ + int ret_val; + struct resource *r; + struct resource *mem_region; + uint32_t dma_status; + uint32_t dma_control; + + ret_val = -EBUSY; + + /* acquire the probe lock */ + if (down_interruptible(&g_dev_probe_sem)) + return -ERESTARTSYS; + + if (g_platform_probe_flag != 0) + goto bad_exit_return; + + ret_val = -EINVAL; + + /* get our first memory resource */ + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + pr_err("IORESOURCE_MEM, 0 does not exist\n"); + goto bad_exit_return; + } + + /* initialize the device offsets and sizes */ + the_fft_dev.phys_fft_st_adapter = r->start; + the_fft_dev.size_fft_st_adapter = 0x10; + the_fft_dev.phys_fft_data_ram = + the_fft_dev.phys_fft_st_adapter - 0x10000; + the_fft_dev.size_fft_data_ram = 0x10000; + the_fft_dev.phys_sgdma_from_fft_descriptor = + the_fft_dev.phys_fft_data_ram - 0x10000; + the_fft_dev.size_sgdma_from_fft_descriptor = 0x10; + the_fft_dev.phys_sgdma_from_fft_csr = + the_fft_dev.phys_sgdma_from_fft_descriptor - 0x10000; + the_fft_dev.size_sgdma_from_fft_csr = 0x20; + the_fft_dev.phys_sgdma_to_fft_descriptor = + the_fft_dev.phys_sgdma_from_fft_csr - 0x10000; + the_fft_dev.size_sgdma_to_fft_descriptor = 0x10; + the_fft_dev.phys_sgdma_to_fft_csr = + the_fft_dev.phys_sgdma_to_fft_descriptor - 0x10000; + the_fft_dev.size_sgdma_to_fft_csr = 0x20; + + the_fft_dev.phys_sgdma_from_ram_descriptor = + the_fft_dev.phys_sgdma_from_fft_descriptor + 0x8000; + the_fft_dev.size_sgdma_from_ram_descriptor = 0x10; + the_fft_dev.phys_sgdma_from_ram_csr = + the_fft_dev.phys_sgdma_from_fft_csr + 0x8000; + the_fft_dev.size_sgdma_from_ram_csr = 0x20; + + ret_val = -EBUSY; + + /* reserve our memory regions */ + mem_region = + request_mem_region(the_fft_dev.phys_fft_st_adapter, + the_fft_dev.size_fft_st_adapter, + "fft_st_adapter_region"); + if (mem_region == NULL) { + pr_err("request_mem_region failed: phys_fft_st_adapter\n"); + goto bad_exit_return; + } + + mem_region = + request_mem_region(the_fft_dev.phys_fft_data_ram, + the_fft_dev.size_fft_data_ram, + "fft_data_ram_region"); + if (mem_region == NULL) { + pr_err("request_mem_region failed: phys_fft_data_ram\n"); + goto bad_exit_release_fft_st_adapter_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_from_fft_descriptor, + the_fft_dev.size_sgdma_from_fft_descriptor, + "sgdma_from_fft_descriptor_region"); + if (mem_region == NULL) { + pr_err + ("request_mem_region failed: phys_sgdma_from_fft_descriptor\n"); + goto bad_exit_release_fft_data_ram_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_from_fft_csr, + the_fft_dev.size_sgdma_from_fft_csr, + "sgdma_from_fft_csr_region"); + if (mem_region == NULL) { + pr_err("request_mem_region failed: phys_sgdma_from_fft_csr\n"); + goto bad_exit_release_sgdma_from_fft_descriptor_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_to_fft_descriptor, + the_fft_dev.size_sgdma_to_fft_descriptor, + "sgdma_to_fft_descriptor_region"); + if (mem_region == NULL) { + pr_err + ("request_mem_region failed: phys_sgdma_to_fft_descriptor\n"); + goto bad_exit_release_sgdma_from_fft_csr_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_to_fft_csr, + the_fft_dev.size_sgdma_to_fft_csr, + "sgdma_to_fft_csr_region"); + if (mem_region == NULL) { + pr_err("request_mem_region failed: phys_sgdma_to_fft_csr\n"); + goto bad_exit_release_sgdma_to_fft_descriptor_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_from_ram_descriptor, + the_fft_dev.size_sgdma_from_ram_descriptor, + "sgdma_from_ram_descriptor_region"); + if (mem_region == NULL) { + pr_err + ("request_mem_region failed: phys_sgdma_from_ram_descriptor\n"); + goto bad_exit_release_sgdma_to_fft_csr_region; + } + + mem_region = + request_mem_region(the_fft_dev.phys_sgdma_from_ram_csr, + the_fft_dev.size_sgdma_from_ram_csr, + "sgdma_from_ram_csr_region"); + if (mem_region == NULL) { + pr_err("request_mem_region failed: phys_sgdma_from_ram_csr\n"); + goto bad_exit_release_sgdma_from_ram_descriptor_region; + } + + /* ioremap our memory regions */ + the_fft_dev.ioremap_fft_st_adapter = + ioremap(the_fft_dev.phys_fft_st_adapter, + the_fft_dev.size_fft_st_adapter); + if (the_fft_dev.ioremap_fft_st_adapter == NULL) { + pr_err("ioremap failed: phys_fft_st_adapter\n"); + goto bad_exit_release_sgdma_from_ram_csr_region; + } + + the_fft_dev.ioremap_fft_data_ram = + ioremap(the_fft_dev.phys_fft_data_ram, + the_fft_dev.size_fft_data_ram); + if (the_fft_dev.ioremap_fft_data_ram == NULL) { + pr_err("ioremap failed: phys_fft_data_ram\n"); + goto bad_exit_iounmap_fft_st_adapter; + } + + the_fft_dev.ioremap_sgdma_from_fft_descriptor = + ioremap(the_fft_dev.phys_sgdma_from_fft_descriptor, + the_fft_dev.size_sgdma_from_fft_descriptor); + if (the_fft_dev.ioremap_sgdma_from_fft_descriptor == NULL) { + pr_err("ioremap failed: phys_sgdma_from_fft_descriptor\n"); + goto bad_exit_iounmap_fft_data_ram; + } + + the_fft_dev.ioremap_sgdma_from_fft_csr = + ioremap(the_fft_dev.phys_sgdma_from_fft_csr, + the_fft_dev.size_sgdma_from_fft_csr); + if (the_fft_dev.ioremap_sgdma_from_fft_csr == NULL) { + pr_err("ioremap failed: phys_sgdma_from_fft_csr\n"); + goto bad_exit_iounmap_sgdma_from_fft_descriptor; + } + + the_fft_dev.ioremap_sgdma_to_fft_descriptor = + ioremap(the_fft_dev.phys_sgdma_to_fft_descriptor, + the_fft_dev.size_sgdma_to_fft_descriptor); + if (the_fft_dev.ioremap_sgdma_to_fft_descriptor == NULL) { + pr_err("ioremap failed: phys_sgdma_to_fft_descriptor\n"); + goto bad_exit_iounmap_sgdma_from_fft_csr; + } + + the_fft_dev.ioremap_sgdma_to_fft_csr = + ioremap(the_fft_dev.phys_sgdma_to_fft_csr, + the_fft_dev.size_sgdma_to_fft_csr); + if (the_fft_dev.ioremap_sgdma_to_fft_csr == NULL) { + pr_err("ioremap failed: phys_sgdma_to_fft_csr\n"); + goto bad_exit_iounmap_sgdma_to_fft_descriptor; + } + + the_fft_dev.ioremap_sgdma_from_ram_descriptor = + ioremap(the_fft_dev.phys_sgdma_from_ram_descriptor, + the_fft_dev.size_sgdma_from_ram_descriptor); + if (the_fft_dev.ioremap_sgdma_from_ram_descriptor == NULL) { + pr_err("ioremap failed: phys_sgdma_from_ram_descriptor\n"); + goto bad_exit_iounmap_sgdma_to_fft_csr; + } + + the_fft_dev.ioremap_sgdma_from_ram_csr = + ioremap(the_fft_dev.phys_sgdma_from_ram_csr, + the_fft_dev.size_sgdma_from_ram_csr); + if (the_fft_dev.ioremap_sgdma_from_ram_csr == NULL) { + pr_err("ioremap failed: phys_sgdma_from_ram_csr\n"); + goto bad_exit_iounmap_sgdma_from_ram_descriptor; + } + + /* initialize the DMA controllers */ + dma_status = + ioread32(the_fft_dev.ioremap_sgdma_from_fft_csr + CSR_STATUS_REG); + if ((dma_status & + (CSR_BUSY_MASK | CSR_STOP_STATE_MASK | + CSR_RESET_STATE_MASK | + CSR_IRQ_SET_MASK)) != 0) { + pr_err("sgdma_from_fft\n"); + pr_err("initial dma status set unexpected: 0x%08X\n", + dma_status); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + if ((dma_status & + CSR_DESCRIPTOR_BUFFER_EMPTY_MASK) == 0) { + pr_err("sgdma_from_fft\n"); + pr_err("initial dma status cleared unexpected: 0x%08X\n", + dma_status); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + dma_control = + ioread32(the_fft_dev.ioremap_sgdma_from_fft_csr + CSR_CONTROL_REG); + if ((dma_control & + (CSR_STOP_MASK | CSR_RESET_MASK | + CSR_STOP_ON_ERROR_MASK | + CSR_STOP_ON_EARLY_TERMINATION_MASK | + CSR_GLOBAL_INTERRUPT_MASK | + CSR_STOP_DESCRIPTORS_MASK)) != 0) { + pr_err("sgdma_from_fft\n"); + pr_err("initial dma control set unexpected: 0x%08X\n", + dma_control); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + dma_status = + ioread32(the_fft_dev.ioremap_sgdma_to_fft_csr + CSR_STATUS_REG); + if ((dma_status & + (CSR_BUSY_MASK | CSR_STOP_STATE_MASK | + CSR_RESET_STATE_MASK | + CSR_IRQ_SET_MASK)) != 0) { + pr_err("sgdma_to_fft\n"); + pr_err("initial dma status set unexpected: 0x%08X\n", + dma_status); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + if ((dma_status & + CSR_DESCRIPTOR_BUFFER_EMPTY_MASK) == 0) { + pr_err("sgdma_to_fft\n"); + pr_err("initial dma status cleared unexpected: 0x%08X\n", + dma_status); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + dma_control = + ioread32(the_fft_dev.ioremap_sgdma_to_fft_csr + CSR_CONTROL_REG); + if ((dma_control & + (CSR_STOP_MASK | CSR_RESET_MASK | + CSR_STOP_ON_ERROR_MASK | + CSR_STOP_ON_EARLY_TERMINATION_MASK | + CSR_GLOBAL_INTERRUPT_MASK | + CSR_STOP_DESCRIPTORS_MASK)) != 0) { + pr_err("sgdma_to_fft\n"); + pr_err("initial dma control set unexpected: 0x%08X\n", + dma_control); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + /* allocate dma buffer */ + ret_val = -ENOMEM; + the_fft_dev.dma_buffer = kmalloc(DMA_BUFFER_ALLOC_SIZE, GFP_KERNEL); + if (the_fft_dev.dma_buffer == NULL) { + pr_err("kmalloc dma_buffer failed\n"); + goto bad_exit_iounmap_sgdma_from_ram_csr; + } + + the_fft_dev.dma_handle = + dma_map_single(&pdev->dev, the_fft_dev.dma_buffer, + DMA_BUFFER_ALLOC_SIZE, DMA_BIDIRECTIONAL); + + if (dma_mapping_error(&pdev->dev, the_fft_dev.dma_handle)) { + pr_info("dma mapping error exit\n"); + goto bad_exit_kfree; + } + + if ((the_fft_dev.dma_handle & (0xC0000000)) != 0) { + pr_info("dma_handle out of range exit\n"); + goto bad_exit_dma_unmap; + } + + /* register misc device fft_dev */ + sema_init(&the_fft_dev.sem, 1); + the_fft_dev.fft_open_for_read = 0; + the_fft_dev.fft_open_for_write = 0; + the_fft_dev.fft256_open_for_read = 0; + the_fft_dev.fft256_open_for_write = 0; + the_fft_dev.fftdma_open_for_read = 0; + the_fft_dev.fftdma_open_for_write = 0; + the_fft_dev.fft256dma_open_for_read = 0; + the_fft_dev.fft256dma_open_for_write = 0; + the_fft_dev.fft256stream_open_for_read = 0; + the_fft_dev.fft256stream_open_for_write = 0; + the_fft_dev.raw256stream_open_for_read = 0; + the_fft_dev.raw256stream_open_for_write = 0; + the_fft_dev.fft256_buffer_read_index = 0; + the_fft_dev.fft256_buffer_write_index = 0; + the_fft_dev.fft256_buffer_inflight_count = 0; + + ret_val = misc_register(&fft_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"fft\"..."); + goto bad_exit_dma_unmap; + } + + /* register misc device fft256_dev */ + ret_val = misc_register(&fft256_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"fft256\"..."); + goto bad_exit_deregister_fft_dev; + } + + /* register misc device fftdma_dev */ + ret_val = misc_register(&fftdma_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"fftdma\"..."); + goto bad_exit_deregister_fft256_dev; + } + + /* register misc device fft256dma_dev */ + ret_val = misc_register(&fft256dma_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"fft256dma\"..."); + goto bad_exit_deregister_fftdma_dev; + } + + /* register misc device fft256stream_dev */ + ret_val = misc_register(&fft256stream_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"fft256stream\"..."); + goto bad_exit_deregister_fft256dma_dev; + } + + /* register misc device raw256stream_dev */ + ret_val = misc_register(&raw256stream_dev_device); + if (ret_val != 0) { + pr_warn("Could not register device \"raw256stream\"..."); + goto bad_exit_deregister_fft256stream_dev; + } + + g_platform_probe_flag = 1; + up(&g_dev_probe_sem); + return 0; + +bad_exit_deregister_fft256stream_dev: + misc_deregister(&fft256stream_dev_device); +bad_exit_deregister_fft256dma_dev: + misc_deregister(&fft256dma_dev_device); +bad_exit_deregister_fftdma_dev: + misc_deregister(&fftdma_dev_device); +bad_exit_deregister_fft256_dev: + misc_deregister(&fft256_dev_device); +bad_exit_deregister_fft_dev: + misc_deregister(&fft_dev_device); +bad_exit_dma_unmap: + dma_unmap_single(&pdev->dev, the_fft_dev.dma_handle, + DMA_BUFFER_ALLOC_SIZE, DMA_BIDIRECTIONAL); +bad_exit_kfree: + kfree(the_fft_dev.dma_buffer); +bad_exit_iounmap_sgdma_from_ram_csr: + iounmap(the_fft_dev.ioremap_sgdma_from_ram_csr); +bad_exit_iounmap_sgdma_from_ram_descriptor: + iounmap(the_fft_dev.ioremap_sgdma_from_ram_descriptor); +bad_exit_iounmap_sgdma_to_fft_csr: + iounmap(the_fft_dev.ioremap_sgdma_to_fft_csr); +bad_exit_iounmap_sgdma_to_fft_descriptor: + iounmap(the_fft_dev.ioremap_sgdma_to_fft_descriptor); +bad_exit_iounmap_sgdma_from_fft_csr: + iounmap(the_fft_dev.ioremap_sgdma_from_fft_csr); +bad_exit_iounmap_sgdma_from_fft_descriptor: + iounmap(the_fft_dev.ioremap_sgdma_from_fft_descriptor); +bad_exit_iounmap_fft_data_ram: + iounmap(the_fft_dev.ioremap_fft_data_ram); +bad_exit_iounmap_fft_st_adapter: + iounmap(the_fft_dev.ioremap_fft_st_adapter); +bad_exit_release_sgdma_from_ram_csr_region: + release_mem_region(the_fft_dev.phys_sgdma_from_ram_csr, + the_fft_dev.size_sgdma_from_ram_csr); +bad_exit_release_sgdma_from_ram_descriptor_region: + release_mem_region(the_fft_dev.phys_sgdma_from_ram_descriptor, + the_fft_dev.size_sgdma_from_ram_descriptor); +bad_exit_release_sgdma_to_fft_csr_region: + release_mem_region(the_fft_dev.phys_sgdma_to_fft_csr, + the_fft_dev.size_sgdma_to_fft_csr); +bad_exit_release_sgdma_to_fft_descriptor_region: + release_mem_region(the_fft_dev.phys_sgdma_to_fft_descriptor, + the_fft_dev.size_sgdma_to_fft_descriptor); +bad_exit_release_sgdma_from_fft_csr_region: + release_mem_region(the_fft_dev.phys_sgdma_from_fft_csr, + the_fft_dev.size_sgdma_from_fft_csr); +bad_exit_release_sgdma_from_fft_descriptor_region: + release_mem_region(the_fft_dev.phys_sgdma_from_fft_descriptor, + the_fft_dev.size_sgdma_from_fft_descriptor); +bad_exit_release_fft_data_ram_region: + release_mem_region(the_fft_dev.phys_fft_data_ram, + the_fft_dev.size_fft_data_ram); +bad_exit_release_fft_st_adapter_region: + release_mem_region(the_fft_dev.phys_fft_st_adapter, + the_fft_dev.size_fft_st_adapter); +bad_exit_return: + up(&g_dev_probe_sem); + return ret_val; +} + +static int platform_remove(struct platform_device *pdev) +{ + misc_deregister(&raw256stream_dev_device); + misc_deregister(&fft256stream_dev_device); + misc_deregister(&fft256dma_dev_device); + misc_deregister(&fftdma_dev_device); + misc_deregister(&fft256_dev_device); + misc_deregister(&fft_dev_device); + dma_unmap_single(&pdev->dev, the_fft_dev.dma_handle, + DMA_BUFFER_ALLOC_SIZE, DMA_BIDIRECTIONAL); + kfree(the_fft_dev.dma_buffer); + iounmap(the_fft_dev.ioremap_sgdma_from_ram_csr); + iounmap(the_fft_dev.ioremap_sgdma_from_ram_descriptor); + iounmap(the_fft_dev.ioremap_sgdma_to_fft_csr); + iounmap(the_fft_dev.ioremap_sgdma_to_fft_descriptor); + iounmap(the_fft_dev.ioremap_sgdma_from_fft_csr); + iounmap(the_fft_dev.ioremap_sgdma_from_fft_descriptor); + iounmap(the_fft_dev.ioremap_fft_data_ram); + iounmap(the_fft_dev.ioremap_fft_st_adapter); + release_mem_region(the_fft_dev.phys_sgdma_from_ram_csr, + the_fft_dev.size_sgdma_from_ram_csr); + release_mem_region(the_fft_dev.phys_sgdma_from_ram_descriptor, + the_fft_dev.size_sgdma_from_ram_descriptor); + release_mem_region(the_fft_dev.phys_sgdma_to_fft_csr, + the_fft_dev.size_sgdma_to_fft_csr); + release_mem_region(the_fft_dev.phys_sgdma_to_fft_descriptor, + the_fft_dev.size_sgdma_to_fft_descriptor); + release_mem_region(the_fft_dev.phys_sgdma_from_fft_csr, + the_fft_dev.size_sgdma_from_fft_csr); + release_mem_region(the_fft_dev.phys_sgdma_from_fft_descriptor, + the_fft_dev.size_sgdma_from_fft_descriptor); + release_mem_region(the_fft_dev.phys_fft_data_ram, + the_fft_dev.size_fft_data_ram); + release_mem_region(the_fft_dev.phys_fft_st_adapter, + the_fft_dev.size_fft_st_adapter); + + if (down_interruptible(&g_dev_probe_sem)) + return -ERESTARTSYS; + + g_platform_probe_flag = 0; + up(&g_dev_probe_sem); + + return 0; +} + +static struct of_device_id fft_driver_dt_ids[] = { + { + .compatible = "altr,fft_stadapter"}, + { /* end of table */ } +}; + +MODULE_DEVICE_TABLE(of, fft_driver_dt_ids); + +static struct platform_driver the_platform_driver = { + .probe = platform_probe, + .remove = platform_remove, + .driver = { + .name = "fft_driver", + .owner = THIS_MODULE, + .of_match_table = fft_driver_dt_ids, + }, +}; + +static int demo_init(void) +{ + int ret_val; + + sema_init(&g_dev_probe_sem, 1); + + ret_val = platform_driver_register(&the_platform_driver); + if (ret_val != 0) { + pr_err("platform_driver_register returned %d\n", ret_val); + return ret_val; + } + + return 0; +} + +static void demo_exit(void) +{ + platform_driver_unregister(&the_platform_driver); +} + +module_init(demo_init); +module_exit(demo_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rod Frazer "); +MODULE_DESCRIPTION("Driver for custom Qsys FFT subsystem."); +MODULE_VERSION("1.0"); -- cgit v1.1