Commit 7a1fb9bc authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'fmc-gpio'

parents 7a10b8bc cd6a8dcb
......@@ -199,6 +199,8 @@ struct fmc_operations {
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);
};
......@@ -254,6 +256,12 @@ The individual methods perform the following tasks:
The handler will receive the @i{fmc} pointer as @i{dev_id}; the
@i{flags} argument is still to be defined.
@item gpio_config
The method allows to configure a GPIO pin in the carrier, and
read its current value if it is configured as input. See
@ref{The GPIO Abstraction} for details.
@item read_ee
@itemx write_ee
......@@ -270,7 +278,80 @@ The individual methods perform the following tasks:
@end table
@c ##########################################################################
@node The GPIO Abstraction
@chapter The GPIO Abstraction
Support for GPIO pins in the @i{fmc-bus} environment is a little
heavy, and deserves special discussion.
While the general idea of a carrier-independent driver seems to fly,
configuration of specific signals within the carrier needs at least
some knowledge of the carrier itself. For this reason, the specific
driver can request to configure carrier-specific GPIO pins, numbered
from 0 to at most 4095. Configuration is performed by passing
a pointer to an array of @t{struct fmc_gpio} items, as well as
the number of those items:
@example
struct fmc_gpio {
char *carrier_name;
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 */
};
@end example
By specifying a @i{carrier_name} for each pin, the driver may access
different pins in different carriers. The @i{gpio_config} method
returns the number of pins successfully configured, and each carrier
just ignores requests for other carriers. So, for example, a driver
that has been developed and tested on both the SPEC and the SVEC may
request configuration of two different GPIO pins, and expect one such
configuration to succeed -- if none succeeds it most likely means that
the current carrier is a still-unknown one. (FIXME: the return value
is not actually used this way in current code).
If, however, your GPIO pin has a specific known role, you can
pass a special number in the @t{gpio} field. The header defines
the following macros:
@example
#define FMC_GPIO_RAW(x) (x) /* 4096 of them */
#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 */
@end example
Use of virtual GPIO numbers (anything but @t{FMC_GPIO_RAW}) is allowed
provided the @i{carrier_name} field is left unspecified (NULL). Each
carrier is responsible for providing a mapping between virtual and
physical GPIO numbers (and possibly cache the raw number in the
@t{_gpio} field). All carriers must map their I/O lines
to the sets above starting from zero. The SPEC, for example, maps
interrupt 0 and 1, and test points 0 through 3.
If, for example, a driver requires a free led and a test point (for a
scope probe to be plugged at some point during development) it may ask
for @t{FMC_GPIO_LED(0)} and @t{FMC_GPIO_TP(0)}. Each carrier will
provide suitable GPIO pins. Clearly, the person running the drivers
will know the order used by the specific carrier driver in assigning
leds and testpoints, so to make a carrier-dependent use of the diagnostic tools.
In theory, some form of autodetection should be possible: a driver
like the @i{wr-nic} (which uses IRQ(1) on the SPEC card) should
configure IRQ(0), make a test with software-generated interrupts and
configure IRQ(1) if the test fails -- the @i{wr-nic} gateware is
known to use IRQ1 on the SPEC, but the driver should be
carrier-independent if possible and thus use IRQ(0) as a first bet.
If a pin is configured as input, the @i{gpio_config} method returns 0
or 1, to report its current value. Invalid GPIO numbers will cause
@code{-ENODEV} to be returned for physical numbers and @code{-ENOENT}
for virtual mappings.
@bye
@c LocalWords: gnudd titlepage iftex texinfo CERN documentlanguage settitle
......
......@@ -2,6 +2,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/fmc.h>
#include "spec.h"
......@@ -16,6 +17,18 @@ irqreturn_t t_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
struct fmc_gpio t_gpio[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}, {
.gpio = FMC_GPIO_IRQ(1),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
int t_probe(struct fmc_device *fmc)
{
int ret;
......@@ -28,6 +41,8 @@ int t_probe(struct fmc_device *fmc)
ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED);
if (ret < 0)
return ret;
/* ignore error code of call below, we really don't care */
fmc->op->gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));
/* Reprogram, if asked to. ESRCH == no filename specified */
ret = fmc->op->reprogram(fmc, &t_drv,"");
......
......@@ -57,7 +57,34 @@ struct fmc_driver {
#define FMC_PARAM_GATEWARE(_d) \
module_param_array_named(gateware, _d.gw_val, charp, &_d.gw_n, 0444)
/* To be carrier-independent, we need to abstract hardware access */
/*
* Drivers may need to configure gpio pins in the carrier. To read input
* (a very uncommon opeation, 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 */
/*
* The operations are offered by each carrier and should make driver
* design completely independent of th carrier. Named GPIO pins may be
* the exception.
*/
struct fmc_operations {
uint32_t (*readl)(struct fmc_device *fmc, int offset);
void (*writel)(struct fmc_device *fmc, uint32_t value, int offset);
......@@ -67,6 +94,8 @@ struct fmc_operations {
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);
};
......
......@@ -11,6 +11,7 @@
#include <linux/fmc.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/gpio.h>
#include <linux/fmc-sdb.h>
#include "spec.h"
......@@ -112,27 +113,7 @@ static int spec_irq_request(struct fmc_device *fmc, irq_handler_t handler,
gennum_writel(spec, value, GNPPCI_MSI_CONTROL);
}
/* Enable gpio interrupts:
* gpio6: tp8: output low
* gpio7: tp7: input (was: interrupt, raising edge)
* gpio8: IRQ1 from FPGA: interrupt, raising edge
* gpio9: IRQ0 from FPGA: interrupt, raising edge
* gpio10: tp6: output low
* gpio11: tp5: input (was: interrupt, raising edge)
*/
/* bypass = alternate function */
gennum_mask_val(spec, 0xfc0, 0x00, GNGPIO_BYPASS_MODE);
/* direction 0 = output */
gennum_mask_val(spec, 0x440, 0x000, GNGPIO_DIRECTION_MODE);
gennum_mask_val(spec, 0xb80, 0xb80, GNGPIO_DIRECTION_MODE);
gennum_mask_val(spec, 0x440, 0x440, GNGPIO_OUTPUT_ENABLE);
gennum_mask_val(spec, 0x300, 0x000, GNGPIO_INT_TYPE); /* 0 = edge */
gennum_mask_val(spec, 0x300, 0x300, GNGPIO_INT_VALUE); /* 1 = raising */
gennum_mask_val(spec, 0x300, 0x000, GNGPIO_INT_ON_ANY);
gennum_writel(spec, 0x300, GNGPIO_INT_MASK_CLR); /* enable */
/* Interrupts are enabled by the driver, with gpio_config() */
return 0;
}
......@@ -157,6 +138,116 @@ static int spec_irq_free(struct fmc_device *fmc)
return 0;
}
/* This is the mapping from virtual GPIO pin numbers to raw gpio numbers */
struct {
int virtual; int raw;
} spec_gpio_map[] = {
/* 0: TCK */
/* 1: TMS */
/* 2: TDO */
/* 3: TDI */
/* 4: SDA */
/* 5: SCL */
/* 6: TP8 */ {FMC_GPIO_TP(3), FMC_GPIO_RAW(6)},
/* 7: TP7 */ {FMC_GPIO_TP(2), FMC_GPIO_RAW(7)},
/* 8: IRQ */ {FMC_GPIO_IRQ(0), FMC_GPIO_RAW(8)},
/* 9: IRQ */ {FMC_GPIO_IRQ(1), FMC_GPIO_RAW(9)},
/* 10: TP6 */ {FMC_GPIO_TP(1), FMC_GPIO_RAW(10)},
/* 11: TP5 */ {FMC_GPIO_TP(0), FMC_GPIO_RAW(11)},
/* 12: flash_cs, 13: spri_din, 14: bootsel1, 15: bootsel0 */
};
static int spec_map_pin(int virtual)
{
int i;
for (i = 0; i < ARRAY_SIZE(spec_gpio_map); i++)
if (spec_gpio_map[i].virtual == virtual)
return spec_gpio_map[i].raw;
return -ENOENT;
}
static int spec_cfg_pin(struct fmc_device *fmc, int pin, int mode, int imode)
{
struct spec_dev *spec = fmc->carrier_data;
int ret = 0;
int bit = (1 << pin);
if (pin < 0 || pin > 15)
return -ENODEV;
if (mode & (GPIOF_OPEN_DRAIN |GPIOF_OPEN_SOURCE))
return -EINVAL;
if (mode & GPIOF_DIR_IN) {
/* 1 = input */
gennum_mask_val(spec, bit, bit, GNGPIO_DIRECTION_MODE);
gennum_mask_val(spec, bit, bit, GNGPIO_OUTPUT_ENABLE);
ret = !!(gennum_readl(spec, GNGPIO_INPUT_VALUE) & bit);
} else {
if (mode & GPIOF_INIT_HIGH)
gennum_mask_val(spec, bit, bit, GNGPIO_OUTPUT_VALUE);
else
gennum_mask_val(spec, bit, 0, GNGPIO_OUTPUT_VALUE);
gennum_mask_val(spec, bit, 0, GNGPIO_DIRECTION_MODE);
}
/* Then, interrupt configuration, if needed */
if (!(imode & IRQF_TRIGGER_MASK)) {
gennum_writel(spec, bit, GNGPIO_INT_MASK_SET); /* disable */
return ret;
}
if (imode & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_RISING))
gennum_mask_val(spec, bit, bit, GNGPIO_INT_VALUE);
else
gennum_mask_val(spec, bit, 0, GNGPIO_INT_VALUE);
if (imode & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW))
gennum_mask_val(spec, bit, bit, GNGPIO_INT_TYPE);
else
gennum_mask_val(spec, bit, 0, GNGPIO_INT_TYPE);
gennum_mask_val(spec, bit, 0, GNGPIO_INT_ON_ANY); /* me lazy */
gennum_writel(spec, bit, GNGPIO_INT_MASK_CLR); /* enable */
return ret;
}
static int spec_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio,
int ngpio)
{
int i, done = 0, retval = 0;
for ( ; ngpio; gpio++, ngpio--) {
if (gpio->carrier_name && strcmp(gpio->carrier_name, "SPEC")) {
/* The array may setup raw pins for various carriers */
continue;
}
if (gpio->carrier_name) {
/* so, it's ours */
gpio->_gpio = gpio->gpio;
}
else if (!gpio->_gpio) {
/* virtual but not mapped (or poor gpio0) */
i = spec_map_pin(gpio->gpio);
if (i < 0)
return i;
gpio->_gpio = i;
}
i = spec_cfg_pin(fmc, gpio->_gpio,
gpio->mode, gpio->irqmode);
if (i < 0)
return i;
retval += i; /* may be the input value */
done++;
}
if (!done)
return -ENODEV;
return retval;
}
/* The engines for this live in spec-i2c.c, we only shape arguments */
static int spec_read_ee(struct fmc_device *fmc, int pos, void *data, int len)
{
......@@ -180,6 +271,7 @@ static struct fmc_operations spec_fmc_operations = {
.irq_request = spec_irq_request,
.irq_ack = spec_irq_ack,
.irq_free = spec_irq_free,
.gpio_config = spec_gpio_config,
.read_ee = spec_read_ee,
.write_ee = spec_write_ee,
};
......
......@@ -127,6 +127,10 @@ static int __devinit spec_probe(struct pci_dev *pdev,
if (ret)
goto out_unmap;
/* Put our 6 pins to a sane state (4 test points, 2 from FPGA) */
gennum_mask_val(spec, 0xfc0, 0x000, GNGPIO_BYPASS_MODE); /* no AF */
gennum_mask_val(spec, 0xfc0, 0xfc0, GNGPIO_DIRECTION_MODE); /* input */
gennum_writel(spec, 0xffff, GNGPIO_INT_MASK_SET); /* disable */
/* Load the golden FPGA binary to read the eeprom */
ret = spec_load_fpga_file(spec, spec_fw_name);
......
......@@ -161,6 +161,14 @@ static struct wrn_core wrn_cores2[] = {
}
};
struct fmc_gpio wrn_gpio_cfg[] = {
{
.gpio = FMC_GPIO_IRQ(1),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
int wrn_eth_init(struct fmc_device *fmc)
{
struct device *dev = fmc->hwdev;
......@@ -179,6 +187,8 @@ int wrn_eth_init(struct fmc_device *fmc)
dev_err(dev, "Can't request interrupt\n");
return ret;
}
/* FIXME: we should request irq0, self-test and then move to irq1 */
fmc->op->gpio_config(fmc, wrn_gpio_cfg, ARRAY_SIZE(wrn_gpio_cfg));
/* Make a copy of the platform device and register it */
ret = -ENOMEM;
......
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