| 
									
										
										
										
											2013-06-12 09:13:36 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2012 CERN (www.cern.ch) | 
					
						
							|  |  |  |  * Author: Alessandro Rubini <rubini@gnudd.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Released according to the GNU GPL, version 2 or any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is part of the White Rabbit project, a research effort led | 
					
						
							|  |  |  |  * by CERN, the European Institute for Nuclear Research. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifndef __LINUX_FMC_H__
 | 
					
						
							|  |  |  | #define __LINUX_FMC_H__
 | 
					
						
							|  |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/moduleparam.h>
 | 
					
						
							|  |  |  | #include <linux/device.h>
 | 
					
						
							|  |  |  | #include <linux/list.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct fmc_device; | 
					
						
							|  |  |  | struct fmc_driver; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This bus abstraction is developed separately from drivers, so we need | 
					
						
							|  |  |  |  * to check the version of the data structures we receive. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FMC_MAJOR	3
 | 
					
						
							|  |  |  | #define FMC_MINOR	0
 | 
					
						
							|  |  |  | #define FMC_VERSION	((FMC_MAJOR << 16) | FMC_MINOR)
 | 
					
						
							|  |  |  | #define __FMC_MAJOR(x)	((x) >> 16)
 | 
					
						
							|  |  |  | #define __FMC_MINOR(x)	((x) & 0xffff)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The device identification, as defined by the IPMI FRU (Field Replaceable | 
					
						
							|  |  |  |  * Unit) includes four different strings to describe the device. Here we | 
					
						
							|  |  |  |  * only match the "Board Manufacturer" and the "Board Product Name", | 
					
						
							|  |  |  |  * ignoring the "Board Serial Number" and "Board Part Number". All 4 are | 
					
						
							|  |  |  |  * expected to be strings, so they are treated as zero-terminated C strings. | 
					
						
							|  |  |  |  * Unspecified string (NULL) means "any", so if both are unspecified this | 
					
						
							|  |  |  |  * is a catch-all driver. So null entries are allowed and we use array | 
					
						
							|  |  |  |  * and length. This is unlike pci and usb that use null-terminated arrays | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fmc_fru_id { | 
					
						
							|  |  |  | 	char *manufacturer; | 
					
						
							|  |  |  | 	char *product_name; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * If the FPGA is already programmed (think Etherbone or the second | 
					
						
							|  |  |  |  * SVEC slot), we can match on SDB devices in the memory image. This | 
					
						
							|  |  |  |  * match uses an array of devices that must all be present, and the | 
					
						
							|  |  |  |  * match is based on vendor and device only. Further checks are expected | 
					
						
							|  |  |  |  * to happen in the probe function. Zero means "any" and catch-all is allowed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fmc_sdb_one_id { | 
					
						
							|  |  |  | 	uint64_t vendor; | 
					
						
							|  |  |  | 	uint32_t device; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | struct fmc_sdb_id { | 
					
						
							|  |  |  | 	struct fmc_sdb_one_id *cores; | 
					
						
							|  |  |  | 	int cores_nr; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct fmc_device_id { | 
					
						
							|  |  |  | 	struct fmc_fru_id *fru_id; | 
					
						
							|  |  |  | 	int fru_id_nr; | 
					
						
							|  |  |  | 	struct fmc_sdb_id *sdb_id; | 
					
						
							|  |  |  | 	int sdb_id_nr; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This sizes the module_param_array used by generic module parameters */ | 
					
						
							|  |  |  | #define FMC_MAX_CARDS 32
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The driver is a pretty simple thing */ | 
					
						
							|  |  |  | struct fmc_driver { | 
					
						
							|  |  |  | 	unsigned long version; | 
					
						
							|  |  |  | 	struct device_driver driver; | 
					
						
							|  |  |  | 	int (*probe)(struct fmc_device *); | 
					
						
							|  |  |  | 	int (*remove)(struct fmc_device *); | 
					
						
							|  |  |  | 	const struct fmc_device_id id_table; | 
					
						
							|  |  |  | 	/* What follows is for generic module parameters */ | 
					
						
							|  |  |  | 	int busid_n; | 
					
						
							|  |  |  | 	int busid_val[FMC_MAX_CARDS]; | 
					
						
							|  |  |  | 	int gw_n; | 
					
						
							|  |  |  | 	char *gw_val[FMC_MAX_CARDS]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | #define to_fmc_driver(x) container_of((x), struct fmc_driver, driver)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* These are the generic parameters, that drivers may instantiate */ | 
					
						
							|  |  |  | #define FMC_PARAM_BUSID(_d) \
 | 
					
						
							|  |  |  |     module_param_array_named(busid, _d.busid_val, int, &_d.busid_n, 0444) | 
					
						
							|  |  |  | #define FMC_PARAM_GATEWARE(_d) \
 | 
					
						
							|  |  |  |     module_param_array_named(gateware, _d.gw_val, charp, &_d.gw_n, 0444) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Drivers may need to configure gpio pins in the carrier. To read input | 
					
						
							|  |  |  |  * (a very uncommon operation, and definitely not in the hot paths), just | 
					
						
							|  |  |  |  * configure one gpio only and get 0 or 1 as retval of the config method | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fmc_gpio { | 
					
						
							|  |  |  | 	char *carrier_name; /* name or NULL for virtual pins */ | 
					
						
							|  |  |  | 	int gpio; | 
					
						
							|  |  |  | 	int _gpio;	/* internal use by the carrier */ | 
					
						
							|  |  |  | 	int mode;	/* GPIOF_DIR_OUT etc, from <linux/gpio.h> */ | 
					
						
							|  |  |  | 	int irqmode;	/* IRQF_TRIGGER_LOW and so on */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The numbering of gpio pins allows access to raw pins or virtual roles */ | 
					
						
							|  |  |  | #define FMC_GPIO_RAW(x)		(x)		/* 4096 of them */
 | 
					
						
							|  |  |  | #define __FMC_GPIO_IS_RAW(x)	((x) < 0x1000)
 | 
					
						
							|  |  |  | #define FMC_GPIO_IRQ(x)		((x) + 0x1000)	/*  256 of them */
 | 
					
						
							|  |  |  | #define FMC_GPIO_LED(x)		((x) + 0x1100)	/*  256 of them */
 | 
					
						
							|  |  |  | #define FMC_GPIO_KEY(x)		((x) + 0x1200)	/*  256 of them */
 | 
					
						
							|  |  |  | #define FMC_GPIO_TP(x)		((x) + 0x1300)	/*  256 of them */
 | 
					
						
							|  |  |  | #define FMC_GPIO_USER(x)	((x) + 0x1400)	/*  256 of them */
 | 
					
						
							|  |  |  | /* We may add SCL and SDA, or other roles if the need arises */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* GPIOF_DIR_IN etc are missing before 3.0. copy from <linux/gpio.h> */ | 
					
						
							|  |  |  | #ifndef GPIOF_DIR_IN
 | 
					
						
							|  |  |  | #  define GPIOF_DIR_OUT   (0 << 0)
 | 
					
						
							|  |  |  | #  define GPIOF_DIR_IN    (1 << 0)
 | 
					
						
							|  |  |  | #  define GPIOF_INIT_LOW  (0 << 1)
 | 
					
						
							|  |  |  | #  define GPIOF_INIT_HIGH (1 << 1)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The operations are offered by each carrier and should make driver | 
					
						
							|  |  |  |  * design completely independent of the carrier. Named GPIO pins may be | 
					
						
							|  |  |  |  * the exception. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fmc_operations { | 
					
						
							| 
									
										
										
										
											2013-06-19 12:49:30 +02:00
										 |  |  | 	uint32_t (*read32)(struct fmc_device *fmc, int offset); | 
					
						
							|  |  |  | 	void (*write32)(struct fmc_device *fmc, uint32_t value, int offset); | 
					
						
							| 
									
										
										
										
											2013-06-12 09:13:36 +02:00
										 |  |  | 	int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv); | 
					
						
							|  |  |  | 	int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw); | 
					
						
							|  |  |  | 	int (*irq_request)(struct fmc_device *fmc, irq_handler_t h, | 
					
						
							|  |  |  | 			   char *name, int flags); | 
					
						
							|  |  |  | 	void (*irq_ack)(struct fmc_device *fmc); | 
					
						
							|  |  |  | 	int (*irq_free)(struct fmc_device *fmc); | 
					
						
							|  |  |  | 	int (*gpio_config)(struct fmc_device *fmc, struct fmc_gpio *gpio, | 
					
						
							|  |  |  | 			   int ngpio); | 
					
						
							|  |  |  | 	int (*read_ee)(struct fmc_device *fmc, int pos, void *d, int l); | 
					
						
							|  |  |  | 	int (*write_ee)(struct fmc_device *fmc, int pos, const void *d, int l); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Prefer this helper rather than calling of fmc->reprogram directly */ | 
					
						
							|  |  |  | extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw, | 
					
						
							|  |  |  | 		     int sdb_entry); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The device reports all information needed to access hw. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * If we have eeprom_len and not contents, the core reads it. | 
					
						
							|  |  |  |  * Then, parsing of identifiers is done by the core which fills fmc_fru_id.. | 
					
						
							|  |  |  |  * Similarly a device that must be matched based on SDB cores must | 
					
						
							|  |  |  |  * fill the entry point and the core will scan the bus (FIXME: sdb match) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fmc_device { | 
					
						
							|  |  |  | 	unsigned long version; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	struct module *owner;		/* char device must pin it */ | 
					
						
							|  |  |  | 	struct fmc_fru_id id;		/* for EEPROM-based match */ | 
					
						
							|  |  |  | 	struct fmc_operations *op;	/* carrier-provided */ | 
					
						
							|  |  |  | 	int irq;			/* according to host bus. 0 == none */ | 
					
						
							|  |  |  | 	int eeprom_len;			/* Usually 8kB, may be less */ | 
					
						
							|  |  |  | 	int eeprom_addr;		/* 0x50, 0x52 etc */ | 
					
						
							|  |  |  | 	uint8_t *eeprom;		/* Full contents or leading part */ | 
					
						
							|  |  |  | 	char *carrier_name;		/* "SPEC" or similar, for special use */ | 
					
						
							|  |  |  | 	void *carrier_data;		/* "struct spec *" or equivalent */ | 
					
						
							|  |  |  | 	__iomem void *fpga_base;	/* May be NULL (Etherbone) */ | 
					
						
							|  |  |  | 	__iomem void *slot_base;	/* Set by the driver */ | 
					
						
							|  |  |  | 	struct fmc_device **devarray;	/* Allocated by the bus */ | 
					
						
							|  |  |  | 	int slot_id;			/* Index in the slot array */ | 
					
						
							|  |  |  | 	int nr_slots;			/* Number of slots in this carrier */ | 
					
						
							|  |  |  | 	unsigned long memlen;		/* Used for the char device */ | 
					
						
							|  |  |  | 	struct device dev;		/* For Linux use */ | 
					
						
							|  |  |  | 	struct device *hwdev;		/* The underlying hardware device */ | 
					
						
							|  |  |  | 	unsigned long sdbfs_entry; | 
					
						
							|  |  |  | 	struct sdb_array *sdb; | 
					
						
							|  |  |  | 	uint32_t device_id;		/* Filled by the device */ | 
					
						
							|  |  |  | 	char *mezzanine_name;		/* Defaults to ``fmc'' */ | 
					
						
							|  |  |  | 	void *mezzanine_data; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | #define to_fmc_device(x) container_of((x), struct fmc_device, dev)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FMC_DEVICE_HAS_GOLDEN		1
 | 
					
						
							|  |  |  | #define FMC_DEVICE_HAS_CUSTOM		2
 | 
					
						
							|  |  |  | #define FMC_DEVICE_NO_MEZZANINE		4
 | 
					
						
							|  |  |  | #define FMC_DEVICE_MATCH_SDB		8 /* fmc-core must scan sdb in fpga */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * If fpga_base can be used, the carrier offers no readl/writel methods, and | 
					
						
							|  |  |  |  * this expands to a single, fast, I/O access. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline uint32_t fmc_readl(struct fmc_device *fmc, int offset) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-19 12:49:30 +02:00
										 |  |  | 	if (unlikely(fmc->op->read32)) | 
					
						
							|  |  |  | 		return fmc->op->read32(fmc, offset); | 
					
						
							| 
									
										
										
										
											2013-06-12 09:13:36 +02:00
										 |  |  | 	return readl(fmc->fpga_base + offset); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static inline void fmc_writel(struct fmc_device *fmc, uint32_t val, int off) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-19 12:49:30 +02:00
										 |  |  | 	if (unlikely(fmc->op->write32)) | 
					
						
							|  |  |  | 		fmc->op->write32(fmc, val, off); | 
					
						
							| 
									
										
										
										
											2013-06-12 09:13:36 +02:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		writel(val, fmc->fpga_base + off); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* pci-like naming */ | 
					
						
							|  |  |  | static inline void *fmc_get_drvdata(const struct fmc_device *fmc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return dev_get_drvdata(&fmc->dev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	dev_set_drvdata(&fmc->dev, data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* The 4 access points */ | 
					
						
							|  |  |  | extern int fmc_driver_register(struct fmc_driver *drv); | 
					
						
							|  |  |  | extern void fmc_driver_unregister(struct fmc_driver *drv); | 
					
						
							|  |  |  | extern int fmc_device_register(struct fmc_device *tdev); | 
					
						
							|  |  |  | extern void fmc_device_unregister(struct fmc_device *tdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Two more for device sets, all driven by the same FPGA */ | 
					
						
							|  |  |  | extern int fmc_device_register_n(struct fmc_device **devs, int n); | 
					
						
							|  |  |  | extern void fmc_device_unregister_n(struct fmc_device **devs, int n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Internal cross-calls between files; not exported to other modules */ | 
					
						
							|  |  |  | extern int fmc_match(struct device *dev, struct device_driver *drv); | 
					
						
							|  |  |  | extern int fmc_fill_id_info(struct fmc_device *fmc); | 
					
						
							|  |  |  | extern void fmc_free_id_info(struct fmc_device *fmc); | 
					
						
							|  |  |  | extern void fmc_dump_eeprom(const struct fmc_device *fmc); | 
					
						
							|  |  |  | extern void fmc_dump_sdb(const struct fmc_device *fmc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* __LINUX_FMC_H__ */
 |