diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2015-02-23 13:02:39 +0100 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2015-04-17 01:10:17 +0200 |
commit | 3bb41226e0941b86d58ecb97f7d292677de573c8 (patch) | |
tree | 907aa270343f7c6d1bc08bf73288fb9b10da6197 /c/src/lib/libbsp/sparc/shared/gpio | |
parent | LEON: added network device configuration helper function (diff) | |
download | rtems-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.c | 265 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/gpio/grgpio.c | 437 |
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; +} |