2014-02-26 20:29:05 +04:00
# include <linux/types.h>
# include <linux/ioport.h>
# include <linux/slab.h>
# include <linux/export.h>
# include <linux/io.h>
# include <linux/mcb.h>
# include "mcb-internal.h"
struct mcb_parse_priv {
phys_addr_t mapbase ;
void __iomem * base ;
} ;
# define for_each_chameleon_cell(dtype, p) \
for ( ( dtype ) = get_next_dtype ( ( p ) ) ; \
( dtype ) ! = CHAMELEON_DTYPE_END ; \
( dtype ) = get_next_dtype ( ( p ) ) )
static inline uint32_t get_next_dtype ( void __iomem * p )
{
uint32_t dtype ;
dtype = readl ( p ) ;
return dtype > > 28 ;
}
static int chameleon_parse_bdd ( struct mcb_bus * bus ,
phys_addr_t mapbase ,
void __iomem * base )
{
return 0 ;
}
static int chameleon_parse_gdd ( struct mcb_bus * bus ,
phys_addr_t mapbase ,
void __iomem * base )
{
struct chameleon_gdd __iomem * gdd =
( struct chameleon_gdd __iomem * ) base ;
struct mcb_device * mdev ;
u32 offset ;
u32 size ;
int ret ;
__le32 reg1 ;
__le32 reg2 ;
mdev = mcb_alloc_dev ( bus ) ;
if ( ! mdev )
return - ENOMEM ;
reg1 = readl ( & gdd - > reg1 ) ;
reg2 = readl ( & gdd - > reg2 ) ;
offset = readl ( & gdd - > offset ) ;
size = readl ( & gdd - > size ) ;
mdev - > id = GDD_DEV ( reg1 ) ;
mdev - > rev = GDD_REV ( reg1 ) ;
mdev - > var = GDD_VAR ( reg1 ) ;
mdev - > bar = GDD_BAR ( reg1 ) ;
mdev - > group = GDD_GRP ( reg2 ) ;
mdev - > inst = GDD_INS ( reg2 ) ;
pr_debug ( " Found a 16z%03d \n " , mdev - > id ) ;
mdev - > irq . start = GDD_IRQ ( reg1 ) ;
mdev - > irq . end = GDD_IRQ ( reg1 ) ;
mdev - > irq . flags = IORESOURCE_IRQ ;
mdev - > mem . start = mapbase + offset ;
mdev - > mem . end = mdev - > mem . start + size - 1 ;
mdev - > mem . flags = IORESOURCE_MEM ;
mdev - > is_added = false ;
ret = mcb_device_register ( bus , mdev ) ;
if ( ret < 0 )
goto err ;
return 0 ;
err :
mcb_free_dev ( mdev ) ;
return ret ;
}
int chameleon_parse_cells ( struct mcb_bus * bus , phys_addr_t mapbase ,
void __iomem * base )
{
char __iomem * p = base ;
struct chameleon_fpga_header * header ;
uint32_t dtype ;
int num_cells = 0 ;
int ret = 0 ;
u32 hsize ;
hsize = sizeof ( struct chameleon_fpga_header ) ;
header = kzalloc ( hsize , GFP_KERNEL ) ;
if ( ! header )
return - ENOMEM ;
/* Extract header information */
memcpy_fromio ( header , p , hsize ) ;
/* We only support chameleon v2 at the moment */
header - > magic = le16_to_cpu ( header - > magic ) ;
if ( header - > magic ! = CHAMELEONV2_MAGIC ) {
pr_err ( " Unsupported chameleon version 0x%x \n " ,
header - > magic ) ;
kfree ( header ) ;
return - ENODEV ;
}
p + = hsize ;
pr_debug ( " header->revision = %d \n " , header - > revision ) ;
pr_debug ( " header->model = 0x%x ('%c') \n " , header - > model ,
header - > model ) ;
pr_debug ( " header->minor = %d \n " , header - > minor ) ;
pr_debug ( " header->bus_type = 0x%x \n " , header - > bus_type ) ;
pr_debug ( " header->magic = 0x%x \n " , header - > magic ) ;
pr_debug ( " header->filename = \" %.*s \" \n " , CHAMELEON_FILENAME_LEN ,
header - > filename ) ;
for_each_chameleon_cell ( dtype , p ) {
switch ( dtype ) {
case CHAMELEON_DTYPE_GENERAL :
ret = chameleon_parse_gdd ( bus , mapbase , p ) ;
if ( ret < 0 )
goto out ;
p + = sizeof ( struct chameleon_gdd ) ;
break ;
case CHAMELEON_DTYPE_BRIDGE :
chameleon_parse_bdd ( bus , mapbase , p ) ;
p + = sizeof ( struct chameleon_bdd ) ;
break ;
case CHAMELEON_DTYPE_END :
break ;
default :
pr_err ( " Invalid chameleon descriptor type 0x%x \n " ,
dtype ) ;
2014-04-11 20:40:05 +04:00
kfree ( header ) ;
2014-02-26 20:29:05 +04:00
return - EINVAL ;
}
num_cells + + ;
}
if ( num_cells = = 0 )
num_cells = - EINVAL ;
kfree ( header ) ;
return num_cells ;
out :
kfree ( header ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( chameleon_parse_cells ) ;