/*
* CARMA DATA-FPGA Access Driver
*
* Copyright (c) 2009-2011 Ira W. Snyder <iws@ovro.caltech.edu>
*
* 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.
*/
/*
* FPGA Memory Dump Format
*
* FPGA #0 control registers (32 x 32-bit words)
* FPGA #1 control registers (32 x 32-bit words)
* FPGA #2 control registers (32 x 32-bit words)
* FPGA #3 control registers (32 x 32-bit words)
* SYSFPGA control registers (32 x 32-bit words)
* FPGA #0 correlation array (NUM_CORL0 correlation blocks)
* FPGA #1 correlation array (NUM_CORL1 correlation blocks)
* FPGA #2 correlation array (NUM_CORL2 correlation blocks)
* FPGA #3 correlation array (NUM_CORL3 correlation blocks)
*
* Each correlation array consists of:
*
* Correlation Data (2 x NUM_LAGSn x 32-bit words)
* Pipeline Metadata (2 x NUM_METAn x 32-bit words)
* Quantization Counters (2 x NUM_QCNTn x 32-bit words)
*
* The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
* the FPGA configuration registers. They do not change once the FPGA's
* have been programmed, they only change on re-programming.
*/
/*
* Basic Description:
*
* This driver is used to capture correlation spectra off of the four data
* processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
* this driver supports dynamic enable/disable of capture while the device
* remains open.
*
* The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast
* capture rate, all buffers are pre-allocated to avoid any potentially long
* running memory allocations while capturing.
*
* There are two lists and one pointer which are used to keep track of the
* different states of data buffers.
*
* 1) free list
* This list holds all empty data buffers which are ready to receive data.
*
* 2) inflight pointer
* This pointer holds the currently inflight data buffer. This buffer is having
* data copied into it by the DMA engine.
*
* 3) used list
* This list holds data buffers which have been filled, and are waiting to be
* read by userspace.
*
* All buffers start life on the free list, then move successively to the
* inflight pointer, and then to the used list. After they have been read by
* userspace, they are moved back to the free list. The cycle repeats as long
* as necessary.
*
* It should be noted that all buffers are mapped and ready for DMA when they
* are on any of the three lists. They are only unmapped when they are in the
* process of being read by userspace.
*/
/*
* Notes on the IRQ masking scheme:
*
* The IRQ masking scheme here is different than most other hardware. The only
* way for the DATA-FPGAs to detect if the kernel has taken too long to copy
* the data is if the status registers are not cleared before the next
* correlation data dump is ready.
*
* The interrupt line is connected to the status registers, such that when they
* are cleared, the interrupt is de-asserted. Therein lies our problem. We need
* to schedule a long-running DMA operation and return from the interrupt
* handler quickly, but we cannot clear the status registers.
*
* To handle this, the system controller FPGA has the capability to connect the
* interrupt line to a user-controlled GPIO pin. This pin is driven high
* (unasserted) and left that way. To mask the interrupt, we change the
* interrupt source to the GPIO pin. Tada, we hid the interrupt. :)
*/
#include <linux/of_platform.h>
#include <linux/dma-mapping.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/seq_file.h>
#include <linux/highmem.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kref.h>
#include <linux/io.h>
#include <media/videobuf-dma-sg.h>
/* system controller registers */
#define SYS_IRQ_SOURCE_CTL 0x24
#define SYS_IRQ_OUTPUT_EN 0x28
#define SYS_IRQ_OUTPUT_DATA 0x2C