2018-05-17 02:49:58 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-10-07 18:36:29 +03:00
/*
* FPGA Manager Driver for Altera SOCFPGA
*
* Copyright ( C ) 2013 - 2015 Altera Corporation
*/
# include <linux/completion.h>
# include <linux/delay.h>
# include <linux/fpga/fpga-mgr.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/of_irq.h>
# include <linux/pm.h>
/* Register offsets */
# define SOCFPGA_FPGMGR_STAT_OFST 0x0
# define SOCFPGA_FPGMGR_CTL_OFST 0x4
# define SOCFPGA_FPGMGR_DCLKCNT_OFST 0x8
# define SOCFPGA_FPGMGR_DCLKSTAT_OFST 0xc
# define SOCFPGA_FPGMGR_GPIO_INTEN_OFST 0x830
# define SOCFPGA_FPGMGR_GPIO_INTMSK_OFST 0x834
# define SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST 0x838
# define SOCFPGA_FPGMGR_GPIO_INT_POL_OFST 0x83c
# define SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST 0x840
# define SOCFPGA_FPGMGR_GPIO_RAW_INTSTAT_OFST 0x844
# define SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST 0x84c
# define SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST 0x850
/* Register bit defines */
/* SOCFPGA_FPGMGR_STAT register mode field values */
# define SOCFPGA_FPGMGR_STAT_POWER_UP 0x0 /*ramping*/
# define SOCFPGA_FPGMGR_STAT_RESET 0x1
# define SOCFPGA_FPGMGR_STAT_CFG 0x2
# define SOCFPGA_FPGMGR_STAT_INIT 0x3
# define SOCFPGA_FPGMGR_STAT_USER_MODE 0x4
# define SOCFPGA_FPGMGR_STAT_UNKNOWN 0x5
# define SOCFPGA_FPGMGR_STAT_STATE_MASK 0x7
/* This is a flag value that doesn't really happen in this register field */
# define SOCFPGA_FPGMGR_STAT_POWER_OFF 0x0
# define MSEL_PP16_FAST_NOAES_NODC 0x0
# define MSEL_PP16_FAST_AES_NODC 0x1
# define MSEL_PP16_FAST_AESOPT_DC 0x2
# define MSEL_PP16_SLOW_NOAES_NODC 0x4
# define MSEL_PP16_SLOW_AES_NODC 0x5
# define MSEL_PP16_SLOW_AESOPT_DC 0x6
# define MSEL_PP32_FAST_NOAES_NODC 0x8
# define MSEL_PP32_FAST_AES_NODC 0x9
# define MSEL_PP32_FAST_AESOPT_DC 0xa
# define MSEL_PP32_SLOW_NOAES_NODC 0xc
# define MSEL_PP32_SLOW_AES_NODC 0xd
# define MSEL_PP32_SLOW_AESOPT_DC 0xe
# define SOCFPGA_FPGMGR_STAT_MSEL_MASK 0x000000f8
# define SOCFPGA_FPGMGR_STAT_MSEL_SHIFT 3
/* SOCFPGA_FPGMGR_CTL register */
# define SOCFPGA_FPGMGR_CTL_EN 0x00000001
# define SOCFPGA_FPGMGR_CTL_NCE 0x00000002
# define SOCFPGA_FPGMGR_CTL_NCFGPULL 0x00000004
# define CDRATIO_X1 0x00000000
# define CDRATIO_X2 0x00000040
# define CDRATIO_X4 0x00000080
# define CDRATIO_X8 0x000000c0
# define SOCFPGA_FPGMGR_CTL_CDRATIO_MASK 0x000000c0
# define SOCFPGA_FPGMGR_CTL_AXICFGEN 0x00000100
# define CFGWDTH_16 0x00000000
# define CFGWDTH_32 0x00000200
# define SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK 0x00000200
/* SOCFPGA_FPGMGR_DCLKSTAT register */
# define SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE 0x1
/* SOCFPGA_FPGMGR_GPIO_* registers share the same bit positions */
# define SOCFPGA_FPGMGR_MON_NSTATUS 0x0001
# define SOCFPGA_FPGMGR_MON_CONF_DONE 0x0002
# define SOCFPGA_FPGMGR_MON_INIT_DONE 0x0004
# define SOCFPGA_FPGMGR_MON_CRC_ERROR 0x0008
# define SOCFPGA_FPGMGR_MON_CVP_CONF_DONE 0x0010
# define SOCFPGA_FPGMGR_MON_PR_READY 0x0020
# define SOCFPGA_FPGMGR_MON_PR_ERROR 0x0040
# define SOCFPGA_FPGMGR_MON_PR_DONE 0x0080
# define SOCFPGA_FPGMGR_MON_NCONFIG_PIN 0x0100
# define SOCFPGA_FPGMGR_MON_NSTATUS_PIN 0x0200
# define SOCFPGA_FPGMGR_MON_CONF_DONE_PIN 0x0400
# define SOCFPGA_FPGMGR_MON_FPGA_POWER_ON 0x0800
# define SOCFPGA_FPGMGR_MON_STATUS_MASK 0x0fff
# define SOCFPGA_FPGMGR_NUM_SUPPLIES 3
# define SOCFPGA_RESUME_TIMEOUT 3
/* In power-up order. Reverse for power-down. */
static const char * supply_names [ SOCFPGA_FPGMGR_NUM_SUPPLIES ] __maybe_unused = {
" FPGA-1.5V " ,
" FPGA-1.1V " ,
" FPGA-2.5V " ,
} ;
struct socfpga_fpga_priv {
void __iomem * fpga_base_addr ;
void __iomem * fpga_data_addr ;
struct completion status_complete ;
int irq ;
} ;
struct cfgmgr_mode {
/* Values to set in the CTRL register */
u32 ctrl ;
/* flag that this table entry is a valid mode */
bool valid ;
} ;
/* For SOCFPGA_FPGMGR_STAT_MSEL field */
static struct cfgmgr_mode cfgmgr_modes [ ] = {
[ MSEL_PP16_FAST_NOAES_NODC ] = { CFGWDTH_16 | CDRATIO_X1 , 1 } ,
[ MSEL_PP16_FAST_AES_NODC ] = { CFGWDTH_16 | CDRATIO_X2 , 1 } ,
[ MSEL_PP16_FAST_AESOPT_DC ] = { CFGWDTH_16 | CDRATIO_X4 , 1 } ,
[ MSEL_PP16_SLOW_NOAES_NODC ] = { CFGWDTH_16 | CDRATIO_X1 , 1 } ,
[ MSEL_PP16_SLOW_AES_NODC ] = { CFGWDTH_16 | CDRATIO_X2 , 1 } ,
[ MSEL_PP16_SLOW_AESOPT_DC ] = { CFGWDTH_16 | CDRATIO_X4 , 1 } ,
[ MSEL_PP32_FAST_NOAES_NODC ] = { CFGWDTH_32 | CDRATIO_X1 , 1 } ,
[ MSEL_PP32_FAST_AES_NODC ] = { CFGWDTH_32 | CDRATIO_X4 , 1 } ,
[ MSEL_PP32_FAST_AESOPT_DC ] = { CFGWDTH_32 | CDRATIO_X8 , 1 } ,
[ MSEL_PP32_SLOW_NOAES_NODC ] = { CFGWDTH_32 | CDRATIO_X1 , 1 } ,
[ MSEL_PP32_SLOW_AES_NODC ] = { CFGWDTH_32 | CDRATIO_X4 , 1 } ,
[ MSEL_PP32_SLOW_AESOPT_DC ] = { CFGWDTH_32 | CDRATIO_X8 , 1 } ,
} ;
static u32 socfpga_fpga_readl ( struct socfpga_fpga_priv * priv , u32 reg_offset )
{
return readl ( priv - > fpga_base_addr + reg_offset ) ;
}
static void socfpga_fpga_writel ( struct socfpga_fpga_priv * priv , u32 reg_offset ,
u32 value )
{
writel ( value , priv - > fpga_base_addr + reg_offset ) ;
}
static u32 socfpga_fpga_raw_readl ( struct socfpga_fpga_priv * priv ,
u32 reg_offset )
{
return __raw_readl ( priv - > fpga_base_addr + reg_offset ) ;
}
static void socfpga_fpga_raw_writel ( struct socfpga_fpga_priv * priv ,
u32 reg_offset , u32 value )
{
__raw_writel ( value , priv - > fpga_base_addr + reg_offset ) ;
}
static void socfpga_fpga_data_writel ( struct socfpga_fpga_priv * priv , u32 value )
{
writel ( value , priv - > fpga_data_addr ) ;
}
static inline void socfpga_fpga_set_bitsl ( struct socfpga_fpga_priv * priv ,
u32 offset , u32 bits )
{
u32 val ;
val = socfpga_fpga_readl ( priv , offset ) ;
val | = bits ;
socfpga_fpga_writel ( priv , offset , val ) ;
}
static inline void socfpga_fpga_clr_bitsl ( struct socfpga_fpga_priv * priv ,
u32 offset , u32 bits )
{
u32 val ;
val = socfpga_fpga_readl ( priv , offset ) ;
val & = ~ bits ;
socfpga_fpga_writel ( priv , offset , val ) ;
}
static u32 socfpga_fpga_mon_status_get ( struct socfpga_fpga_priv * priv )
{
return socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST ) &
SOCFPGA_FPGMGR_MON_STATUS_MASK ;
}
static u32 socfpga_fpga_state_get ( struct socfpga_fpga_priv * priv )
{
u32 status = socfpga_fpga_mon_status_get ( priv ) ;
if ( ( status & SOCFPGA_FPGMGR_MON_FPGA_POWER_ON ) = = 0 )
return SOCFPGA_FPGMGR_STAT_POWER_OFF ;
return socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_STAT_OFST ) &
SOCFPGA_FPGMGR_STAT_STATE_MASK ;
}
static void socfpga_fpga_clear_done_status ( struct socfpga_fpga_priv * priv )
{
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_DCLKSTAT_OFST ,
SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE ) ;
}
/*
* Set the DCLKCNT , wait for DCLKSTAT to report the count completed , and clear
* the complete status .
*/
static int socfpga_fpga_dclk_set_and_wait_clear ( struct socfpga_fpga_priv * priv ,
u32 count )
{
int timeout = 2 ;
u32 done ;
/* Clear any existing DONE status. */
if ( socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_DCLKSTAT_OFST ) )
socfpga_fpga_clear_done_status ( priv ) ;
/* Issue the DCLK count. */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_DCLKCNT_OFST , count ) ;
/* Poll DCLKSTAT to see if it completed in the timeout period. */
do {
done = socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_DCLKSTAT_OFST ) ;
if ( done = = SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE ) {
socfpga_fpga_clear_done_status ( priv ) ;
return 0 ;
}
udelay ( 1 ) ;
} while ( timeout - - ) ;
return - ETIMEDOUT ;
}
static int socfpga_fpga_wait_for_state ( struct socfpga_fpga_priv * priv ,
u32 state )
{
int timeout = 2 ;
/*
* HW doesn ' t support an interrupt for changes in state , so poll to see
* if it matches the requested state within the timeout period .
*/
do {
if ( ( socfpga_fpga_state_get ( priv ) & state ) ! = 0 )
return 0 ;
msleep ( 20 ) ;
} while ( timeout - - ) ;
return - ETIMEDOUT ;
}
static void socfpga_fpga_enable_irqs ( struct socfpga_fpga_priv * priv , u32 irqs )
{
/* set irqs to level sensitive */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST , 0 ) ;
/* set interrupt polarity */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_INT_POL_OFST , irqs ) ;
/* clear irqs */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST , irqs ) ;
/* unmask interrupts */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_INTMSK_OFST , 0 ) ;
/* enable interrupts */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_INTEN_OFST , irqs ) ;
}
static void socfpga_fpga_disable_irqs ( struct socfpga_fpga_priv * priv )
{
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_INTEN_OFST , 0 ) ;
}
static irqreturn_t socfpga_fpga_isr ( int irq , void * dev_id )
{
struct socfpga_fpga_priv * priv = dev_id ;
u32 irqs , st ;
bool conf_done , nstatus ;
/* clear irqs */
irqs = socfpga_fpga_raw_readl ( priv , SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST ) ;
socfpga_fpga_raw_writel ( priv , SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST , irqs ) ;
st = socfpga_fpga_raw_readl ( priv , SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST ) ;
conf_done = ( st & SOCFPGA_FPGMGR_MON_CONF_DONE ) ! = 0 ;
nstatus = ( st & SOCFPGA_FPGMGR_MON_NSTATUS ) ! = 0 ;
/* success */
if ( conf_done & & nstatus ) {
/* disable irqs */
socfpga_fpga_raw_writel ( priv ,
SOCFPGA_FPGMGR_GPIO_INTEN_OFST , 0 ) ;
complete ( & priv - > status_complete ) ;
}
return IRQ_HANDLED ;
}
static int socfpga_fpga_wait_for_config_done ( struct socfpga_fpga_priv * priv )
{
int timeout , ret = 0 ;
socfpga_fpga_disable_irqs ( priv ) ;
init_completion ( & priv - > status_complete ) ;
socfpga_fpga_enable_irqs ( priv , SOCFPGA_FPGMGR_MON_CONF_DONE ) ;
timeout = wait_for_completion_interruptible_timeout (
& priv - > status_complete ,
msecs_to_jiffies ( 10 ) ) ;
if ( timeout = = 0 )
ret = - ETIMEDOUT ;
socfpga_fpga_disable_irqs ( priv ) ;
return ret ;
}
static int socfpga_fpga_cfg_mode_get ( struct socfpga_fpga_priv * priv )
{
u32 msel ;
msel = socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_STAT_OFST ) ;
msel & = SOCFPGA_FPGMGR_STAT_MSEL_MASK ;
msel > > = SOCFPGA_FPGMGR_STAT_MSEL_SHIFT ;
/* Check that this MSEL setting is supported */
if ( ( msel > = ARRAY_SIZE ( cfgmgr_modes ) ) | | ! cfgmgr_modes [ msel ] . valid )
return - EINVAL ;
return msel ;
}
static int socfpga_fpga_cfg_mode_set ( struct socfpga_fpga_priv * priv )
{
u32 ctrl_reg ;
int mode ;
/* get value from MSEL pins */
mode = socfpga_fpga_cfg_mode_get ( priv ) ;
if ( mode < 0 )
return mode ;
/* Adjust CTRL for the CDRATIO */
ctrl_reg = socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_CTL_OFST ) ;
ctrl_reg & = ~ SOCFPGA_FPGMGR_CTL_CDRATIO_MASK ;
ctrl_reg & = ~ SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK ;
ctrl_reg | = cfgmgr_modes [ mode ] . ctrl ;
/* Set NCE to 0. */
ctrl_reg & = ~ SOCFPGA_FPGMGR_CTL_NCE ;
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_CTL_OFST , ctrl_reg ) ;
return 0 ;
}
static int socfpga_fpga_reset ( struct fpga_manager * mgr )
{
struct socfpga_fpga_priv * priv = mgr - > priv ;
u32 ctrl_reg , status ;
int ret ;
/*
* Step 1 :
* - Set CTRL . CFGWDTH , CTRL . CDRATIO to match cfg mode
* - Set CTRL . NCE to 0
*/
ret = socfpga_fpga_cfg_mode_set ( priv ) ;
if ( ret )
return ret ;
/* Step 2: Set CTRL.EN to 1 */
socfpga_fpga_set_bitsl ( priv , SOCFPGA_FPGMGR_CTL_OFST ,
SOCFPGA_FPGMGR_CTL_EN ) ;
/* Step 3: Set CTRL.NCONFIGPULL to 1 to put FPGA in reset */
ctrl_reg = socfpga_fpga_readl ( priv , SOCFPGA_FPGMGR_CTL_OFST ) ;
ctrl_reg | = SOCFPGA_FPGMGR_CTL_NCFGPULL ;
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_CTL_OFST , ctrl_reg ) ;
/* Step 4: Wait for STATUS.MODE to report FPGA is in reset phase */
status = socfpga_fpga_wait_for_state ( priv , SOCFPGA_FPGMGR_STAT_RESET ) ;
/* Step 5: Set CONTROL.NCONFIGPULL to 0 to release FPGA from reset */
ctrl_reg & = ~ SOCFPGA_FPGMGR_CTL_NCFGPULL ;
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_CTL_OFST , ctrl_reg ) ;
/* Timeout waiting for reset */
if ( status )
return - ETIMEDOUT ;
return 0 ;
}
/*
* Prepare the FPGA to receive the configuration data .
*/
2016-11-01 22:14:26 +03:00
static int socfpga_fpga_ops_configure_init ( struct fpga_manager * mgr ,
struct fpga_image_info * info ,
2015-10-07 18:36:29 +03:00
const char * buf , size_t count )
{
struct socfpga_fpga_priv * priv = mgr - > priv ;
int ret ;
2016-11-01 22:14:26 +03:00
if ( info - > flags & FPGA_MGR_PARTIAL_RECONFIG ) {
2015-10-07 18:36:29 +03:00
dev_err ( & mgr - > dev , " Partial reconfiguration not supported. \n " ) ;
return - EINVAL ;
}
/* Steps 1 - 5: Reset the FPGA */
ret = socfpga_fpga_reset ( mgr ) ;
if ( ret )
return ret ;
/* Step 6: Wait for FPGA to enter configuration phase */
if ( socfpga_fpga_wait_for_state ( priv , SOCFPGA_FPGMGR_STAT_CFG ) )
return - ETIMEDOUT ;
/* Step 7: Clear nSTATUS interrupt */
socfpga_fpga_writel ( priv , SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST ,
SOCFPGA_FPGMGR_MON_NSTATUS ) ;
/* Step 8: Set CTRL.AXICFGEN to 1 to enable transfer of config data */
socfpga_fpga_set_bitsl ( priv , SOCFPGA_FPGMGR_CTL_OFST ,
SOCFPGA_FPGMGR_CTL_AXICFGEN ) ;
return 0 ;
}
/*
* Step 9 : write data to the FPGA data register
*/
static int socfpga_fpga_ops_configure_write ( struct fpga_manager * mgr ,
const char * buf , size_t count )
{
struct socfpga_fpga_priv * priv = mgr - > priv ;
u32 * buffer_32 = ( u32 * ) buf ;
size_t i = 0 ;
if ( count < = 0 )
return - EINVAL ;
/* Write out the complete 32-bit chunks. */
while ( count > = sizeof ( u32 ) ) {
socfpga_fpga_data_writel ( priv , buffer_32 [ i + + ] ) ;
count - = sizeof ( u32 ) ;
}
/* Write out remaining non 32-bit chunks. */
switch ( count ) {
case 3 :
socfpga_fpga_data_writel ( priv , buffer_32 [ i + + ] & 0x00ffffff ) ;
break ;
case 2 :
socfpga_fpga_data_writel ( priv , buffer_32 [ i + + ] & 0x0000ffff ) ;
break ;
case 1 :
socfpga_fpga_data_writel ( priv , buffer_32 [ i + + ] & 0x000000ff ) ;
break ;
case 0 :
break ;
default :
/* This will never happen. */
return - EFAULT ;
}
return 0 ;
}
static int socfpga_fpga_ops_configure_complete ( struct fpga_manager * mgr ,
2016-11-01 22:14:26 +03:00
struct fpga_image_info * info )
2015-10-07 18:36:29 +03:00
{
struct socfpga_fpga_priv * priv = mgr - > priv ;
u32 status ;
/*
* Step 10 :
* - Observe CONF_DONE and nSTATUS ( active low )
* - if CONF_DONE = 1 and nSTATUS = 1 , configuration was successful
* - if CONF_DONE = 0 and nSTATUS = 0 , configuration failed
*/
status = socfpga_fpga_wait_for_config_done ( priv ) ;
if ( status )
return status ;
/* Step 11: Clear CTRL.AXICFGEN to disable transfer of config data */
socfpga_fpga_clr_bitsl ( priv , SOCFPGA_FPGMGR_CTL_OFST ,
SOCFPGA_FPGMGR_CTL_AXICFGEN ) ;
/*
* Step 12 :
* - Write 4 to DCLKCNT
* - Wait for STATUS . DCNTDONE = 1
* - Clear W1C bit in STATUS . DCNTDONE
*/
if ( socfpga_fpga_dclk_set_and_wait_clear ( priv , 4 ) )
return - ETIMEDOUT ;
/* Step 13: Wait for STATUS.MODE to report USER MODE */
if ( socfpga_fpga_wait_for_state ( priv , SOCFPGA_FPGMGR_STAT_USER_MODE ) )
return - ETIMEDOUT ;
/* Step 14: Set CTRL.EN to 0 */
socfpga_fpga_clr_bitsl ( priv , SOCFPGA_FPGMGR_CTL_OFST ,
SOCFPGA_FPGMGR_CTL_EN ) ;
return 0 ;
}
/* Translate state register values to FPGA framework state */
static const enum fpga_mgr_states socfpga_state_to_framework_state [ ] = {
[ SOCFPGA_FPGMGR_STAT_POWER_OFF ] = FPGA_MGR_STATE_POWER_OFF ,
[ SOCFPGA_FPGMGR_STAT_RESET ] = FPGA_MGR_STATE_RESET ,
[ SOCFPGA_FPGMGR_STAT_CFG ] = FPGA_MGR_STATE_WRITE_INIT ,
[ SOCFPGA_FPGMGR_STAT_INIT ] = FPGA_MGR_STATE_WRITE_INIT ,
[ SOCFPGA_FPGMGR_STAT_USER_MODE ] = FPGA_MGR_STATE_OPERATING ,
[ SOCFPGA_FPGMGR_STAT_UNKNOWN ] = FPGA_MGR_STATE_UNKNOWN ,
} ;
static enum fpga_mgr_states socfpga_fpga_ops_state ( struct fpga_manager * mgr )
{
struct socfpga_fpga_priv * priv = mgr - > priv ;
enum fpga_mgr_states ret ;
u32 state ;
state = socfpga_fpga_state_get ( priv ) ;
if ( state < ARRAY_SIZE ( socfpga_state_to_framework_state ) )
ret = socfpga_state_to_framework_state [ state ] ;
else
ret = FPGA_MGR_STATE_UNKNOWN ;
return ret ;
}
static const struct fpga_manager_ops socfpga_fpga_ops = {
. state = socfpga_fpga_ops_state ,
. write_init = socfpga_fpga_ops_configure_init ,
. write = socfpga_fpga_ops_configure_write ,
. write_complete = socfpga_fpga_ops_configure_complete ,
} ;
static int socfpga_fpga_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct socfpga_fpga_priv * priv ;
2018-05-17 02:49:55 +03:00
struct fpga_manager * mgr ;
2015-10-07 18:36:29 +03:00
struct resource * res ;
int ret ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
priv - > fpga_base_addr = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( priv - > fpga_base_addr ) )
return PTR_ERR ( priv - > fpga_base_addr ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
priv - > fpga_data_addr = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( priv - > fpga_data_addr ) )
return PTR_ERR ( priv - > fpga_data_addr ) ;
priv - > irq = platform_get_irq ( pdev , 0 ) ;
if ( priv - > irq < 0 )
return priv - > irq ;
ret = devm_request_irq ( dev , priv - > irq , socfpga_fpga_isr , 0 ,
dev_name ( dev ) , priv ) ;
2015-10-29 18:56:31 +03:00
if ( ret )
2015-10-07 18:36:29 +03:00
return ret ;
2021-11-19 04:55:51 +03:00
mgr = devm_fpga_mgr_register ( dev , " Altera SOCFPGA FPGA Manager " ,
& socfpga_fpga_ops , priv ) ;
return PTR_ERR_OR_ZERO ( mgr ) ;
2015-10-07 18:36:29 +03:00
}
# ifdef CONFIG_OF
static const struct of_device_id socfpga_fpga_of_match [ ] = {
{ . compatible = " altr,socfpga-fpga-mgr " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , socfpga_fpga_of_match ) ;
# endif
static struct platform_driver socfpga_fpga_driver = {
. probe = socfpga_fpga_probe ,
. driver = {
. name = " socfpga_fpga_manager " ,
. of_match_table = of_match_ptr ( socfpga_fpga_of_match ) ,
} ,
} ;
module_platform_driver ( socfpga_fpga_driver ) ;
MODULE_AUTHOR ( " Alan Tull <atull@opensource.altera.com> " ) ;
MODULE_DESCRIPTION ( " Altera SOCFPGA FPGA Manager " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;