2011-02-11 13:34:30 +00:00
/*
* CARMA Board DATA - FPGA Programmer
*
* 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 .
*/
# include <linux/dma-mapping.h>
2013-09-17 14:28:33 -05:00
# include <linux/of_address.h>
# include <linux/of_irq.h>
2011-02-11 13:34:30 +00:00
# include <linux/of_platform.h>
# include <linux/completion.h>
# include <linux/miscdevice.h>
# include <linux/dmaengine.h>
# include <linux/interrupt.h>
# include <linux/highmem.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/leds.h>
# include <linux/slab.h>
# include <linux/kref.h>
# include <linux/fs.h>
# include <linux/io.h>
# include <media/videobuf-dma-sg.h>
/* MPC8349EMDS specific get_immrbase() */
# include <sysdev/fsl_soc.h>
static const char drv_name [ ] = " carma-fpga-program " ;
/*
* Firmware images are always this exact size
*
* 12849552 bytes for a CARMA Digitizer Board ( EP2S90 FPGAs )
* 18662880 bytes for a CARMA Correlator Board ( EP2S130 FPGAs )
*/
# define FW_SIZE_EP2S90 12849552
# define FW_SIZE_EP2S130 18662880
struct fpga_dev {
struct miscdevice miscdev ;
/* Reference count */
struct kref ref ;
/* Device Registers */
struct device * dev ;
void __iomem * regs ;
void __iomem * immr ;
/* Freescale DMA Device */
struct dma_chan * chan ;
/* Interrupts */
int irq , status ;
struct completion completion ;
/* FPGA Bitfile */
struct mutex lock ;
struct videobuf_dmabuf vb ;
bool vb_allocated ;
/* max size and written bytes */
size_t fw_size ;
size_t bytes ;
} ;
/*
* FPGA Bitfile Helpers
*/
/**
* fpga_drop_firmware_data ( ) - drop the bitfile image from memory
* @ priv : the driver ' s private data structure
*
* LOCKING : must hold priv - > lock
*/
static void fpga_drop_firmware_data ( struct fpga_dev * priv )
{
videobuf_dma_free ( & priv - > vb ) ;
priv - > vb_allocated = false ;
priv - > bytes = 0 ;
}
/*
* Private Data Reference Count
*/
static void fpga_dev_remove ( struct kref * ref )
{
struct fpga_dev * priv = container_of ( ref , struct fpga_dev , ref ) ;
/* free any firmware image that was not programmed */
fpga_drop_firmware_data ( priv ) ;
mutex_destroy ( & priv - > lock ) ;
kfree ( priv ) ;
}
/*
* LED Trigger ( could be a seperate module )
*/
/*
* NOTE : this whole thing does have the problem that whenever the led ' s are
* NOTE : first set to use the fpga trigger , they could be in the wrong state
*/
DEFINE_LED_TRIGGER ( ledtrig_fpga ) ;
static void ledtrig_fpga_programmed ( bool enabled )
{
if ( enabled )
led_trigger_event ( ledtrig_fpga , LED_FULL ) ;
else
led_trigger_event ( ledtrig_fpga , LED_OFF ) ;
}
/*
* FPGA Register Helpers
*/
/* Register Definitions */
# define FPGA_CONFIG_CONTROL 0x40
# define FPGA_CONFIG_STATUS 0x44
# define FPGA_CONFIG_FIFO_SIZE 0x48
# define FPGA_CONFIG_FIFO_USED 0x4C
# define FPGA_CONFIG_TOTAL_BYTE_COUNT 0x50
# define FPGA_CONFIG_CUR_BYTE_COUNT 0x54
# define FPGA_FIFO_ADDRESS 0x3000
static int fpga_fifo_size ( void __iomem * regs )
{
return ioread32be ( regs + FPGA_CONFIG_FIFO_SIZE ) ;
}
# define CFG_STATUS_ERR_MASK 0xfffe
static int fpga_config_error ( void __iomem * regs )
{
return ioread32be ( regs + FPGA_CONFIG_STATUS ) & CFG_STATUS_ERR_MASK ;
}
static int fpga_fifo_empty ( void __iomem * regs )
{
return ioread32be ( regs + FPGA_CONFIG_FIFO_USED ) = = 0 ;
}
static void fpga_fifo_write ( void __iomem * regs , u32 val )
{
iowrite32be ( val , regs + FPGA_FIFO_ADDRESS ) ;
}
static void fpga_set_byte_count ( void __iomem * regs , u32 count )
{
iowrite32be ( count , regs + FPGA_CONFIG_TOTAL_BYTE_COUNT ) ;
}
# define CFG_CTL_ENABLE (1 << 0)
# define CFG_CTL_RESET (1 << 1)
# define CFG_CTL_DMA (1 << 2)
static void fpga_programmer_enable ( struct fpga_dev * priv , bool dma )
{
u32 val ;
val = ( dma ) ? ( CFG_CTL_ENABLE | CFG_CTL_DMA ) : CFG_CTL_ENABLE ;
iowrite32be ( val , priv - > regs + FPGA_CONFIG_CONTROL ) ;
}
static void fpga_programmer_disable ( struct fpga_dev * priv )
{
iowrite32be ( 0x0 , priv - > regs + FPGA_CONFIG_CONTROL ) ;
}
static void fpga_dump_registers ( struct fpga_dev * priv )
{
u32 control , status , size , used , total , curr ;
/* good status: do nothing */
if ( priv - > status = = 0 )
return ;
/* Dump all status registers */
control = ioread32be ( priv - > regs + FPGA_CONFIG_CONTROL ) ;
status = ioread32be ( priv - > regs + FPGA_CONFIG_STATUS ) ;
size = ioread32be ( priv - > regs + FPGA_CONFIG_FIFO_SIZE ) ;
used = ioread32be ( priv - > regs + FPGA_CONFIG_FIFO_USED ) ;
total = ioread32be ( priv - > regs + FPGA_CONFIG_TOTAL_BYTE_COUNT ) ;
curr = ioread32be ( priv - > regs + FPGA_CONFIG_CUR_BYTE_COUNT ) ;
dev_err ( priv - > dev , " Configuration failed, dumping status registers \n " ) ;
dev_err ( priv - > dev , " Control: 0x%.8x \n " , control ) ;
dev_err ( priv - > dev , " Status: 0x%.8x \n " , status ) ;
dev_err ( priv - > dev , " FIFO Size: 0x%.8x \n " , size ) ;
dev_err ( priv - > dev , " FIFO Used: 0x%.8x \n " , used ) ;
dev_err ( priv - > dev , " FIFO Total: 0x%.8x \n " , total ) ;
dev_err ( priv - > dev , " FIFO Curr: 0x%.8x \n " , curr ) ;
}
/*
* FPGA Power Supply Code
*/
# define CTL_PWR_CONTROL 0x2006
# define CTL_PWR_STATUS 0x200A
# define CTL_PWR_FAIL 0x200B
# define PWR_CONTROL_ENABLE 0x01
# define PWR_STATUS_ERROR_MASK 0x10
# define PWR_STATUS_GOOD 0x0f
/*
* Determine if the FPGA power is good for all supplies
*/
static bool fpga_power_good ( struct fpga_dev * priv )
{
u8 val ;
val = ioread8 ( priv - > regs + CTL_PWR_STATUS ) ;
if ( val & PWR_STATUS_ERROR_MASK )
return false ;
return val = = PWR_STATUS_GOOD ;
}
/*
* Disable the FPGA power supplies
*/
static void fpga_disable_power_supplies ( struct fpga_dev * priv )
{
unsigned long start ;
u8 val ;
iowrite8 ( 0x0 , priv - > regs + CTL_PWR_CONTROL ) ;
/*
* Wait 500 ms for the power rails to discharge
*
* Without this delay , the CTL - CPLD state machine can get into a
* state where it is waiting for the power - goods to assert , but they
* never do . This only happens when enabling and disabling the
* power sequencer very rapidly .
*
* The loop below will also wait for the power goods to de - assert ,
* but testing has shown that they are always disabled by the time
* the sleep completes . However , omitting the sleep and only waiting
* for the power - goods to de - assert was not sufficient to ensure
* that the power sequencer would not wedge itself .
*/
msleep ( 500 ) ;
start = jiffies ;
while ( time_before ( jiffies , start + HZ ) ) {
val = ioread8 ( priv - > regs + CTL_PWR_STATUS ) ;
if ( ! ( val & PWR_STATUS_GOOD ) )
break ;
usleep_range ( 5000 , 10000 ) ;
}
val = ioread8 ( priv - > regs + CTL_PWR_STATUS ) ;
if ( val & PWR_STATUS_GOOD ) {
dev_err ( priv - > dev , " power disable failed: "
" power goods: status 0x%.2x \n " , val ) ;
}
if ( val & PWR_STATUS_ERROR_MASK ) {
dev_err ( priv - > dev , " power disable failed: "
" alarm bit set: status 0x%.2x \n " , val ) ;
}
}
/**
* fpga_enable_power_supplies ( ) - enable the DATA - FPGA power supplies
* @ priv : the driver ' s private data structure
*
* Enable the DATA - FPGA power supplies , waiting up to 1 second for
* them to enable successfully .
*
* Returns 0 on success , - ERRNO otherwise
*/
static int fpga_enable_power_supplies ( struct fpga_dev * priv )
{
unsigned long start = jiffies ;
if ( fpga_power_good ( priv ) ) {
dev_dbg ( priv - > dev , " power was already good \n " ) ;
return 0 ;
}
iowrite8 ( PWR_CONTROL_ENABLE , priv - > regs + CTL_PWR_CONTROL ) ;
while ( time_before ( jiffies , start + HZ ) ) {
if ( fpga_power_good ( priv ) )
return 0 ;
usleep_range ( 5000 , 10000 ) ;
}
return fpga_power_good ( priv ) ? 0 : - ETIMEDOUT ;
}
/*
* Determine if the FPGA power supplies are all enabled
*/
static bool fpga_power_enabled ( struct fpga_dev * priv )
{
u8 val ;
val = ioread8 ( priv - > regs + CTL_PWR_CONTROL ) ;
if ( val & PWR_CONTROL_ENABLE )
return true ;
return false ;
}
/*
* Determine if the FPGA ' s are programmed and running correctly
*/
static bool fpga_running ( struct fpga_dev * priv )
{
if ( ! fpga_power_good ( priv ) )
return false ;
/* Check the config done bit */
return ioread32be ( priv - > regs + FPGA_CONFIG_STATUS ) & ( 1 < < 18 ) ;
}
/*
* FPGA Programming Code
*/
/**
* fpga_program_block ( ) - put a block of data into the programmer ' s FIFO
* @ priv : the driver ' s private data structure
* @ buf : the data to program
* @ count : the length of data to program ( must be a multiple of 4 bytes )
*
* Returns 0 on success , - ERRNO otherwise
*/
static int fpga_program_block ( struct fpga_dev * priv , void * buf , size_t count )
{
u32 * data = buf ;
int size = fpga_fifo_size ( priv - > regs ) ;
int i , len ;
unsigned long timeout ;
/* enforce correct data length for the FIFO */
BUG_ON ( count % 4 ! = 0 ) ;
while ( count > 0 ) {
/* Get the size of the block to write (maximum is FIFO_SIZE) */
len = min_t ( size_t , count , size ) ;
timeout = jiffies + HZ / 4 ;
/* Write the block */
for ( i = 0 ; i < len / 4 ; i + + )
fpga_fifo_write ( priv - > regs , data [ i ] ) ;
/* Update the amounts left */
count - = len ;
data + = len / 4 ;
/* Wait for the fifo to empty */
while ( true ) {
if ( fpga_fifo_empty ( priv - > regs ) ) {
break ;
} else {
dev_dbg ( priv - > dev , " Fifo not empty \n " ) ;
cpu_relax ( ) ;
}
if ( fpga_config_error ( priv - > regs ) ) {
dev_err ( priv - > dev , " Error detected \n " ) ;
return - EIO ;
}
if ( time_after ( jiffies , timeout ) ) {
dev_err ( priv - > dev , " Fifo drain timeout \n " ) ;
return - ETIMEDOUT ;
}
usleep_range ( 5000 , 10000 ) ;
}
}
return 0 ;
}
/**
* fpga_program_cpu ( ) - program the DATA - FPGA ' s using the CPU
* @ priv : the driver ' s private data structure
*
* This is useful when the DMA programming method fails . It is possible to
* wedge the Freescale DMA controller such that the DMA programming method
* always fails . This method has always succeeded .
*
* Returns 0 on success , - ERRNO otherwise
*/
static noinline int fpga_program_cpu ( struct fpga_dev * priv )
{
int ret ;
/* Disable the programmer */
fpga_programmer_disable ( priv ) ;
/* Set the total byte count */
fpga_set_byte_count ( priv - > regs , priv - > bytes ) ;
dev_dbg ( priv - > dev , " total byte count %u bytes \n " , priv - > bytes ) ;
/* Enable the controller for programming */
fpga_programmer_enable ( priv , false ) ;
dev_dbg ( priv - > dev , " enabled the controller \n " ) ;
/* Write each chunk of the FPGA bitfile to FPGA programmer */
ret = fpga_program_block ( priv , priv - > vb . vaddr , priv - > bytes ) ;
if ( ret )
goto out_disable_controller ;
/* Wait for the interrupt handler to signal that programming finished */
ret = wait_for_completion_timeout ( & priv - > completion , 2 * HZ ) ;
if ( ! ret ) {
dev_err ( priv - > dev , " Timed out waiting for completion \n " ) ;
ret = - ETIMEDOUT ;
goto out_disable_controller ;
}
/* Retrieve the status from the interrupt handler */
ret = priv - > status ;
out_disable_controller :
fpga_programmer_disable ( priv ) ;
return ret ;
}
# define FIFO_DMA_ADDRESS 0xf0003000
# define FIFO_MAX_LEN 4096
/**
* fpga_program_dma ( ) - program the DATA - FPGA ' s using the DMA engine
* @ priv : the driver ' s private data structure
*
* Program the DATA - FPGA ' s using the Freescale DMA engine . This requires that
* the engine is programmed such that the hardware DMA request lines can
* control the entire DMA transaction . The system controller FPGA then
* completely offloads the programming from the CPU .
*
* Returns 0 on success , - ERRNO otherwise
*/
static noinline int fpga_program_dma ( struct fpga_dev * priv )
{
struct videobuf_dmabuf * vb = & priv - > vb ;
struct dma_chan * chan = priv - > chan ;
struct dma_async_tx_descriptor * tx ;
size_t num_pages , len , avail = 0 ;
struct dma_slave_config config ;
struct scatterlist * sg ;
struct sg_table table ;
dma_cookie_t cookie ;
int ret , i ;
/* Disable the programmer */
fpga_programmer_disable ( priv ) ;
/* Allocate a scatterlist for the DMA destination */
num_pages = DIV_ROUND_UP ( priv - > bytes , FIFO_MAX_LEN ) ;
ret = sg_alloc_table ( & table , num_pages , GFP_KERNEL ) ;
if ( ret ) {
dev_err ( priv - > dev , " Unable to allocate dst scatterlist \n " ) ;
ret = - ENOMEM ;
goto out_return ;
}
/*
* This is an ugly hack
*
* We fill in a scatterlist as if it were mapped for DMA . This is
* necessary because there exists no better structure for this
* inside the kernel code .
*
* As an added bonus , we can use the DMAEngine API for all of this ,
* rather than inventing another extremely similar API .
*/
avail = priv - > bytes ;
for_each_sg ( table . sgl , sg , num_pages , i ) {
len = min_t ( size_t , avail , FIFO_MAX_LEN ) ;
sg_dma_address ( sg ) = FIFO_DMA_ADDRESS ;
sg_dma_len ( sg ) = len ;
avail - = len ;
}
/* Map the buffer for DMA */
ret = videobuf_dma_map ( priv - > dev , & priv - > vb ) ;
if ( ret ) {
dev_err ( priv - > dev , " Unable to map buffer for DMA \n " ) ;
goto out_free_table ;
}
/*
* Configure the DMA channel to transfer FIFO_SIZE / 2 bytes per
* transaction , and then put it under external control
*/
memset ( & config , 0 , sizeof ( config ) ) ;
2011-10-14 10:42:56 +05:30
config . direction = DMA_MEM_TO_DEV ;
2011-02-11 13:34:30 +00:00
config . dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
config . dst_maxburst = fpga_fifo_size ( priv - > regs ) / 2 / 4 ;
ret = chan - > device - > device_control ( chan , DMA_SLAVE_CONFIG ,
( unsigned long ) & config ) ;
if ( ret ) {
dev_err ( priv - > dev , " DMA slave configuration failed \n " ) ;
goto out_dma_unmap ;
}
ret = chan - > device - > device_control ( chan , FSLDMA_EXTERNAL_START , 1 ) ;
if ( ret ) {
dev_err ( priv - > dev , " DMA external control setup failed \n " ) ;
goto out_dma_unmap ;
}
/* setup and submit the DMA transaction */
tx = chan - > device - > device_prep_dma_sg ( chan ,
table . sgl , num_pages ,
vb - > sglist , vb - > sglen , 0 ) ;
if ( ! tx ) {
dev_err ( priv - > dev , " Unable to prep DMA transaction \n " ) ;
ret = - ENOMEM ;
goto out_dma_unmap ;
}
cookie = tx - > tx_submit ( tx ) ;
if ( dma_submit_error ( cookie ) ) {
dev_err ( priv - > dev , " Unable to submit DMA transaction \n " ) ;
ret = - ENOMEM ;
goto out_dma_unmap ;
}
2012-11-08 09:59:54 +00:00
dma_async_issue_pending ( chan ) ;
2011-02-11 13:34:30 +00:00
/* Set the total byte count */
fpga_set_byte_count ( priv - > regs , priv - > bytes ) ;
dev_dbg ( priv - > dev , " total byte count %u bytes \n " , priv - > bytes ) ;
/* Enable the controller for DMA programming */
fpga_programmer_enable ( priv , true ) ;
dev_dbg ( priv - > dev , " enabled the controller \n " ) ;
/* Wait for the interrupt handler to signal that programming finished */
ret = wait_for_completion_timeout ( & priv - > completion , 2 * HZ ) ;
if ( ! ret ) {
dev_err ( priv - > dev , " Timed out waiting for completion \n " ) ;
ret = - ETIMEDOUT ;
goto out_disable_controller ;
}
/* Retrieve the status from the interrupt handler */
ret = priv - > status ;
out_disable_controller :
fpga_programmer_disable ( priv ) ;
out_dma_unmap :
videobuf_dma_unmap ( priv - > dev , vb ) ;
out_free_table :
sg_free_table ( & table ) ;
out_return :
return ret ;
}
/*
* Interrupt Handling
*/
static irqreturn_t fpga_irq ( int irq , void * dev_id )
{
struct fpga_dev * priv = dev_id ;
/* Save the status */
priv - > status = fpga_config_error ( priv - > regs ) ? - EIO : 0 ;
dev_dbg ( priv - > dev , " INTERRUPT status %d \n " , priv - > status ) ;
fpga_dump_registers ( priv ) ;
/* Disabling the programmer clears the interrupt */
fpga_programmer_disable ( priv ) ;
/* Notify any waiters */
complete ( & priv - > completion ) ;
return IRQ_HANDLED ;
}
/*
* SYSFS Helpers
*/
/**
* fpga_do_stop ( ) - deconfigure ( reset ) the DATA - FPGA ' s
* @ priv : the driver ' s private data structure
*
* LOCKING : must hold priv - > lock
*/
static int fpga_do_stop ( struct fpga_dev * priv )
{
u32 val ;
/* Set the led to unprogrammed */
ledtrig_fpga_programmed ( false ) ;
/* Pulse the config line to reset the FPGA's */
val = CFG_CTL_ENABLE | CFG_CTL_RESET ;
iowrite32be ( val , priv - > regs + FPGA_CONFIG_CONTROL ) ;
iowrite32be ( 0x0 , priv - > regs + FPGA_CONFIG_CONTROL ) ;
return 0 ;
}
static noinline int fpga_do_program ( struct fpga_dev * priv )
{
int ret ;
if ( priv - > bytes ! = priv - > fw_size ) {
dev_err ( priv - > dev , " Incorrect bitfile size: got %zu bytes, "
" should be %zu bytes \n " ,
priv - > bytes , priv - > fw_size ) ;
return - EINVAL ;
}
if ( ! fpga_power_enabled ( priv ) ) {
dev_err ( priv - > dev , " Power not enabled \n " ) ;
return - EINVAL ;
}
if ( ! fpga_power_good ( priv ) ) {
dev_err ( priv - > dev , " Power not good \n " ) ;
return - EINVAL ;
}
/* Set the LED to unprogrammed */
ledtrig_fpga_programmed ( false ) ;
/* Try to program the FPGA's using DMA */
ret = fpga_program_dma ( priv ) ;
/* If DMA failed or doesn't exist, try with CPU */
if ( ret ) {
dev_warn ( priv - > dev , " Falling back to CPU programming \n " ) ;
ret = fpga_program_cpu ( priv ) ;
}
if ( ret ) {
dev_err ( priv - > dev , " Unable to program FPGA's \n " ) ;
return ret ;
}
/* Drop the firmware bitfile from memory */
fpga_drop_firmware_data ( priv ) ;
dev_dbg ( priv - > dev , " FPGA programming successful \n " ) ;
ledtrig_fpga_programmed ( true ) ;
return 0 ;
}
/*
* File Operations
*/
static int fpga_open ( struct inode * inode , struct file * filp )
{
/*
* The miscdevice layer puts our struct miscdevice into the
* filp - > private_data field . We use this to find our private
* data and then overwrite it with our own private structure .
*/
struct fpga_dev * priv = container_of ( filp - > private_data ,
struct fpga_dev , miscdev ) ;
unsigned int nr_pages ;
int ret ;
/* We only allow one process at a time */
ret = mutex_lock_interruptible ( & priv - > lock ) ;
if ( ret )
return ret ;
filp - > private_data = priv ;
kref_get ( & priv - > ref ) ;
/* Truncation: drop any existing data */
if ( filp - > f_flags & O_TRUNC )
priv - > bytes = 0 ;
/* Check if we have already allocated a buffer */
if ( priv - > vb_allocated )
return 0 ;
/* Allocate a buffer to hold enough data for the bitfile */
nr_pages = DIV_ROUND_UP ( priv - > fw_size , PAGE_SIZE ) ;
ret = videobuf_dma_init_kernel ( & priv - > vb , DMA_TO_DEVICE , nr_pages ) ;
if ( ret ) {
dev_err ( priv - > dev , " unable to allocate data buffer \n " ) ;
mutex_unlock ( & priv - > lock ) ;
kref_put ( & priv - > ref , fpga_dev_remove ) ;
return ret ;
}
priv - > vb_allocated = true ;
return 0 ;
}
static int fpga_release ( struct inode * inode , struct file * filp )
{
struct fpga_dev * priv = filp - > private_data ;
mutex_unlock ( & priv - > lock ) ;
kref_put ( & priv - > ref , fpga_dev_remove ) ;
return 0 ;
}
static ssize_t fpga_write ( struct file * filp , const char __user * buf ,
size_t count , loff_t * f_pos )
{
struct fpga_dev * priv = filp - > private_data ;
/* FPGA bitfiles have an exact size: disallow anything else */
if ( priv - > bytes > = priv - > fw_size )
return - ENOSPC ;
count = min_t ( size_t , priv - > fw_size - priv - > bytes , count ) ;
if ( copy_from_user ( priv - > vb . vaddr + priv - > bytes , buf , count ) )
return - EFAULT ;
priv - > bytes + = count ;
return count ;
}
static ssize_t fpga_read ( struct file * filp , char __user * buf , size_t count ,
loff_t * f_pos )
{
struct fpga_dev * priv = filp - > private_data ;
count = min_t ( size_t , priv - > bytes - * f_pos , count ) ;
if ( copy_to_user ( buf , priv - > vb . vaddr + * f_pos , count ) )
return - EFAULT ;
* f_pos + = count ;
return count ;
}
static loff_t fpga_llseek ( struct file * filp , loff_t offset , int origin )
{
struct fpga_dev * priv = filp - > private_data ;
loff_t newpos ;
/* only read-only opens are allowed to seek */
if ( ( filp - > f_flags & O_ACCMODE ) ! = O_RDONLY )
return - EINVAL ;
switch ( origin ) {
case SEEK_SET : /* seek relative to the beginning of the file */
newpos = offset ;
break ;
case SEEK_CUR : /* seek relative to current position in the file */
newpos = filp - > f_pos + offset ;
break ;
case SEEK_END : /* seek relative to the end of the file */
newpos = priv - > fw_size - offset ;
break ;
default :
return - EINVAL ;
}
/* check for sanity */
if ( newpos > priv - > fw_size )
return - EINVAL ;
filp - > f_pos = newpos ;
return newpos ;
}
static const struct file_operations fpga_fops = {
. open = fpga_open ,
. release = fpga_release ,
. write = fpga_write ,
. read = fpga_read ,
. llseek = fpga_llseek ,
} ;
/*
* Device Attributes
*/
static ssize_t pfail_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
u8 val ;
val = ioread8 ( priv - > regs + CTL_PWR_FAIL ) ;
return snprintf ( buf , PAGE_SIZE , " 0x%.2x \n " , val ) ;
}
static ssize_t pgood_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , fpga_power_good ( priv ) ) ;
}
static ssize_t penable_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , fpga_power_enabled ( priv ) ) ;
}
static ssize_t penable_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
unsigned long val ;
int ret ;
2013-06-04 13:15:16 +09:00
ret = kstrtoul ( buf , 0 , & val ) ;
if ( ret )
return ret ;
2011-02-11 13:34:30 +00:00
if ( val ) {
ret = fpga_enable_power_supplies ( priv ) ;
if ( ret )
return ret ;
} else {
fpga_do_stop ( priv ) ;
fpga_disable_power_supplies ( priv ) ;
}
return count ;
}
static ssize_t program_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %d \n " , fpga_running ( priv ) ) ;
}
static ssize_t program_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fpga_dev * priv = dev_get_drvdata ( dev ) ;
unsigned long val ;
int ret ;
2013-06-04 13:15:16 +09:00
ret = kstrtoul ( buf , 0 , & val ) ;
if ( ret )
return ret ;
2011-02-11 13:34:30 +00:00
/* We can't have an image writer and be programming simultaneously */
if ( mutex_lock_interruptible ( & priv - > lock ) )
return - ERESTARTSYS ;
/* Program or Reset the FPGA's */
ret = val ? fpga_do_program ( priv ) : fpga_do_stop ( priv ) ;
if ( ret )
goto out_unlock ;
/* Success */
ret = count ;
out_unlock :
mutex_unlock ( & priv - > lock ) ;
return ret ;
}
static DEVICE_ATTR ( power_fail , S_IRUGO , pfail_show , NULL ) ;
static DEVICE_ATTR ( power_good , S_IRUGO , pgood_show , NULL ) ;
static DEVICE_ATTR ( power_enable , S_IRUGO | S_IWUSR ,
penable_show , penable_store ) ;
static DEVICE_ATTR ( program , S_IRUGO | S_IWUSR ,
program_show , program_store ) ;
static struct attribute * fpga_attributes [ ] = {
& dev_attr_power_fail . attr ,
& dev_attr_power_good . attr ,
& dev_attr_power_enable . attr ,
& dev_attr_program . attr ,
NULL ,
} ;
static const struct attribute_group fpga_attr_group = {
. attrs = fpga_attributes ,
} ;
/*
* OpenFirmware Device Subsystem
*/
# define SYS_REG_VERSION 0x00
# define SYS_REG_GEOGRAPHIC 0x10
static bool dma_filter ( struct dma_chan * chan , void * data )
{
/*
* DMA Channel # 0 is the only acceptable device
*
* This probably won ' t survive an unload / load cycle of the Freescale
* DMAEngine driver , but that won ' t be a problem
*/
return chan - > chan_id = = 0 & & chan - > device - > dev_id = = 0 ;
}
static int fpga_of_remove ( struct platform_device * op )
{
2013-05-23 19:35:23 +09:00
struct fpga_dev * priv = platform_get_drvdata ( op ) ;
2011-02-11 13:34:30 +00:00
struct device * this_device = priv - > miscdev . this_device ;
sysfs_remove_group ( & this_device - > kobj , & fpga_attr_group ) ;
misc_deregister ( & priv - > miscdev ) ;
free_irq ( priv - > irq , priv ) ;
irq_dispose_mapping ( priv - > irq ) ;
/* make sure the power supplies are off */
fpga_disable_power_supplies ( priv ) ;
/* unmap registers */
iounmap ( priv - > immr ) ;
iounmap ( priv - > regs ) ;
dma_release_channel ( priv - > chan ) ;
/* drop our reference to the private data structure */
kref_put ( & priv - > ref , fpga_dev_remove ) ;
return 0 ;
}
/* CTL-CPLD Version Register */
# define CTL_CPLD_VERSION 0x2000
2011-11-08 19:57:05 -05:00
static int fpga_of_probe ( struct platform_device * op )
2011-02-11 13:34:30 +00:00
{
struct device_node * of_node = op - > dev . of_node ;
struct device * this_device ;
struct fpga_dev * priv ;
dma_cap_mask_t mask ;
u32 ver ;
int ret ;
/* Allocate private data */
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv ) {
dev_err ( & op - > dev , " Unable to allocate private data \n " ) ;
ret = - ENOMEM ;
goto out_return ;
}
/* Setup the miscdevice */
priv - > miscdev . minor = MISC_DYNAMIC_MINOR ;
priv - > miscdev . name = drv_name ;
priv - > miscdev . fops = & fpga_fops ;
kref_init ( & priv - > ref ) ;
2013-05-23 19:35:23 +09:00
platform_set_drvdata ( op , priv ) ;
2011-02-11 13:34:30 +00:00
priv - > dev = & op - > dev ;
mutex_init ( & priv - > lock ) ;
init_completion ( & priv - > completion ) ;
videobuf_dma_init ( & priv - > vb ) ;
dev_set_drvdata ( priv - > dev , priv ) ;
dma_cap_zero ( mask ) ;
dma_cap_set ( DMA_MEMCPY , mask ) ;
dma_cap_set ( DMA_SLAVE , mask ) ;
dma_cap_set ( DMA_SG , mask ) ;
/* Get control of DMA channel #0 */
priv - > chan = dma_request_channel ( mask , dma_filter , NULL ) ;
if ( ! priv - > chan ) {
dev_err ( & op - > dev , " Unable to acquire DMA channel #0 \n " ) ;
ret = - ENODEV ;
goto out_free_priv ;
}
/* Remap the registers for use */
priv - > regs = of_iomap ( of_node , 0 ) ;
if ( ! priv - > regs ) {
dev_err ( & op - > dev , " Unable to ioremap registers \n " ) ;
ret = - ENOMEM ;
goto out_dma_release_channel ;
}
/* Remap the IMMR for use */
priv - > immr = ioremap ( get_immrbase ( ) , 0x100000 ) ;
if ( ! priv - > immr ) {
dev_err ( & op - > dev , " Unable to ioremap IMMR \n " ) ;
ret = - ENOMEM ;
goto out_unmap_regs ;
}
/*
* Check that external DMA is configured
*
* U - Boot does this for us , but we should check it and bail out if
* there is a problem . Failing to have this register setup correctly
* will cause the DMA controller to transfer a single cacheline
* worth of data , then wedge itself .
*/
if ( ( ioread32be ( priv - > immr + 0x114 ) & 0xE00 ) ! = 0xE00 ) {
dev_err ( & op - > dev , " External DMA control not configured \n " ) ;
ret = - ENODEV ;
goto out_unmap_immr ;
}
/*
* Check the CTL - CPLD version
*
* This driver uses the CTL - CPLD DATA - FPGA power sequencer , and we
* don ' t want to run on any version of the CTL - CPLD that does not use
* a compatible register layout .
*
* v2 : changed register layout , added power sequencer
* v3 : added glitch filter on the i2c overcurrent / overtemp outputs
*/
ver = ioread8 ( priv - > regs + CTL_CPLD_VERSION ) ;
if ( ver ! = 0x02 & & ver ! = 0x03 ) {
dev_err ( & op - > dev , " CTL-CPLD is not version 0x02 or 0x03! \n " ) ;
ret = - ENODEV ;
goto out_unmap_immr ;
}
/* Set the exact size that the firmware image should be */
ver = ioread32be ( priv - > regs + SYS_REG_VERSION ) ;
priv - > fw_size = ( ver & ( 1 < < 18 ) ) ? FW_SIZE_EP2S130 : FW_SIZE_EP2S90 ;
/* Find the correct IRQ number */
priv - > irq = irq_of_parse_and_map ( of_node , 0 ) ;
if ( priv - > irq = = NO_IRQ ) {
dev_err ( & op - > dev , " Unable to find IRQ line \n " ) ;
ret = - ENODEV ;
goto out_unmap_immr ;
}
/* Request the IRQ */
ret = request_irq ( priv - > irq , fpga_irq , IRQF_SHARED , drv_name , priv ) ;
if ( ret ) {
dev_err ( & op - > dev , " Unable to request IRQ %d \n " , priv - > irq ) ;
ret = - ENODEV ;
goto out_irq_dispose_mapping ;
}
/* Reset and stop the FPGA's, just in case */
fpga_do_stop ( priv ) ;
/* Register the miscdevice */
ret = misc_register ( & priv - > miscdev ) ;
if ( ret ) {
dev_err ( & op - > dev , " Unable to register miscdevice \n " ) ;
goto out_free_irq ;
}
/* Create the sysfs files */
this_device = priv - > miscdev . this_device ;
dev_set_drvdata ( this_device , priv ) ;
ret = sysfs_create_group ( & this_device - > kobj , & fpga_attr_group ) ;
if ( ret ) {
dev_err ( & op - > dev , " Unable to create sysfs files \n " ) ;
goto out_misc_deregister ;
}
dev_info ( priv - > dev , " CARMA FPGA Programmer: %s rev%s with %s FPGAs \n " ,
( ver & ( 1 < < 17 ) ) ? " Correlator " : " Digitizer " ,
( ver & ( 1 < < 16 ) ) ? " B " : " A " ,
( ver & ( 1 < < 18 ) ) ? " EP2S130 " : " EP2S90 " ) ;
return 0 ;
out_misc_deregister :
misc_deregister ( & priv - > miscdev ) ;
out_free_irq :
free_irq ( priv - > irq , priv ) ;
out_irq_dispose_mapping :
irq_dispose_mapping ( priv - > irq ) ;
out_unmap_immr :
iounmap ( priv - > immr ) ;
out_unmap_regs :
iounmap ( priv - > regs ) ;
out_dma_release_channel :
dma_release_channel ( priv - > chan ) ;
out_free_priv :
kref_put ( & priv - > ref , fpga_dev_remove ) ;
out_return :
return ret ;
}
static struct of_device_id fpga_of_match [ ] = {
{ . compatible = " carma,fpga-programmer " , } ,
{ } ,
} ;
2011-11-08 19:57:05 -05:00
static struct platform_driver fpga_of_driver = {
2011-02-11 13:34:30 +00:00
. probe = fpga_of_probe ,
. remove = fpga_of_remove ,
. driver = {
. name = drv_name ,
. of_match_table = fpga_of_match ,
. owner = THIS_MODULE ,
} ,
} ;
/*
* Module Init / Exit
*/
static int __init fpga_init ( void )
{
led_trigger_register_simple ( " fpga " , & ledtrig_fpga ) ;
2011-11-08 19:57:05 -05:00
return platform_driver_register ( & fpga_of_driver ) ;
2011-02-11 13:34:30 +00:00
}
static void __exit fpga_exit ( void )
{
2011-11-08 19:57:05 -05:00
platform_driver_unregister ( & fpga_of_driver ) ;
2011-02-11 13:34:30 +00:00
led_trigger_unregister_simple ( ledtrig_fpga ) ;
}
MODULE_AUTHOR ( " Ira W. Snyder <iws@ovro.caltech.edu> " ) ;
MODULE_DESCRIPTION ( " CARMA Board DATA-FPGA Programmer " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( fpga_init ) ;
module_exit ( fpga_exit ) ;