Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  GRGPIO GPIO Driver interface.
0004  *
0005  *  COPYRIGHT (c) 2009.
0006  *  Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <bsp.h>
0031 #include <rtems/libio.h>
0032 #include <stdlib.h>
0033 #include <assert.h>
0034 #include <rtems/bspIo.h>
0035 #include <string.h>
0036 #include <stdio.h>
0037 
0038 #include <drvmgr/drvmgr.h>
0039 #include <grlib/ambapp_bus.h>
0040 #include <grlib/grgpio.h>
0041 #include <grlib/gpiolib.h>
0042 #include <grlib/ambapp.h>
0043 #include <grlib/grlib.h>
0044 #include <grlib/grlib_impl.h>
0045 
0046 /*#define DEBUG 1*/
0047 
0048 #ifdef DEBUG
0049 #define DBG(x...) printk(x)
0050 #define STATIC
0051 #else
0052 #define DBG(x...) 
0053 #define STATIC static
0054 #endif
0055 
0056 struct grgpio_isr {
0057     drvmgr_isr isr;
0058     void *arg;
0059 };
0060 
0061 struct grgpio_priv {
0062     struct drvmgr_dev   *dev;
0063     struct grgpio_regs      *regs;
0064     int             irq;
0065     int             minor;
0066 
0067     /* Driver implementation */
0068     int             port_cnt;
0069     unsigned char           port_handles[32];
0070     struct grgpio_isr       isrs[32];
0071     struct gpiolib_drv      gpiolib_desc;
0072     unsigned int            bypass;
0073     unsigned int            imask;
0074 };
0075 
0076 /******************* Driver Manager Part ***********************/
0077 
0078 int grgpio_device_init(struct grgpio_priv *priv);
0079 
0080 int grgpio_init1(struct drvmgr_dev *dev);
0081 int grgpio_init2(struct drvmgr_dev *dev);
0082 
0083 struct drvmgr_drv_ops grgpio_ops = 
0084 {
0085     .init = {grgpio_init1, NULL, NULL, NULL},
0086     .remove = NULL,
0087     .info = NULL
0088 };
0089 
0090 struct amba_dev_id grgpio_ids[] = 
0091 {
0092     {VENDOR_GAISLER, GAISLER_GPIO},
0093     {0, 0}      /* Mark end of table */
0094 };
0095 
0096 struct amba_drv_info grgpio_drv_info =
0097 {
0098     {
0099         DRVMGR_OBJ_DRV,             /* Driver */
0100         NULL,                   /* Next driver */
0101         NULL,                   /* Device list */
0102         DRIVER_AMBAPP_GAISLER_GRGPIO_ID,    /* Driver ID */
0103         "GRGPIO_DRV",               /* Driver Name */
0104         DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
0105         &grgpio_ops,
0106         NULL,                   /* Funcs */
0107         0,                  /* No devices yet */
0108         0,
0109     },
0110     &grgpio_ids[0]
0111 };
0112 
0113 void grgpio_register_drv (void)
0114 {
0115     DBG("Registering GRGPIO driver\n");
0116     drvmgr_drv_register(&grgpio_drv_info.general);
0117 }
0118 
0119 /* Register GRGPIO pins as quick as possible to the GPIO library,
0120  * other drivers may depend upon them in INIT LEVEL 2.
0121  * Note that since IRQ may not be available in init1, it is assumed
0122  * that the GPIOLibrary does not request IRQ routines until LEVEL 2.
0123  */
0124 int grgpio_init1(struct drvmgr_dev *dev)
0125 {
0126     struct grgpio_priv *priv;
0127     int status, port;
0128 
0129     DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0130 
0131     /* This core will not find other cores, but other driver may depend upon 
0132      * the GPIO library to function. So, we set up GPIO right away.
0133      */
0134 
0135     /* Initialize library if not already done */
0136     status = gpiolib_initialize();
0137     if ( status < 0 )
0138         return DRVMGR_FAIL;
0139 
0140     priv = dev->priv = grlib_calloc(1, sizeof(*priv));
0141     if ( !priv )
0142         return DRVMGR_NOMEM;
0143     priv->dev = dev;
0144 
0145     if ( grgpio_device_init(priv) ) {
0146         free(dev->priv);
0147         dev->priv = NULL;
0148         return DRVMGR_FAIL;
0149     }
0150 
0151     /* Register all ports available on this core as GPIO port to 
0152      * upper layer
0153      */
0154     for(port=0; port<priv->port_cnt; port++) {
0155         priv->port_handles[port] = port;
0156         gpiolib_drv_register(&priv->gpiolib_desc,
0157                     &priv->port_handles[port]);
0158     }
0159 
0160     return DRVMGR_OK;
0161 }
0162 
0163 /******************* Driver Implementation ***********************/
0164 
0165 /* Find port from handle, returns -1 if not found */
0166 static int grgpio_find_port(void *handle, struct grgpio_priv **priv)
0167 {
0168     unsigned char portnr;
0169     
0170     portnr = *(unsigned char *)handle;
0171     if ( portnr > 31 )
0172         return -1;
0173     *priv = (struct grgpio_priv *)
0174         (((unsigned int)handle - portnr*sizeof(unsigned char)) - 
0175         offsetof(struct grgpio_priv, port_handles));
0176     return portnr;
0177 }
0178 
0179 static int grgpio_gpiolib_open(void *handle)
0180 {
0181     struct grgpio_priv *priv;
0182     int portnr;
0183 
0184     portnr = grgpio_find_port(handle, &priv);
0185     if ( portnr < 0 ) {
0186         DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
0187         return -1;
0188     }
0189     DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
0190 
0191     /* Open the device, nothing to be done... */
0192 
0193     return 0;
0194 }
0195 
0196 static int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
0197 {
0198     struct grgpio_priv *priv;
0199     int portnr;
0200     unsigned int mask;
0201 
0202     portnr = grgpio_find_port(handle, &priv);
0203     if ( portnr < 0 ) {
0204         return -1;
0205     }
0206     DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
0207 
0208     /* Configure the device. And check that operation is supported,
0209      * not all I/O Pins have IRQ support.
0210      */
0211     mask = (1<<portnr);
0212 
0213     /* Return error when IRQ not supported by this I/O Line and it
0214      * is beeing enabled by user.
0215      */
0216     if ( ((mask & priv->imask) == 0) && cfg->mask )
0217         return -1;
0218 
0219     priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
0220 
0221     /* Configure settings before enabling interrupt */
0222     priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
0223     priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
0224     priv->regs->imask |= cfg->mask ? mask : 0;
0225 
0226     return 0;
0227 }
0228 
0229 static int grgpio_grpiolib_get(void *handle, int *inval)
0230 {
0231     struct grgpio_priv *priv;
0232     int portnr;
0233 
0234     portnr = grgpio_find_port(handle, &priv);
0235     if ( portnr < 0 ) {
0236         return -1;
0237     }
0238     DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
0239 
0240     /* Get current status of the port */
0241     if ( inval )
0242         *inval = (priv->regs->data >> portnr) & 0x1;
0243 
0244     return 0;
0245 }
0246 
0247 static int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
0248 {
0249     struct grgpio_priv *priv;
0250     int portnr;
0251     drvmgr_isr isr;
0252     void *arg;
0253 
0254     portnr = grgpio_find_port(handle, &priv);
0255     if ( portnr < 0 ) {
0256         return -1;
0257     }
0258     DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
0259 
0260     if ( options & GPIOLIB_IRQ_FORCE )
0261         return -1;
0262 
0263     isr = priv->isrs[portnr].isr;
0264     arg = priv->isrs[portnr].arg;
0265 
0266     if ( options & GPIOLIB_IRQ_DISABLE ) {
0267         /* Disable interrupt at interrupt controller */
0268         if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
0269             return -1;
0270         }
0271     }
0272     if ( options & GPIOLIB_IRQ_CLEAR ) {
0273         /* Clear interrupt at interrupt controller */
0274         if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
0275             return -1;
0276         }
0277     }
0278     if ( options & GPIOLIB_IRQ_ENABLE ) {
0279         /* Enable interrupt at interrupt controller */
0280         if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
0281             return -1;
0282         }
0283     }
0284     if ( options & GPIOLIB_IRQ_MASK ) {
0285         /* Mask (disable) interrupt at interrupt controller */
0286         if ( drvmgr_interrupt_mask(priv->dev, portnr) ) {
0287             return -1;
0288         }
0289     }
0290     if ( options & GPIOLIB_IRQ_UNMASK ) {
0291         /* Unmask (enable) interrupt at interrupt controller */
0292         if ( drvmgr_interrupt_unmask(priv->dev, portnr) ) {
0293             return -1;
0294         }
0295     }
0296 
0297     return 0;
0298 }
0299 
0300 static int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
0301 {
0302     struct grgpio_priv *priv;
0303     int portnr;
0304 
0305     portnr = grgpio_find_port(handle, &priv);
0306     if ( portnr < 0 ) {
0307         DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
0308         return -1;
0309     }
0310     DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
0311 
0312     /* Since the user doesn't provide the ISR and argument, we must... */
0313     priv->isrs[portnr].isr = func;
0314     priv->isrs[portnr].arg = arg;
0315 
0316     return 0;
0317 }
0318 
0319 static int grgpio_grpiolib_set(void *handle, int dir, int outval)
0320 {
0321     struct grgpio_priv *priv;
0322     int portnr;
0323     unsigned int mask;
0324 
0325     portnr = grgpio_find_port(handle, &priv);
0326     if ( portnr < 0 ) {
0327         DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
0328         return -1;
0329     }
0330     DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
0331 
0332     /* Set Direction and Output */
0333     mask = 1<<portnr;
0334     priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
0335     priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
0336 
0337     return 0;
0338 }
0339 
0340 static int grgpio_gpiolib_show(void *handle)
0341 {
0342     struct grgpio_priv *priv;
0343     int portnr, i, regs[7];
0344     volatile unsigned int *reg;
0345 
0346     portnr = grgpio_find_port(handle, &priv);
0347     if ( portnr < 0 ) {
0348         DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
0349         return -1;
0350     }
0351     for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
0352         regs[i] = ( *reg >> portnr) & 1;
0353     }
0354     printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
0355         priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
0356     return 0;
0357 }
0358 
0359 static int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
0360 {
0361     struct grgpio_priv *priv;
0362     int portnr;
0363     char prefix[48];
0364     struct drvmgr_dev *dev;
0365 
0366     if ( !pinfo )
0367         return -1;
0368 
0369     portnr = grgpio_find_port(handle, &priv);
0370     if ( portnr < 0 ) {
0371         DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
0372         return -1;
0373     }
0374 
0375     /* Get Filesystem name prefix */
0376     dev = priv->dev;
0377     prefix[0] = '\0';
0378     if ( drvmgr_get_dev_prefix(dev, prefix) ) {
0379         /* Failed to get prefix, make sure of a unique FS name
0380          * by using the driver minor.
0381          */
0382         snprintf(pinfo->devName, 80, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
0383     } else {
0384         /* Got special prefix, this means we have a bus prefix
0385          * And we should use our "bus minor"
0386          */
0387         snprintf(pinfo->devName, 80, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
0388     }
0389 
0390     return 0;
0391 }
0392 
0393 static struct gpiolib_drv_ops grgpio_gpiolib_ops = 
0394 {
0395     .config     = grgpio_grpiolib_config,
0396     .get        = grgpio_grpiolib_get,
0397     .irq_opts   = grgpio_grpiolib_irq_opts,
0398     .irq_register   = grgpio_grpiolib_irq_register,
0399     .open       = grgpio_gpiolib_open,
0400     .set        = grgpio_grpiolib_set,
0401     .show       = grgpio_gpiolib_show,
0402     .get_info   = grgpio_gpiolib_get_info,
0403 };
0404 
0405 int grgpio_device_init(struct grgpio_priv *priv)
0406 {
0407     struct amba_dev_info *ambadev;
0408     struct ambapp_core *pnpinfo;
0409     union drvmgr_key_value *value;
0410     unsigned int mask;
0411     int port_cnt;
0412 
0413     /* Get device information from AMBA PnP information */
0414     ambadev = (struct amba_dev_info *)priv->dev->businfo;
0415     if ( ambadev == NULL ) {
0416         return -1;
0417     }
0418     pnpinfo = &ambadev->info;
0419     priv->irq = pnpinfo->irq;
0420     priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
0421 
0422     DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
0423 
0424     /* Mask all Interrupts */
0425     priv->regs->imask = 0;
0426 
0427     /* Make IRQ Rising edge triggered default */
0428     priv->regs->ipol = 0xfffffffe;
0429     priv->regs->iedge = 0xfffffffe;
0430 
0431     /* Read what I/O lines have IRQ support */
0432     priv->imask = priv->regs->ipol;
0433 
0434     /* Let the user configure the port count, this might be needed
0435      * when the GPIO lines must not be changed (assigned during bootup)
0436      */
0437     value = drvmgr_dev_key_get(priv->dev, "nBits", DRVMGR_KT_INT);
0438     if ( value ) {
0439         priv->port_cnt = value->i;
0440     } else {
0441         /* Auto detect number of GPIO ports */
0442         priv->regs->dir = 0;
0443         priv->regs->output = 0xffffffff;
0444         mask = priv->regs->output;
0445         priv->regs->output = 0;
0446 
0447         for(port_cnt=0; port_cnt<32; port_cnt++)
0448             if ( (mask & (1<<port_cnt)) == 0 )
0449                 break;
0450         priv->port_cnt = port_cnt;
0451     }
0452 
0453     /* Let the user configure the BYPASS register, this might be needed
0454      * to select which cores can do I/O on a pin.
0455      */
0456     value = drvmgr_dev_key_get(priv->dev, "bypass", DRVMGR_KT_INT);
0457     if ( value ) {
0458         priv->bypass = value->i;
0459     } else {
0460         priv->bypass = 0;
0461     }
0462     priv->regs->bypass = priv->bypass;
0463 
0464     /* Prepare GPIOLIB layer */
0465     priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
0466 
0467     return 0;
0468 }