summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/gpio
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2015-02-23 13:02:39 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3bb41226e0941b86d58ecb97f7d292677de573c8 (patch)
tree907aa270343f7c6d1bc08bf73288fb9b10da6197 /c/src/lib/libbsp/sparc/shared/gpio
parentLEON: added network device configuration helper function (diff)
downloadrtems-3bb41226e0941b86d58ecb97f7d292677de573c8.tar.bz2
LEON: added new drivers to the LEON2/LEON3 BSPs
Most drivers use the Driver Manager for device probing, they work on AMBA-over-PCI systems if PCI is big-endian. New APIs: * GPIO Library, interfaced to GRGPIO * GENIRQ, Generic interrupt service implementation helper New GRLIB Drivers: * ACTEL 1553 RT, user interface is similar to 1553 BRM driver * GR1553 (1553 BC, RT and BM core) * AHBSTAT (AHB error status core) * GRADCDAC (Core interfacing to ADC/DAC hardware) * GRGPIO (GPIO port accessed from GPIO Library) * MCTRL (Memory controller settings configuration) * GRETH (10/100/1000 Ethernet driver using Driver manager) * GRPWM (Pulse Width Modulation core) * SPICTRL (SPI master interface) * GRSPW_ROUTER (SpaceWire Router AMBA configuration interface) * GRCTM (SpaceCraft on-board Time Management core) * SPWCUC (Time distribution over SpaceWire) * GRTC (SpaceCraft up-link Tele core) * GRTM (SpaceCraft down-link Tele Metry core) GR712RC ASIC specific interfaces: * GRASCS * CANMUX (select between OCCAN and SATCAN) * SATCAN * SLINK
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/gpio')
-rw-r--r--c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c265
-rw-r--r--c/src/lib/libbsp/sparc/shared/gpio/grgpio.c437
2 files changed, 702 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
new file mode 100644
index 0000000000..22f1baa5f3
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/gpiolib.c
@@ -0,0 +1,265 @@
+/* GPIOLIB interface implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpiolib.h>
+
+struct gpiolib_port;
+
+struct gpiolib_port {
+ struct gpiolib_port *next;
+ int minor;
+ struct gpiolib_drv *drv;
+ void *handle;
+
+ int open;
+};
+
+/* Root of GPIO Ports */
+struct gpiolib_port *gpiolib_ports;
+
+/* Number of GPIO ports registered */
+static int port_nr;
+
+/* 1 if libraray initialized */
+static int gpiolib_initied = 0;
+
+/* Insert a port first in ports list */
+void gpiolib_list_add(struct gpiolib_port *port)
+{
+ port->next = gpiolib_ports;
+ gpiolib_ports = port;
+}
+
+struct gpiolib_port *gpiolib_find(int minor)
+{
+ struct gpiolib_port *p;
+
+ p = gpiolib_ports;
+ while ( p && (p->minor != minor) ) {
+ p = p->next;
+ }
+ return p;
+}
+
+struct gpiolib_port *gpiolib_find_by_name(char *name)
+{
+ struct gpiolib_port *p;
+ struct gpiolib_info info;
+ int (*get_info)(void *, struct gpiolib_info *);
+
+ p = gpiolib_ports;
+ while ( p ) {
+ get_info = p->drv->ops->get_info;
+ if ( get_info && (get_info(p->handle, &info) == 0) ) {
+ if ( strncmp(name, (char *)&info.devName[0], 64) == 0 ) {
+ break;
+ }
+ }
+ p = p->next;
+ }
+ return p;
+}
+
+void gpiolib_list_remove(struct gpiolib_port *port)
+{
+
+}
+
+int gpiolib_drv_register(struct gpiolib_drv *drv, void *handle)
+{
+ struct gpiolib_port *port;
+
+ if ( !drv || !drv->ops )
+ return -1;
+
+ port = malloc(sizeof(*port));
+ if ( port == NULL )
+ return -1;
+
+ memset(port, 0, sizeof(*port));
+ port->handle = handle;
+ port->minor = port_nr++;
+ port->drv = drv;
+
+ gpiolib_list_add(port);
+
+ return 0;
+}
+
+void gpiolib_show(int port, void *handle)
+{
+ struct gpiolib_port *p;
+
+ if ( port == -1 ) {
+ p = gpiolib_ports;
+ while (p != NULL) {
+ if ( p->drv->ops->show )
+ p->drv->ops->show(p->handle);
+ p = p->next;
+ }
+ } else {
+ if ( handle ) {
+ p = handle;
+ } else {
+ p = gpiolib_find(port);
+ }
+ if ( p == NULL ) {
+ printf("PORT %d NOT FOUND\n", port);
+ return;
+ }
+ if ( p->drv->ops->show )
+ p->drv->ops->show(p->handle);
+ }
+}
+
+void *gpiolib_open_internal(int port, char *devName)
+{
+ struct gpiolib_port *p;
+
+ if ( gpiolib_initied == 0 )
+ return NULL;
+
+ /* Find */
+ if ( port >= 0 ) {
+ p = gpiolib_find(port);
+ } else {
+ p = gpiolib_find_by_name(devName);
+ }
+ if ( p == NULL )
+ return NULL;
+
+ if ( p->open )
+ return NULL;
+
+ p->open = 1;
+ return p;
+}
+
+void *gpiolib_open(int port)
+{
+ return gpiolib_open_internal(port, NULL);
+}
+
+void *gpiolib_open_by_name(char *devName)
+{
+ return gpiolib_open_internal(-1, devName);
+}
+
+void gpiolib_close(void *handle)
+{
+ struct gpiolib_port *p = handle;
+
+ if ( p && p->open ) {
+ p->open = 0;
+ }
+}
+
+int gpiolib_set_config(void *handle, struct gpiolib_config *cfg)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port || !cfg )
+ return -1;
+
+ if ( !port->drv->ops->config )
+ return -1;
+
+ return port->drv->ops->config(port->handle, cfg);
+}
+
+int gpiolib_set(void *handle, int dir, int outval)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->set )
+ return -1;
+
+ return port->drv->ops->set(port->handle, dir, outval);
+}
+
+int gpiolib_get(void *handle, int *inval)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port || !inval)
+ return -1;
+
+ if ( !port->drv->ops->get )
+ return -1;
+
+ return port->drv->ops->get(port->handle, inval);
+}
+
+/*** IRQ Functions ***/
+int gpiolib_irq_register(void *handle, void *func, void *arg)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->irq_register )
+ return -1;
+
+ return port->drv->ops->irq_register(port->handle, func, arg);
+}
+
+int gpiolib_irq_opts(void *handle, unsigned int options)
+{
+ struct gpiolib_port *port = handle;
+
+ if ( !port )
+ return -1;
+
+ if ( !port->drv->ops->irq_opts )
+ return -1;
+
+ return port->drv->ops->irq_opts(port->handle, options);
+}
+
+int gpiolib_irq_clear(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_CLEAR);
+}
+
+int gpiolib_irq_force(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_FORCE);
+}
+
+int gpiolib_irq_enable(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_ENABLE);
+}
+
+int gpiolib_irq_disable(void *handle)
+{
+ return gpiolib_irq_opts(handle, GPIOLIB_IRQ_DISABLE);
+}
+
+/*** Initialization ***/
+int gpiolib_initialize(void)
+{
+ if ( gpiolib_initied != 0 )
+ return 0;
+
+ /* Initialize Libarary */
+ port_nr = 0;
+ gpiolib_ports = 0;
+ gpiolib_initied = 1;
+ return 0;
+}
diff --git a/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
new file mode 100644
index 0000000000..92e9657833
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c
@@ -0,0 +1,437 @@
+/* GRGPIO GPIO Driver interface.
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <grgpio.h>
+#include <gpiolib.h>
+#include <ambapp.h>
+#include <grlib.h>
+
+/*#define DEBUG 1*/
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#define STATIC
+#else
+#define DBG(x...)
+#define STATIC static
+#endif
+
+struct grgpio_isr {
+ drvmgr_isr isr;
+ void *arg;
+};
+
+struct grgpio_priv {
+ struct drvmgr_dev *dev;
+ struct grgpio_regs *regs;
+ int irq;
+ int minor;
+
+ /* Driver implementation */
+ int port_cnt;
+ unsigned char port_handles[32];
+ struct grgpio_isr isrs[32];
+ struct gpiolib_drv gpiolib_desc;
+ unsigned int bypass;
+ unsigned int imask;
+};
+
+/******************* Driver Manager Part ***********************/
+
+int grgpio_device_init(struct grgpio_priv *priv);
+
+int grgpio_init1(struct drvmgr_dev *dev);
+int grgpio_init2(struct drvmgr_dev *dev);
+
+struct drvmgr_drv_ops grgpio_ops =
+{
+ .init = {grgpio_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id grgpio_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GPIO},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info grgpio_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRGPIO_ID, /* Driver ID */
+ "GRGPIO_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &grgpio_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &grgpio_ids[0]
+};
+
+void grgpio_register_drv (void)
+{
+ DBG("Registering GRGPIO driver\n");
+ drvmgr_drv_register(&grgpio_drv_info.general);
+}
+
+/* Register GRGPIO pins as quick as possible to the GPIO library,
+ * other drivers may depend upon them in INIT LEVEL 2.
+ * Note that since IRQ may not be available in init1, it is assumed
+ * that the GPIOLibrary does not request IRQ routines until LEVEL 2.
+ */
+int grgpio_init1(struct drvmgr_dev *dev)
+{
+ struct grgpio_priv *priv;
+ int status, port;
+
+ DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ /* This core will not find other cores, but other driver may depend upon
+ * the GPIO library to function. So, we set up GPIO right away.
+ */
+
+ /* Initialize library if not already done */
+ status = gpiolib_initialize();
+ if ( status < 0 )
+ return DRVMGR_FAIL;
+
+ priv = dev->priv = malloc(sizeof(struct grgpio_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ priv->dev = dev;
+
+ if ( grgpio_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Register all ports available on this core as GPIO port to
+ * upper layer
+ */
+ for(port=0; port<priv->port_cnt; port++) {
+ priv->port_handles[port] = port;
+ gpiolib_drv_register(&priv->gpiolib_desc,
+ &priv->port_handles[port]);
+ }
+
+ return DRVMGR_OK;
+}
+
+/******************* Driver Implementation ***********************/
+
+/* Find port from handle, returns -1 if not found */
+int grgpio_find_port(void *handle, struct grgpio_priv **priv)
+{
+ unsigned char portnr;
+
+ portnr = *(unsigned char *)handle;
+ if ( portnr > 31 )
+ return -1;
+ *priv = (struct grgpio_priv *)
+ (((unsigned int)handle - portnr*sizeof(unsigned char)) -
+ offsetof(struct grgpio_priv, port_handles));
+ return portnr;
+}
+
+int grgpio_gpiolib_open(void *handle)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
+
+ /* Open the device, nothing to be done... */
+
+ return 0;
+}
+
+int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ unsigned int mask;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
+
+ /* Configure the device. And check that operation is supported,
+ * not all I/O Pins have IRQ support.
+ */
+ mask = (1<<portnr);
+
+ /* Return error when IRQ not supported by this I/O Line and it
+ * is beeing enabled by user.
+ */
+ if ( ((mask & priv->imask) == 0) && cfg->mask )
+ return -1;
+
+ priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
+
+ /* Configure settings before enabling interrupt */
+ priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
+ priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
+ priv->regs->imask |= cfg->mask ? mask : 0;
+
+ return 0;
+}
+
+int grgpio_grpiolib_get(void *handle, int *inval)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
+
+ /* Get current status of the port */
+ if ( inval )
+ *inval = (priv->regs->data >> portnr) & 0x1;
+
+ return 0;
+}
+
+int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ drvmgr_isr isr;
+ void *arg;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ return -1;
+ }
+ DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
+
+ if ( options & GPIOLIB_IRQ_FORCE )
+ return -1;
+
+ isr = priv->isrs[portnr].isr;
+ arg = priv->isrs[portnr].arg;
+
+ if ( options & GPIOLIB_IRQ_DISABLE ) {
+ /* Disable interrupt at interrupt controller */
+ if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_CLEAR ) {
+ /* Clear interrupt at interrupt controller */
+ if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
+ return -1;
+ }
+ }
+ if ( options & GPIOLIB_IRQ_ENABLE ) {
+ /* Enable interrupt at interrupt controller */
+ if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+ /* Since the user doesn't provide the ISR and argument, we must... */
+ priv->isrs[portnr].isr = func;
+ priv->isrs[portnr].arg = arg;
+
+ return 0;
+}
+
+int grgpio_grpiolib_set(void *handle, int dir, int outval)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ unsigned int mask;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
+
+ /* Set Direction and Output */
+ mask = 1<<portnr;
+ priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
+ priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
+
+ return 0;
+}
+
+int grgpio_gpiolib_show(void *handle)
+{
+ struct grgpio_priv *priv;
+ int portnr, i, regs[7];
+ volatile unsigned int *reg;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+ for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
+ regs[i] = ( *reg >> portnr) & 1;
+ }
+ printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
+ priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
+ return 0;
+}
+
+int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
+{
+ struct grgpio_priv *priv;
+ int portnr;
+ char prefix[48];
+ struct drvmgr_dev *dev;
+
+ if ( !pinfo )
+ return -1;
+
+ portnr = grgpio_find_port(handle, &priv);
+ if ( portnr < 0 ) {
+ DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
+ return -1;
+ }
+
+ /* Get Filesystem name prefix */
+ dev = priv->dev;
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
+ }
+
+ return 0;
+}
+
+static struct gpiolib_drv_ops grgpio_gpiolib_ops =
+{
+ .config = grgpio_grpiolib_config,
+ .get = grgpio_grpiolib_get,
+ .irq_opts = grgpio_grpiolib_irq_opts,
+ .irq_register = grgpio_grpiolib_irq_register,
+ .open = grgpio_gpiolib_open,
+ .set = grgpio_grpiolib_set,
+ .show = grgpio_gpiolib_show,
+ .get_info = grgpio_gpiolib_get_info,
+};
+
+int grgpio_device_init(struct grgpio_priv *priv)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ unsigned int mask;
+ int port_cnt;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ priv->irq = pnpinfo->irq;
+ priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
+
+ DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
+
+ /* Mask all Interrupts */
+ priv->regs->imask = 0;
+
+ /* Make IRQ Rising edge triggered default */
+ priv->regs->ipol = 0xfffffffe;
+ priv->regs->iedge = 0xfffffffe;
+
+ /* Read what I/O lines have IRQ support */
+ priv->imask = priv->regs->ipol;
+
+ /* Let the user configure the port count, this might be needed
+ * when the GPIO lines must not be changed (assigned during bootup)
+ */
+ value = drvmgr_dev_key_get(priv->dev, "nBits", KEY_TYPE_INT);
+ if ( value ) {
+ priv->port_cnt = value->i;
+ } else {
+ /* Auto detect number of GPIO ports */
+ priv->regs->dir = 0;
+ priv->regs->output = 0xffffffff;
+ mask = priv->regs->output;
+ priv->regs->output = 0;
+
+ for(port_cnt=0; port_cnt<32; port_cnt++)
+ if ( (mask & (1<<port_cnt)) == 0 )
+ break;
+ priv->port_cnt = port_cnt;
+ }
+
+ /* Let the user configure the BYPASS register, this might be needed
+ * to select which cores can do I/O on a pin.
+ */
+ value = drvmgr_dev_key_get(priv->dev, "bypass", KEY_TYPE_INT);
+ if ( value ) {
+ priv->bypass = value->i;
+ } else {
+ priv->bypass = 0;
+ }
+ priv->regs->bypass = priv->bypass;
+
+ /* Prepare GPIOLIB layer */
+ priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
+
+ return 0;
+}