svec: add Luis' code (fw loader and VME bus matching)

I made some minor fixes to correctly build the driver

1. compile under 3.2 (actually 2.6.26+) with no Module.symvers
dependencies on vmebridge. Module.symvers.vme has been consequently
added

2. usleep_range belongs to <linux/delay.h>, not <linux/timer.h>

3. include/ is now a sibling of kernel/
parent 7b13a8b2
/**
* \file libvmebus.h
* \brief VME Bus access user library interface
* \author Sbastien Dugu
* \date 04/02/2009
*
* This library gives userspace applications access to the VME bus
*
* Copyright (c) 2009 \em Sbastien \em Dugu
*
* \par License:
* 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.
*
*/
#ifndef _LIBVMEBUS_H_INCLUDE_
#define _LIBVMEBUS_H_INCLUDE_
#ifdef __cplusplus
extern "C" {
#endif
#include <vmebus.h>
/**
* \brief Swap a 16-bit halfword bytewise
* \param val The 16-bit halfword to swap
*
* \return The swapped value
*
*/
static inline unsigned short swapbe16(unsigned short val)
{
return (((val & 0xff00) >> 8) | ((val & 0xff) << 8));
}
/**
* \brief Swap a 32-bit word bytewise
* \param val The 32-bit word to swap
*
* \return The swapped value
*
*/
static inline unsigned int swapbe32(unsigned int val)
{
return (((val & 0xff000000) >> 24) | ((val & 0xff0000) >> 8) |
((val & 0xff00) << 8) | ((val & 0xff) << 24));
}
extern int vme_bus_error_check(struct vme_mapping *desc);
extern int vme_bus_error_check_clear(struct vme_mapping *desc, __u64 address);
/* VME address space mapping - CES library emulation */
extern unsigned long find_controller(unsigned long vmeaddr, unsigned long len,
unsigned long am, unsigned long offset,
unsigned long size,
struct pdparam_master *param);
extern unsigned long return_controller(struct vme_mapping *desc);
/* VME address space mapping */
extern void *vme_map(struct vme_mapping *, int);
extern int vme_unmap(struct vme_mapping *, int);
/* DMA access */
extern int vme_dma_read(struct vme_dma *);
extern int vme_dma_write(struct vme_dma *);
#ifdef __cplusplus
}
#endif
#endif /* _LIBVMEBUS_H_INCLUDE_ */
/**
* \file vmebus.h
* \brief PCI-VME public API
* \author Sebastien Dugue
* \date 04/02/2009
*
* This API presents in fact 2 APIs with some common definitions. One for
* drivers and one for user applications. User applications cannot use the
* driver specific parts enclosed in \#ifdef __KERNEL__ sections.
*
* Copyright (c) 2009 \em Sebastien \em Dugue
*
* \par License:
* 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.
*
*/
#ifndef _VME_H
#define _VME_H
#ifdef __KERNEL__
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#endif /* __KERNEL__ */
#include <linux/types.h>
/*
* VME window attributes
*/
/**
* \brief Read prefetch size
*/
enum vme_read_prefetch_size {
VME_PREFETCH_2 = 0,
VME_PREFETCH_4,
VME_PREFETCH_8,
VME_PREFETCH_16
};
/**
* \brief Data width
*/
enum vme_data_width {
VME_D8 = 8,
VME_D16 = 16,
VME_D32 = 32,
VME_D64 = 64
};
/**
* \brief 2eSST data transfer speed
*/
enum vme_2esst_mode {
VME_SST160 = 0,
VME_SST267,
VME_SST320
};
/**
* \brief Address modifiers
*/
enum vme_address_modifier {
VME_A64_MBLT = 0, /* 0x00 */
VME_A64_SCT, /* 0x01 */
VME_A64_BLT = 3, /* 0x03 */
VME_A64_LCK, /* 0x04 */
VME_A32_LCK, /* 0x05 */
VME_A32_USER_MBLT = 8, /* 0x08 */
VME_A32_USER_DATA_SCT, /* 0x09 */
VME_A32_USER_PRG_SCT, /* 0x0a */
VME_A32_USER_BLT, /* 0x0b */
VME_A32_SUP_MBLT, /* 0x0c */
VME_A32_SUP_DATA_SCT, /* 0x0d */
VME_A32_SUP_PRG_SCT, /* 0x0e */
VME_A32_SUP_BLT, /* 0x0f */
VME_2e6U = 0x20, /* 0x20 */
VME_2e3U, /* 0x21 */
VME_A16_USER = 0x29, /* 0x29 */
VME_A16_LCK = 0x2c, /* 0x2c */
VME_A16_SUP = 0x2d, /* 0x2d */
VME_CR_CSR = 0x2f, /* 0x2f */
VME_A40_SCT = 0x34, /* 0x34 */
VME_A40_LCK, /* 0x35 */
VME_A40_BLT = 0x37, /* 0x37 */
VME_A24_USER_MBLT, /* 0x38 */
VME_A24_USER_DATA_SCT, /* 0x39 */
VME_A24_USER_PRG_SCT, /* 0x3a */
VME_A24_USER_BLT, /* 0x3b */
VME_A24_SUP_MBLT, /* 0x3c */
VME_A24_SUP_DATA_SCT, /* 0x3d */
VME_A24_SUP_PRG_SCT, /* 0x3e */
VME_A24_SUP_BLT, /* 0x3f */
};
/**
* \brief PCI-VME mapping descriptor
* \param window_num Hardware window number
* \param kernel_va Kernel virtual address of the mapping for use by drivers
* \param user_va User virtual address of the mapping for use by applications
* \param fd User file descriptor for this mapping
* \param window_enabled State of the hardware window
* \param data_width VME data width
* \param am VME address modifier
* \param read_prefetch_enabled PCI read prefetch enabled state
* \param read_prefetch_size PCI read prefetch size (in cache lines)
* \param v2esst_mode VME 2eSST transfer speed
* \param bcast_select VME 2eSST broadcast select
* \param pci_addru PCI bus start address upper 32 bits
* \param pci_addrl PCI bus start address lower 32 bits
* \param sizeu Window size upper 32 bits
* \param sizel Window size lower 32 bits
* \param vme_addru VME bus start address upper 32 bits
* \param vme_addrl VME bus start address lower 32 bits
*
* This data structure is used for describing both a hardware window
* and a logical mapping on top of a hardware window. Therefore some of
* the fields are only relevant to one of those two entities.
*/
struct vme_mapping {
int window_num;
/* Reserved for kernel use */
void *kernel_va;
/* Reserved for userspace */
void *user_va;
int fd;
/* Window settings */
int window_enabled;
enum vme_data_width data_width;
enum vme_address_modifier am;
int read_prefetch_enabled;
enum vme_read_prefetch_size read_prefetch_size;
enum vme_2esst_mode v2esst_mode;
int bcast_select;
unsigned int pci_addru;
unsigned int pci_addrl;
unsigned int sizeu;
unsigned int sizel;
unsigned int vme_addru;
unsigned int vme_addrl;
};
/**
* \brief VME RMW descriptor
* \param vme_addru VME address for the RMW cycle upper 32 bits
* \param vme_addrl VME address for the RMW cycle lower 32 bits
* \param am VME address modifier
* \param enable_mask Bitmask of the bit
* \param compare_data
* \param swap_data
*
*/
struct vme_rmw {
unsigned int vme_addru;
unsigned int vme_addrl;
enum vme_address_modifier am;
unsigned int enable_mask;
unsigned int compare_data;
unsigned int swap_data;
};
/**
* \brief DMA endpoint attributes
* \param data_width VME data width (only used if endpoint is on the VME bus)
* \param am VME address modifier (ditto)
* \param v2esst_mode VME 2eSST transfer speed (ditto)
* \param bcast_select VME 2eSST broadcast select (ditto)
* \param addru Address upper 32 bits
* \param addrl Address lower 32 bits
*
* This data structure is used for describing the attributes of a DMA endpoint.
* All the field excepted for the address are only relevant for an endpoint
* on the VME bus.
*/
struct vme_dma_attr {
enum vme_data_width data_width;
enum vme_address_modifier am;
enum vme_2esst_mode v2esst_mode;
unsigned int bcast_select;
unsigned int addru;
unsigned int addrl;
};
/** \brief DMA block size on the PCI or VME bus */
enum vme_dma_block_size {
VME_DMA_BSIZE_32 = 0,
VME_DMA_BSIZE_64,
VME_DMA_BSIZE_128,
VME_DMA_BSIZE_256,
VME_DMA_BSIZE_512,
VME_DMA_BSIZE_1024,
VME_DMA_BSIZE_2048,
VME_DMA_BSIZE_4096
};
/** \brief DMA backoff time (us) on the PCI or VME bus */
enum vme_dma_backoff {
VME_DMA_BACKOFF_0 = 0,
VME_DMA_BACKOFF_1,
VME_DMA_BACKOFF_2,
VME_DMA_BACKOFF_4,
VME_DMA_BACKOFF_8,
VME_DMA_BACKOFF_16,
VME_DMA_BACKOFF_32,
VME_DMA_BACKOFF_64
};
/**
* \brief DMA control
* \param vme_block_size VME bus block size when the source is VME
* \param vme_backoff_time VME bus backoff time when the source is VME
* \param pci_block_size PCI/X bus block size when the source is PCI
* \param pci_backoff_time PCI bus backoff time when the source is PCI
*
*/
struct vme_dma_ctrl {
enum vme_dma_block_size vme_block_size;
enum vme_dma_backoff vme_backoff_time;
enum vme_dma_block_size pci_block_size;
enum vme_dma_backoff pci_backoff_time;
};
/** \brief DMA transfer direction */
enum vme_dma_dir {
VME_DMA_TO_DEVICE = 1,
VME_DMA_FROM_DEVICE
};
/**
* \brief VME DMA transfer descriptor
* \param status Transfer status
* \param length Transfer size in bytes
* \param novmeinc Must be set to 1 when accessing a FIFO like device on the VME
* \param dir Transfer direction
* \param src Transfer source attributes
* \param dst Transfer destination attributes
* \param opt Transfer control
*
*/
struct vme_dma {
unsigned int status;
unsigned int length;
unsigned int novmeinc;
enum vme_dma_dir dir;
struct vme_dma_attr src;
struct vme_dma_attr dst;
struct vme_dma_ctrl ctrl;
};
/**
* \brief VME Bus Error
* \param address Address of the bus error
* \param am Address Modifier of the bus error
*/
struct vme_bus_error {
__u64 address;
enum vme_address_modifier am;
};
/**
* \brief VME Bus Error descriptor
* \param error Address/AM of the bus error
* \param valid Valid Flag: 0 -> no error, 1 -> error
*/
struct vme_bus_error_desc {
struct vme_bus_error error;
int valid;
};
/*! @name VME single access swapping policy
*@{
*/
#define SINGLE_NO_SWAP 0
#define SINGLE_AUTO_SWAP 1
#define SINGLE_WORD_SWAP 2
#define SINGLE_BYTEWORD_SWAP 3
/*@}*/
/*! @name page qualifier
*
*@{
*/
#define VME_PG_SHARED 0x00
#define VME_PG_PRIVATE 0x02
/*@}*/
/**
* \brief VME mapping attributes
* \param iack VME IACK 0 -> IACK pages
* \param rdpref VME read prefetch option 0 -> Disable
* \param wrpost VME write posting option
* \param swap VME swap options
* \param sgmin page descriptor number returned by find_controller
* \param dum -- dum[0] page qualifier (shared/private), dum[1] XPC ADP-type
* dum[2] - reserved, _must_ be 0.
*
* This structure is used for the find_controller() and return_controller()
* LynxOS CES driver emulation.
*/
struct pdparam_master
{
unsigned long iack;
unsigned long rdpref;
unsigned long wrpost;
unsigned long swap;
unsigned long sgmin;
unsigned long dum[3];
};
/**
* \name Window management ioctl numbers
* \{
*/
/** Get a physical window attributes */
#define VME_IOCTL_GET_WINDOW_ATTR _IOWR('V', 0, struct vme_mapping)
/** Create a physical window */
#define VME_IOCTL_CREATE_WINDOW _IOW( 'V', 1, struct vme_mapping)
/** Destroy a physical window */
#define VME_IOCTL_DESTROY_WINDOW _IOW( 'V', 2, int)
/** Create a mapping over a physical window */
#define VME_IOCTL_FIND_MAPPING _IOWR('V', 3, struct vme_mapping)
/** Remove a mapping */
#define VME_IOCTL_RELEASE_MAPPING _IOW( 'V', 4, struct vme_mapping)
/** Get the create on find failed flag */
#define VME_IOCTL_GET_CREATE_ON_FIND_FAIL _IOR( 'V', 5, unsigned int)
/** Set the create on find failed flag */
#define VME_IOCTL_SET_CREATE_ON_FIND_FAIL _IOW( 'V', 6, unsigned int)
/** Get the destroy on remove flag */
#define VME_IOCTL_GET_DESTROY_ON_REMOVE _IOR( 'V', 7, unsigned int)
/** Set the destroy on remove flag */
#define VME_IOCTL_SET_DESTROY_ON_REMOVE _IOW( 'V', 8, unsigned int)
/** Get bus error status -- DEPRECATED */
#define VME_IOCTL_GET_BUS_ERROR _IOR( 'V', 9, unsigned int)
/** Check (and possibly clear) the bus error status */
#define VME_IOCTL_CHECK_CLEAR_BUS_ERROR _IOWR('V',10, struct vme_bus_error_desc)
/* \}*/
/**
* DMA ioctls
* \{
*/
/** Start a DMA transfer */
#define VME_IOCTL_START_DMA _IOWR('V', 10, struct vme_dma)
/* \}*/
#ifdef __KERNEL__
/*
* Those definitions are for drivers only and are not visible to userspace.
*/
struct vme_driver {
int (*match)(struct device *, unsigned int);
int (*probe)(struct device *, unsigned int);
int (*remove)(struct device *, unsigned int);
void (*shutdown)(struct device *, unsigned int);
int (*suspend)(struct device *, unsigned int, pm_message_t);
int (*resume)(struct device *, unsigned int);
struct device_driver driver;
struct device *devices;
};
#define to_vme_driver(x) container_of((x), struct vme_driver, driver)
typedef void (*vme_berr_handler_t)(struct vme_bus_error *);
/* API for new drivers */
extern int vme_register_driver(struct vme_driver *vme_driver, unsigned int ndev);
extern void vme_unregister_driver(struct vme_driver *vme_driver);
extern int vme_request_irq(unsigned int, int (*)(void *),
void *, const char *);
extern int vme_free_irq(unsigned int );
extern int vme_generate_interrupt(int, int, signed long);
extern struct vme_mapping* find_vme_mapping_from_addr(unsigned);
extern int vme_get_window_attr(struct vme_mapping *);
extern int vme_create_window(struct vme_mapping *);
extern int vme_destroy_window(int);
extern int vme_find_mapping(struct vme_mapping *, int);
extern int vme_release_mapping(struct vme_mapping *, int);
extern int vme_do_dma(struct vme_dma *);
extern int vme_do_dma_kernel(struct vme_dma *);
extern int vme_bus_error_check(int);
extern struct vme_berr_handler *
vme_register_berr_handler(struct vme_bus_error *, size_t, vme_berr_handler_t);
extern void vme_unregister_berr_handler(struct vme_berr_handler *);
/* API providing an emulation of the CES VME driver for legacy drivers */
extern unsigned long find_controller(unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned long, struct pdparam_master *);
extern unsigned long return_controller(unsigned, unsigned);
extern int vme_intset(int, int (*)(void *), void *, void *);
extern int vme_intclr(int, void *);
#endif /* __KERNEL__ */
#endif /* _VME_H */
EXTRA_CFLAGS += -I $(M)/../include
KBUILD_EXTRA_SYMBOLS += $(M)/Module.symvers.vme
obj-m := svec.o
svec-objs := svec_drv.o
CPU := L865
KVER := 3.2.33-rt50
KERN_DIR:= "/acc/sys/$(CPU)/usr/src/kernels/$(KVER)"
VME_DIR := "../../repo/vmebridge/driver"
#VME_OBJDIR := "../../repo/vmebridge/driver/$(CPU)/$(KVER)"
VME_OBJDIR := "../../repo/vmebridge/driver/"
ccflags-y += -DDEBUG
all: modules
$(MAKE) -C $(KERN_DIR) M=$(shell /bin/pwd)
.PHONY: all clean help
modules:
$(MAKE) -C $(KERN_DIR) M=$(shell pwd) CPU=$(CPU) KVER=$(KVER)
clean:
$(MAKE) -C $(KERN_DIR) M=`pwd` clean
help:
$(MAKE) -C $(KERN_DIR) M=`pwd` help
0x00000000 vme_bus_error_check /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_create_window /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_release_mapping /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_unregister_driver /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_do_dma_kernel /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 find_controller /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_register_berr_handler /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_request_irq /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_free_irq /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 find_vme_mapping_from_addr /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_find_mapping /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_bus_error_check_clear /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_register_driver /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_generate_interrupt /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_destroy_window /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_do_dma /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 return_controller /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_unregister_berr_handler /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_intset /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_intclr /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
0x00000000 vme_get_window_attr /acc/src/dsc/drivers/coht/vmebridge/driver/vmebus EXPORT_SYMBOL_GPL
#!/bin/sh
echo Installing svec WIP driver...
echo 8 > /proc/sys/kernel/printk
/sbin/insmod svec.ko lun=0 vmebase1=0x900000 vmebase2=0x6000 vector=0x86 level=2
MAJOR=`cat /proc/devices | awk '{if ($2 == "svec") printf $1}'`
echo Making nodes for ${MODULE} major device svec ${MAJOR}
if [ -z "$MAJOR" ]; then
echo "driver SVEC not installed !"
exit 2
fi
rm -f /dev/svec.*
#/bin/mknod -m 0666 /dev/svec.0 c ${MAJOR} 0
/*
* svec_priv.h
*
* private SVEC definitions
*/
#ifndef _SVEC_PRIV_H_
#define _SVEC_PRIV_H_
#define SVEC_MAX_DEVICES 32
#define SVEC_DEFAULT_IDX { [0 ... (SVEC_MAX_DEVICES-1)] = -1 }
#endif
/**
* svec_drv.c
* Driver for SVEC carrier.
*
* Released under GPL v2. (and only v2, not any later version)
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <vmebus.h>
#include "svec.h"
#include "xloader_regs.h"
#define DRIVER_NAME "svec"
#define PFX DRIVER_NAME ": "
#define BASE_LOADER 0x70000
#define US_TICKS 100
#define TIMEOUT 1000
struct svec_dev {
int lun;
unsigned long vmebase1;
unsigned long vmebase2;
int vector;
int level;
char *fw_name;
struct device *dev;
struct cdev cdev;
char driver[16];
char description[80];
};
/* Module parameters */
char *svec_fw_name = "fmc/svec-init.bin";
/*
module_param_named(fw_name, svec_fw_name, charp, 0444);
*/
static long vmebase1[SVEC_MAX_DEVICES];
static unsigned int vmebase1_num;
static long vmebase2[SVEC_MAX_DEVICES];
static unsigned int vmebase2_num;
static char *fw_name[SVEC_MAX_DEVICES];
static unsigned int fw_name_num;
static int vector[SVEC_MAX_DEVICES];
static unsigned int vector_num;
static int level[SVEC_MAX_DEVICES];
static unsigned int level_num;
static int lun[SVEC_MAX_DEVICES] = SVEC_DEFAULT_IDX;
static unsigned int lun_num;
module_param_array(vmebase1, long, &vmebase1_num, S_IRUGO);
MODULE_PARM_DESC(vmebase1, "VME Base Adress #1 of the SVEC card");
module_param_array(vmebase2, long, &vmebase2_num, S_IRUGO);
MODULE_PARM_DESC(vmebase2, "VME Base Adress #2 of the SVEC card");
module_param_array_named(fw_name, fw_name , charp, &fw_name_num, S_IRUGO);
MODULE_PARM_DESC(fw_name, "firmware file");
module_param_array(vector, int, &vector_num, S_IRUGO);
MODULE_PARM_DESC(vector, "IRQ vector");
module_param_array(level, int, &level_num, S_IRUGO);
MODULE_PARM_DESC(level, "IRQ level");
module_param_array(lun, int, &lun_num, S_IRUGO);
MODULE_PARM_DESC(lun, "Index value for SVEC card");
/* For device creation. Not really sure if it's necessary... */
static dev_t svec_devno;
static struct class *svec_class;
static const struct file_operations svec_fops = {
.owner = THIS_MODULE,
};
static inline unsigned short swapbe16(unsigned short val)
{
return (((val & 0xff00) >> 8) | ((val & 0xff) << 8));
}
static inline unsigned int swapbe32(unsigned int val)
{
return (((val & 0xff000000) >> 24) | ((val & 0xff0000) >> 8) |
((val & 0xff00) << 8) | ((val & 0xff) << 24));
}
int svec_load_fpga(struct svec_dev *svec, uint32_t *data, int size)
{
const uint32_t boot_seq[8] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe};
const char svec_idr[4] = "SVEC";
int i;
char idr[5];
struct vme_mapping mapping;
void *vaddr;
uint32_t idc;
uint32_t n;
uint32_t rval;
void *addr;
int timeout;
/* CS/CSR mapping*/
memset(&mapping, 0, sizeof(mapping));
mapping.am = VME_CR_CSR; /* 0x2f */
mapping.data_width = VME_D32;
mapping.vme_addru = 0;
mapping.vme_addrl = svec->vmebase1;
mapping.sizeu = 0;
mapping.sizel = 0x80000;
mapping.window_num = 0;
mapping.bcast_select = 0;
mapping.read_prefetch_enabled = 0;
printk(KERN_ERR PFX "Mapping CR/CSR space\n");
if (( rval = vme_find_mapping(&mapping, 1)) != 0) {
printk(KERN_ERR PFX "Failed to map CS_CSR (%d)\n", rval);
return -EINVAL;
}
vaddr = mapping.kernel_va;
printk(KERN_ERR PFX "Mapping successful at 0x%p\n", mapping.kernel_va);
/* Magic sequence: unlock bootloader mode, disable application FPGA */
for (i=0; i<8; i++)
iowrite32(swapbe32(boot_seq[i]), vaddr + BASE_LOADER + XLDR_REG_BTRIGR);
printk(KERN_ERR PFX "wrote unlock sequence at %x\n",
(unsigned int)vaddr + BASE_LOADER + XLDR_REG_BTRIGR);
/* check if we are really talking to a SVEC */
addr = vaddr + BASE_LOADER + XLDR_REG_IDR;
/*
printk(KERN_ERR PFX "reading at 0x%p:0x%p\n", vaddr, addr);
printk(KERN_ERR PFX "C: 0x%08x\n", ioread32be(vaddr + 0x1f));
printk(KERN_ERR PFX "R: 0x%08x\n", ioread32be(vaddr + 0x23));
*/
/* Looking for 'SVEC' string */
idc = swapbe32(ioread32(addr));
idr[0] = (idc >> 24) & 0xff;
idr[1] = (idc >> 16) & 0xff;
idr[2] = (idc >> 8) & 0xff;
idr[3] = (idc >> 0) & 0xff;
idr[4] = 0;
if(strncmp(idr, svec_idr, 4))
{
printk(KERN_ERR PFX "Invalid IDCode value %d [%s].\n", idc, &idr[0]);
return -EINVAL;
}
printk(KERN_INFO PFX "IDCode value %d [%s].\n", idc, &idr[0]);
if (data == NULL) {
printk(KERN_ERR PFX "firmware data is null\n");
return 0;
}
iowrite32(swapbe32(XLDR_CSR_SWRST), vaddr + BASE_LOADER + XLDR_REG_CSR);
iowrite32(swapbe32(XLDR_CSR_START | XLDR_CSR_MSBF), vaddr + BASE_LOADER + XLDR_REG_CSR);
timeout = 0;
while(i < size) {
rval = swapbe32(ioread32(vaddr + XLDR_REG_FIFO_CSR + XLDR_FIFO_CSR_FULL));
if (rval & XLDR_FIFO_CSR_FULL) {
if (timeout++ > TIMEOUT) {
printk(KERN_ERR PFX "timeout on XLDR_FIFO_CSR_FULL\n");
return -ETIME;
}
usleep_range(1, US_TICKS);
continue;
}
printk(KERN_ERR PFX "pass #1\n");
n = (size -i) > 4 ? 3 : size -i - 1;
if (n < 3)
n |= XLDR_FIFO_R0_XLAST;
iowrite32(swapbe32(n), vaddr + BASE_LOADER + XLDR_REG_FIFO_R0);
iowrite32(swapbe32(htonl(data[i>>2])), vaddr + BASE_LOADER + XLDR_REG_FIFO_R1);
i+=n;
}
printk(KERN_ERR PFX "pass #2\n");
while(1)
{
rval = swapbe32(ioread32(vaddr + BASE_LOADER + XLDR_REG_CSR));
if(rval & XLDR_CSR_DONE) {
printk(KERN_ERR PFX "Bitstream loaded, status: %s\n",
(rval & XLDR_CSR_ERROR ? "ERROR" : "OK"));
/* give the VME bus control to App FPGA */
iowrite32(swapbe32(XLDR_CSR_EXIT), vaddr + BASE_LOADER + XLDR_REG_CSR);
vme_release_mapping(&mapping, 1);
return rval & XLDR_CSR_ERROR ? -1 : 0;
}
if (rval & XLDR_CSR_ERROR) {
printk(KERN_ERR PFX "Error loading bitstream\n");
return -EINVAL;
}
}
return 0;
}
static int __devexit svec_remove(struct device *pdev, unsigned int ndev)
{
printk("remove\n");
/* struct svec_dev *card = dev_get_drvdata(pdev);
int ret;
dev_t devno = MKDEV(MAJOR(svec_devno), 0);
ret = vme_free_irq(vector[ndev]);
if (ret)
dev_warn(pdev, "Cannot free irq %d, err %d\n", vector[ndev], ret);
*/
/* avoid deleting unregistered devices */
/*
if (card) {
if (card->cdev.owner == THIS_MODULE) {
printk(KERN_ERR PFX "unregister_chrdev_region\n");
unregister_chrdev_region(devno, lun_num);
}
}
else
printk(KERN_ERR PFX "card is null!\n");
printk(KERN_ERR PFX "class_destroy\n");
class_destroy(svec_class);
*/
return 0;
}
/*
static int svec_irq(void *arg)
{
return 0;
}
*/
static int __devinit svec_match(struct device *pdev, unsigned int ndev)
{
printk (KERN_ERR PFX "match\n");
/* TODO */
if (ndev >= vmebase1_num)
return 0;
if (ndev >= vector_num || ndev >= level_num) {
dev_warn(pdev, "irq vector/level missing\n");
return 0;
}
return 1;
}
int svec_load_fpga_file (struct svec_dev *svec, char *name)
{
struct device *dev = svec->dev;
const struct firmware *fw;
int err = 0;
dev_info(dev, "%s: file %s\n", __func__, name);
if (name == NULL) {
printk (KERN_ERR PFX "%s: file name is NULL\n", __func__);
}
err = request_firmware(&fw, name, dev);
if (err < 0) {
dev_err(dev, "request firmware \"%s\": error %i\n", name, err);
return err;
}
printk (KERN_ERR PFX "got file \"%s\", %i (0x%x) bytes\n",
name, fw->size, fw->size);
err = svec_load_fpga(svec, (uint32_t *)fw->data, 0);
release_firmware(fw);
return err;
}
static int __devinit svec_probe(struct device *pdev, unsigned int ndev)
{
struct svec_dev *svec;
const char *name;
dev_t devno;
int error = 0;
if (lun[ndev] >= SVEC_MAX_DEVICES) {
printk(KERN_ERR PFX "Card lun %d out of range [0..%d]\n",
lun[ndev], SVEC_MAX_DEVICES -1);
return -EINVAL;
}
printk (KERN_ERR PFX "probe for device %02d\n", ndev);
svec = kzalloc(sizeof(*svec), GFP_KERNEL);
if (svec == NULL) {
printk(KERN_ERR PFX "Cannot allocate memory for svec card struct\n");
return -ENOMEM;
}
/* Initialize struct fields*/
svec->lun = lun[ndev];
svec->vmebase1 = vmebase1[ndev];
svec->vmebase2 = vmebase2[ndev];
svec->vector = vector[ndev];
svec->level = level[ndev];
svec->fw_name = fw_name[ndev];
svec->dev = pdev;
/* Load the golden FPGA binary to read the eeprom */
error = svec_load_fpga_file(svec, svec->fw_name);
if (error)
goto failed;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
name = pdev->bus_id;
#else
name = dev_name(pdev);
#endif
/*
error = vme_request_irq(vector[ndev], svec_irq, svec, name);
if (error) {
printk(KERN_ERR PFX "vme_request_irq failed %d\n", error);
goto failed;
}
*/
strlcpy(svec->driver, DRIVER_NAME, sizeof(svec->driver));
snprintf(svec->description, sizeof(svec->description),
"SVEC at VME-A32 0x%08lx - 0x%08lx irqv %d irql %d",
svec->vmebase1, svec->vmebase2, vector[ndev], level[ndev]);
printk (KERN_ERR PFX "%s\n", svec->description);
/*Create cdev, just to know the carrier is there */
devno = MKDEV(MAJOR(svec_devno), ndev);
cdev_init(&svec->cdev, &svec_fops);
svec->cdev.owner = THIS_MODULE;
error = cdev_add(&svec->cdev, devno, 1);
if (error) {
dev_err(pdev, "Error %d adding cdev %d\n", error, ndev);
goto failed;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
svec->dev = device_create(svec_class, pdev, devno, NULL, "svec.%i", ndev);
#else
svec->dev = device_create(svec_class, pdev, devno, "svec.%i", ndev);
#endif /* 2.6.28 */
if (IS_ERR(pdev)) {
error = PTR_ERR(svec->dev);
dev_err(pdev, "Error %d creating device %d\n", error, ndev);
svec->dev = NULL;
goto device_create_failed;
}
if (!error) {
dev_set_drvdata(svec->dev, svec);
goto out;
}
device_create_failed:
cdev_del(&svec->cdev);
failed:
kfree(svec);
return -EINVAL;
out:
return error;
}
static struct vme_driver svec_driver = {
.match = svec_match,
.probe = svec_probe,
.remove = __devexit_p(svec_remove),
.driver = {
.name = DRIVER_NAME,
},
};
static int __init svec_init(void)
{
int error = 0;
/* TODO: Check parameters */
/* Device creation for the carrier, just in case... */
error = alloc_chrdev_region(&svec_devno, 0, lun_num, "svec");
if (error) {
printk(KERN_ERR PFX "Failed to allocate chrdev region\n");
goto out;
}
/*
svec_class = class_create(THIS_MODULE, "svec");
if (IS_ERR(svec_class)) {
printk(KERN_ERR PFX "Failed to create svec class\n");
error = PTR_ERR(svec_class);
goto out;
}
*/
error = vme_register_driver(&svec_driver, lun_num);
if (error) {
printk(KERN_ERR PFX "Cannot register vme driver - lun [%d]\n", lun_num);
class_destroy(svec_class);
}
out:
return error;
}
static void __exit svec_exit(void)
{
printk("svec_exit\n");
vme_unregister_driver(&svec_driver);
}
module_init(svec_init);
module_exit(svec_exit);
MODULE_AUTHOR("");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("svec driver");
/*
Register definitions for slave core: Xilinx FPGA loader
* File : xloader_regs.h
* Author : auto-generated by wbgen2 from xloader_wb.wb
* Created : Thu Jun 21 15:17:30 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE xloader_wb.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_XLOADER_WB_WB
#define __WBGEN2_REGDEFS_XLOADER_WB_WB
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Control/status register */
/* definitions for field: Start configuration in reg: Control/status register */
#define XLDR_CSR_START WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Configuration done in reg: Control/status register */
#define XLDR_CSR_DONE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Configuration error in reg: Control/status register */
#define XLDR_CSR_ERROR WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Loader busy in reg: Control/status register */
#define XLDR_CSR_BUSY WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Byte order select in reg: Control/status register */
#define XLDR_CSR_MSBF WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Software resest in reg: Control/status register */
#define XLDR_CSR_SWRST WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Exit bootloader mode in reg: Control/status register */
#define XLDR_CSR_EXIT WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Serial clock divider in reg: Control/status register */
#define XLDR_CSR_CLKDIV_MASK WBGEN2_GEN_MASK(8, 6)
#define XLDR_CSR_CLKDIV_SHIFT 8
#define XLDR_CSR_CLKDIV_W(value) WBGEN2_GEN_WRITE(value, 8, 6)
#define XLDR_CSR_CLKDIV_R(reg) WBGEN2_GEN_READ(reg, 8, 6)
/* definitions for register: Bootloader Trigger Register */
/* definitions for register: GPIO Output Register */
/* definitions for register: ID Register */
/* definitions for register: FIFO 'Bitstream FIFO' data input register 0 */
/* definitions for field: Entry size in reg: FIFO 'Bitstream FIFO' data input register 0 */
#define XLDR_FIFO_R0_XSIZE_MASK WBGEN2_GEN_MASK(0, 2)
#define XLDR_FIFO_R0_XSIZE_SHIFT 0
#define XLDR_FIFO_R0_XSIZE_W(value) WBGEN2_GEN_WRITE(value, 0, 2)
#define XLDR_FIFO_R0_XSIZE_R(reg) WBGEN2_GEN_READ(reg, 0, 2)
/* definitions for field: Last xfer in reg: FIFO 'Bitstream FIFO' data input register 0 */
#define XLDR_FIFO_R0_XLAST WBGEN2_GEN_MASK(2, 1)
/* definitions for register: FIFO 'Bitstream FIFO' data input register 1 */
/* definitions for field: Data in reg: FIFO 'Bitstream FIFO' data input register 1 */
#define XLDR_FIFO_R1_XDATA_MASK WBGEN2_GEN_MASK(0, 32)
#define XLDR_FIFO_R1_XDATA_SHIFT 0
#define XLDR_FIFO_R1_XDATA_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define XLDR_FIFO_R1_XDATA_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Bitstream FIFO' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Bitstream FIFO' control/status register */
#define XLDR_FIFO_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Bitstream FIFO' control/status register */
#define XLDR_FIFO_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO clear in reg: FIFO 'Bitstream FIFO' control/status register */
#define XLDR_FIFO_CSR_CLEAR_BUS WBGEN2_GEN_MASK(18, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Bitstream FIFO' control/status register */
#define XLDR_FIFO_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define XLDR_FIFO_CSR_USEDW_SHIFT 0
#define XLDR_FIFO_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define XLDR_FIFO_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* [0x0]: REG Control/status register */
#define XLDR_REG_CSR 0x00000000
/* [0x4]: REG Bootloader Trigger Register */
#define XLDR_REG_BTRIGR 0x00000004
/* [0x8]: REG GPIO Output Register */
#define XLDR_REG_GPIOR 0x00000008
/* [0xc]: REG ID Register */
#define XLDR_REG_IDR 0x0000000c
/* [0x10]: REG FIFO 'Bitstream FIFO' data input register 0 */
#define XLDR_REG_FIFO_R0 0x00000010
/* [0x14]: REG FIFO 'Bitstream FIFO' data input register 1 */
#define XLDR_REG_FIFO_R1 0x00000014
/* [0x18]: REG FIFO 'Bitstream FIFO' control/status register */
#define XLDR_REG_FIFO_CSR 0x00000018
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment