Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  GRIOMMU Driver Interface
0005  *
0006  *  COPYRIGHT (c) 2017
0007  *  Cobham Gaisler AB
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <stdlib.h>
0032 #include <string.h>
0033 #include <drvmgr/drvmgr.h>
0034 #include <grlib/ambapp_bus.h>
0035 #include <grlib/ambapp.h>
0036 #include <rtems.h>
0037 #include <rtems/bspIo.h>
0038 #include <bsp.h>
0039 #include <grlib/griommu.h>
0040 
0041 #include <grlib/grlib_impl.h>
0042 
0043 /*#define STATIC*/
0044 #define STATIC static
0045 
0046 /*#define INLINE*/
0047 #define INLINE inline
0048 
0049 #define UNUSED __attribute__((unused))
0050 
0051 /*#define DEBUG 1*/
0052 
0053 #ifdef DEBUG
0054 #define DBG(x...) printf(x)
0055 #else
0056 #define DBG(x...) 
0057 #endif
0058 
0059 /*
0060  * GRIOMMU CAP0 register fields 
0061  */
0062 #define CAP0_A (0x1 << CAP0_A_BIT)
0063 #define CAP0_AC (0x1 << CAP0_AC_BIT)
0064 #define CAP0_CA (0x1 << CAP0_CA_BIT)
0065 #define CAP0_CP (0x1 << CAP0_CP_BIT)
0066 #define CAP0_NARB (0xf << CAP0_NARB_BIT)
0067 #define CAP0_CS (0x1 << CAP0_CS_BIT)
0068 #define CAP0_FT (0x3 << CAP0_FT_BIT)
0069 #define CAP0_ST (0x1 << CAP0_ST_BIT)
0070 #define CAP0_I (0x1 << CAP0_I_BIT)
0071 #define CAP0_IT (0x1 << CAP0_IT_BIT)
0072 #define CAP0_IA (0x1 << CAP0_IA_BIT)
0073 #define CAP0_IP (0x1 << CAP0_IP_BIT)
0074 #define CAP0_MB (0x1 << CAP0_MB_BIT)
0075 #define CAP0_GRPS (0xf << CAP0_GRPS_BIT)
0076 #define CAP0_MSTS (0xf << CAP0_MSTS_BIT)
0077 
0078 #define CAP0_A_BIT 31
0079 #define CAP0_AC_BIT 30
0080 #define CAP0_CA_BIT 29
0081 #define CAP0_CP_BIT 28
0082 #define CAP0_NARB_BIT 20
0083 #define CAP0_CS_BIT 19
0084 #define CAP0_FT_BIT 17
0085 #define CAP0_ST_BIT 16
0086 #define CAP0_I_BIT 15
0087 #define CAP0_IT_BIT 14
0088 #define CAP0_IA_BIT 13
0089 #define CAP0_IP_BIT 12
0090 #define CAP0_MB_BIT 8
0091 #define CAP0_GRPS_BIT 4
0092 #define CAP0_MSTS_BIT 0
0093 
0094 /*
0095  * GRIOMMU CAP1 register fields 
0096  */
0097 #define CAP1_CADDR (0xfff << CAP1_CADDR_BIT)
0098 #define CAP1_CMASK (0xf << CAP1_CMASK_BIT)
0099 #define CAP1_CTAGBITS (0xff << CAP1_CTAGBITS_BIT)
0100 #define CAP1_CISIZE (0x7 << CAP1_CISIZE_BIT)
0101 #define CAP1_CLINES (0x1f << CAP1_CLINES_BIT)
0102 
0103 #define CAP1_CADDR_BIT 20
0104 #define CAP1_CMASK_BIT 16
0105 #define CAP1_CTAGBITS_BIT 8
0106 #define CAP1_CISIZE_BIT 5
0107 #define CAP1_CLINES_BIT 0 
0108 
0109 /*
0110  * GRIOMMU CTRL register fields 
0111  * DEFINED IN HEADER FILE
0112  */
0113 
0114 /*
0115  * GRIOMMU FLUSH register fields 
0116  */
0117 #define FLUSH_FGRP (0xf << FLUSH_FGRP_BIT)
0118 #define FLUSH_GF (0x1 << FLUSH_GF_BIT)
0119 #define FLUSH_F (0x1 << FLUSH_F_BIT)
0120 
0121 #define FLUSH_FGRP_BIT 4
0122 #define FLUSH_GF_BIT 1
0123 #define FLUSH_F_BIT 0
0124 
0125 /*
0126  * GRIOMMU STATUS register fields 
0127  */
0128 #define STS_PE (0x1 << STS_PE_BIT)
0129 #define STS_DE (0x1 << STS_DE_BIT)
0130 #define STS_FC (0x1 << STS_FC_BIT)
0131 #define STS_FL (0x1 << STS_FL_BIT)
0132 #define STS_AD (0x1 << STS_AD_BIT)
0133 #define STS_TE (0x1 << STS_TE_BIT)
0134 #define STS_ALL (STS_PE | STS_DE | STS_FC | STS_FL | STS_AD | STS_TE)
0135 
0136 #define STS_PE_BIT 5
0137 #define STS_DE_BIT 4
0138 #define STS_FC_BIT 3
0139 #define STS_FL_BIT 2
0140 #define STS_AD_BIT 1
0141 #define STS_TE_BIT 0
0142 
0143 /*
0144  * GRIOMMU IMASK register fields 
0145  */
0146 #define IMASK_PEI (0x1 << IMASK_PEI_BIT)
0147 #define IMASK_FCI (0x1 << IMASK_FCI_BIT)
0148 #define IMASK_FLI (0x1 << IMASK_FLI_BIT)
0149 #define IMASK_ADI (0x1 << IMASK_ADI_BIT)
0150 #define IMASK_TEI (0x1 << IMASK_TEI_BIT)
0151 #define IMASK_ALL (IMASK_PEI | IMASK_FCI | IMASK_FLI | IMASK_ADI | IMASK_TEI)
0152 
0153 #define IMASK_PEI_BIT 5
0154 #define IMASK_FCI_BIT 3
0155 #define IMASK_FLI_BIT 2
0156 #define IMASK_ADI_BIT 1
0157 #define IMASK_TEI_BIT 0
0158 
0159 /*
0160  * GRIOMMU MASTER register fields 
0161  */
0162 /* DEFINED IN HEADER FILE 
0163 #define MASTER_VENDOR (0xff << MASTER_VENDOR_BIT)
0164 #define MASTER_DEVICE (0xfff << MASTER_DEVICE_BIT)
0165 #define MASTER_BS (0x1 << MASTER_BS_BIT)
0166 #define MASTER_GROUP (0xf << MASTER_GROUP_BIT)
0167 
0168 #define MASTER_VENDOR_BIT 24
0169 #define MASTER_DEVICE_BIT 12
0170 #define MASTER_BS_BIT 4
0171 #define MASTER_GROUP_BIT 0
0172 */
0173 
0174 #define MASTER_BS_BUS0 0
0175 #define MASTER_BS_BUS1 MASTER_BS
0176 
0177 /*
0178  * GRIOMMU GROUP register fields 
0179  */
0180 #define GRP_BASE (0xfffffff << GRP_BASE_BIT)
0181 #define GRP_P (0x1 << GRP_P_BIT)
0182 #define GRP_AG (0x1 << GRP_AG_BIT)
0183 
0184 #define GRP_BASE_BIT 4
0185 #define GRP_P_BIT 1
0186 #define GRP_AG_BIT 0
0187 
0188 
0189 #define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val))
0190 #define REG_READ(addr) (*(volatile unsigned int *)(addr))
0191 
0192 /*
0193  * GRIOMMU APB Register MAP
0194  */
0195 struct griommu_regs {
0196     volatile unsigned int cap0;         /* 0x00 - Capability 0 */
0197     volatile unsigned int cap1;         /* 0x04 - Capability 1 */
0198     volatile unsigned int cap2;         /* 0x08 - Capability 2 */
0199     volatile unsigned int resv1;        /* 0x0c - Reserved */
0200     volatile unsigned int ctrl;         /* 0x10 - Control */
0201     volatile unsigned int flush;        /* 0x14 - TLB/cache flush */
0202     volatile unsigned int status;       /* 0x18 - Status */
0203     volatile unsigned int imask;        /* 0x1c - Interrupt mask */
0204     volatile unsigned int ahbstat;      /* 0x20 - AHB Failing Access */
0205     volatile unsigned int resv2[7];     /* 0x24-0x3c - Reserved. No access */
0206     volatile unsigned int master[16];   /* 0x40-0x7c - Master configuration */
0207     volatile unsigned int grp_ctrl[16]; /* 0x80-0xbc - Group control */
0208     volatile unsigned int diag_ca;      /* 0xc0 - Diagnostic cache access */
0209     volatile unsigned int diag_cad[8];  /* 0xc4-0xe0 - Diagnostic cache data */
0210     volatile unsigned int diag_cat;     /* 0xe4 - Diagnostic cache tag */
0211     volatile unsigned int ei_data;      /* 0xe8 - Data RAM error injection */
0212     volatile unsigned int ei_tag;       /* 0xec - Tag RAM error injection */
0213     volatile unsigned int resv3[4];     /* 0xf0-0xfc - Reserved. No access */
0214     volatile unsigned int asmpctrl[16]; /* 0x100-0x13c - ASMP access control */
0215 };
0216 
0217 #define DEVNAME_LEN 9
0218 /*
0219  * GRIOMMU Driver private data struture
0220  */
0221 struct griommu_priv {
0222     struct drvmgr_dev   *dev;
0223     char devname[DEVNAME_LEN];
0224     /* GRIOMMU control registers */
0225     struct griommu_regs *regs;
0226 
0227     /* GRIOMMU capabilities */
0228     int apv;
0229     int apv_cache;
0230     int apv_cache_addr;
0231     int conf_pagesize;
0232 
0233     int groups;
0234     int masters;
0235 
0236     /* GRIOMMU page size */
0237     int pagesize;
0238 
0239     /* GRIOMMU APV cache */
0240     int cache_enabled;
0241     int group_addressing;
0242 
0243     /* User defined ISR */
0244     griommu_isr_t isr;
0245     void *isr_arg;
0246 };
0247 
0248 /*
0249  * GRIOMMU internal prototypes 
0250  */
0251 /* -Register access functions */
0252 STATIC INLINE unsigned int griommu_reg_cap0(void);
0253 STATIC INLINE unsigned int griommu_reg_cap1(void);
0254 STATIC INLINE unsigned int griommu_reg_ctrl(void);
0255 STATIC INLINE int griommu_reg_ctrl_set(unsigned int val);
0256 STATIC INLINE int griommu_reg_flush_set(unsigned int val);
0257 STATIC INLINE unsigned int griommu_reg_status(void);
0258 STATIC INLINE int griommu_reg_status_clear(unsigned int val);
0259 STATIC INLINE unsigned int griommu_reg_imask(void);
0260 STATIC INLINE int griommu_reg_imask_set(int mask);
0261 STATIC INLINE unsigned int griommu_reg_ahbfas(void);
0262 STATIC INLINE unsigned int griommu_reg_master(int master);
0263 STATIC INLINE int griommu_reg_master_set(int master, unsigned int val);
0264 STATIC INLINE unsigned int griommu_reg_group(int group);
0265 STATIC INLINE int griommu_reg_group_set(int group, unsigned int val);
0266 
0267 /* APV helper functions */
0268 STATIC void griommu_apv_set_word(unsigned int * wordptr, int startbitidx, 
0269         int nbits, unsigned int val);
0270 STATIC int griommu_apv_set(void * apv, int index, int size, unsigned int val);
0271 
0272 /* -Init function called by drvmgr */
0273 int griommu_init1(struct drvmgr_dev *dev);
0274 STATIC int griommu_init(struct griommu_priv *priv);
0275 
0276 
0277 /* -IRQ handler */
0278 void griommu_isr(void *arg);
0279 
0280 /*
0281  * GRIOMMU static members 
0282  */
0283 static struct griommu_priv *griommupriv = NULL;
0284 
0285 /* GRIOMMU DRIVER */
0286 
0287 struct drvmgr_drv_ops griommu_ops = 
0288 {
0289     .init = {griommu_init1, NULL, NULL, NULL},
0290     .remove = NULL,
0291     .info = NULL
0292 };
0293 
0294 struct amba_dev_id griommu_ids[] = 
0295 {
0296     {VENDOR_GAISLER, GAISLER_GRIOMMU},
0297     {0, 0}      /* Mark end of table */
0298 };
0299 
0300 struct amba_drv_info griommu_info =
0301 {
0302     {
0303         DRVMGR_OBJ_DRV,                 /* Driver */
0304         NULL,               /* Next driver */
0305         NULL,               /* Device list */
0306         DRIVER_AMBAPP_GAISLER_GRIOMMU_ID,/* Driver ID */
0307         "GRIOMMU_DRV",          /* Driver Name */
0308         DRVMGR_BUS_TYPE_AMBAPP,     /* Bus Type */
0309         &griommu_ops,
0310         NULL,               /* Funcs */
0311         0,              /* No devices yet */
0312         sizeof(struct griommu_priv),    /* Make drvmgr alloc private */
0313     },
0314     &griommu_ids[0]
0315 };
0316 
0317 void griommu_register_drv(void)
0318 {
0319     DBG("Registering GRIOMMU driver\n");
0320     drvmgr_drv_register(&griommu_info.general);
0321 }
0322 
0323 /* Initializes the GRIOMMU core and driver
0324  *
0325  * Return values
0326  *  0             Successful initalization
0327  */
0328 STATIC int griommu_init(struct griommu_priv *priv)
0329 {
0330     struct ambapp_ahb_info *ahb;
0331     struct amba_dev_info *ainfo = priv->dev->businfo;
0332 
0333     /* Find GRIOMMU core from Plug&Play information */
0334     ahb = ainfo->info.ahb_slv;
0335 
0336     /* Found GRIOMMU core, init private structure */
0337     priv->regs = (struct griommu_regs *)ahb->start[0];
0338 
0339     /* Mask all interrupts */
0340     griommu_reg_imask_set(0);
0341 
0342     /* Initialize GRIOMMU capabilities */
0343     uint32_t cap0 = griommu_reg_cap0();
0344     priv->apv = (cap0 & CAP0_A) >> CAP0_A_BIT;
0345     priv->apv_cache = (cap0 & CAP0_AC) >> CAP0_AC_BIT;
0346     priv->apv_cache_addr = (cap0 & CAP0_CA) >> CAP0_CA_BIT;
0347     priv->conf_pagesize = (cap0 & CAP0_CS) >> CAP0_CS_BIT;
0348     priv->groups = ((cap0 & CAP0_GRPS) >> CAP0_GRPS_BIT) + 1;
0349     priv->masters = ((cap0 & CAP0_MSTS) >> CAP0_MSTS_BIT) + 1;
0350 
0351     /* Get GRIOMMU pagesize */
0352     uint32_t ctrl = griommu_reg_ctrl();
0353     if (priv->conf_pagesize){
0354         priv->pagesize = (4*1024 << ((ctrl & CTRL_PGSZ) >> CTRL_PGSZ_BIT));
0355     }else{
0356         priv->pagesize = 4*1024;
0357     }
0358     priv->cache_enabled = (ctrl & CTRL_CE);
0359     priv->group_addressing = (ctrl & CTRL_GS);
0360 
0361     DBG("GRIOMMU Capabilities: APV=%d, APVC=%d, APVCA=%d, CS=%d, "
0362             "GRPS=%d, MSTS=%d\n",
0363             priv->apv, priv->apv_cache, priv->apv_cache_addr, 
0364             priv->conf_pagesize, priv->groups, priv->masters);
0365     DBG("GRIOMMU driver initialized\n");
0366 
0367     return 0;
0368 }
0369 
0370 /* Called when a core is found with the AMBA device and vendor ID 
0371  * given in griommu_ids[]. IRQ, Console does not work here
0372  */
0373 int griommu_init1(struct drvmgr_dev *dev)
0374 {
0375     int status;
0376     struct griommu_priv *priv;
0377 
0378     DBG("GRIOMMU[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0379 
0380     if (griommupriv) {
0381         DBG("Driver only supports one GRIOMMU core\n");
0382         return DRVMGR_FAIL;
0383     }
0384 
0385     priv = dev->priv;
0386     if (!priv)
0387         return DRVMGR_NOMEM;
0388 
0389     priv->dev = dev;
0390     strncpy(&priv->devname[0], "griommu0", DEVNAME_LEN);
0391     griommupriv = priv;
0392 
0393     /* Initialize GRIOMMU Hardware */
0394     status = griommu_init(priv);
0395     if (status) {
0396         printk("Failed to initialize griommu driver %d\n", status);
0397         return -1;
0398     }
0399 
0400     return DRVMGR_OK;
0401 }
0402 
0403 STATIC INLINE unsigned int griommu_reg_cap0(void)
0404 {
0405     struct griommu_priv *priv = griommupriv;
0406 
0407     return REG_READ(&priv->regs->cap0);
0408 }
0409 
0410 STATIC INLINE unsigned int griommu_reg_cap1(void)
0411 {
0412     struct griommu_priv *priv = griommupriv;
0413 
0414     return REG_READ(&priv->regs->cap1);
0415 }
0416 
0417 STATIC INLINE unsigned int griommu_reg_ctrl(void)
0418 {
0419     struct griommu_priv *priv = griommupriv;
0420 
0421     return REG_READ(&priv->regs->ctrl);
0422 }
0423 
0424 STATIC INLINE int griommu_reg_ctrl_set(unsigned int val)
0425 {
0426     struct griommu_priv *priv = griommupriv;
0427 
0428     REG_WRITE(&priv->regs->ctrl, val);
0429     return 0;
0430 }
0431 
0432 STATIC INLINE int griommu_reg_flush_set(unsigned int val)
0433 {
0434     struct griommu_priv *priv = griommupriv;
0435 
0436     REG_WRITE(&priv->regs->flush, val);
0437     return 0;
0438 }
0439 
0440 STATIC INLINE unsigned int griommu_reg_status(void)
0441 {
0442     struct griommu_priv *priv = griommupriv;
0443 
0444    return REG_READ(&priv->regs->status);
0445 }
0446 
0447 STATIC INLINE int griommu_reg_status_clear(unsigned int val)
0448 {
0449     struct griommu_priv *priv = griommupriv;
0450 
0451     /* Clear errors */
0452     REG_WRITE(&priv->regs->status, (val & STS_ALL));
0453     return 0;
0454 }
0455 
0456 STATIC INLINE unsigned int griommu_reg_imask(void)
0457 {
0458     struct griommu_priv *priv = griommupriv;
0459 
0460    return REG_READ(&priv->regs->imask);
0461 }
0462 
0463 STATIC INLINE int griommu_reg_imask_set(int mask)
0464 {
0465     struct griommu_priv *priv = griommupriv;
0466 
0467     /* Clear errors */
0468     REG_WRITE(&priv->regs->imask, (mask & IMASK_ALL));
0469     return 0;
0470 }
0471 
0472 STATIC INLINE unsigned int griommu_reg_ahbfas(void)
0473 {
0474     struct griommu_priv *priv = griommupriv;
0475 
0476    return REG_READ(&priv->regs->ahbstat);
0477 }
0478 
0479 STATIC INLINE int griommu_reg_master_set(int master, unsigned int val)
0480 {
0481     struct griommu_priv *priv = griommupriv;
0482 
0483     /* Change master conf */
0484     REG_WRITE(&priv->regs->master[master], val);
0485     return 0;
0486 }
0487 
0488 STATIC INLINE unsigned int griommu_reg_master(int master)
0489 {
0490     struct griommu_priv *priv = griommupriv;
0491 
0492     return REG_READ(&priv->regs->master[master]);
0493 }
0494 
0495 STATIC INLINE unsigned int griommu_reg_group(int group)
0496 {
0497     struct griommu_priv *priv = griommupriv;
0498 
0499     return REG_READ(&priv->regs->grp_ctrl[group]);
0500 }
0501 
0502 STATIC INLINE int griommu_reg_group_set(int group, unsigned int val)
0503 {
0504     struct griommu_priv *priv = griommupriv;
0505 
0506     REG_WRITE(&priv->regs->grp_ctrl[group], val);
0507     return 0;
0508 }
0509 
0510 STATIC void griommu_apv_set_word(unsigned int * wordptr, int startbitidx, 
0511         int nbits, unsigned int val)
0512 {
0513     unsigned int mask;
0514     unsigned int word = *wordptr;
0515     int endbitidx = startbitidx + nbits - 1;
0516 
0517     /* Set initial mask */
0518     mask = 0xffffffff;
0519 
0520     /* Adjust mask for the starting bit */
0521     mask >>= startbitidx;
0522 
0523     /* Adjust mask for the end bit */
0524     mask >>= (31 - endbitidx);
0525     mask <<= (31 - endbitidx);
0526 
0527     DBG("Setting word: startbitdx=%d, endbitidx=%d, mask=0x%02x",
0528             startbitidx, endbitidx, (unsigned int) mask);
0529 
0530     /* Clear written bits with mask */
0531     word &= ~(mask);
0532 
0533     /* Set bits in val with mask */
0534     mask &= val;
0535     word |= mask;
0536 
0537     DBG(", old word=0x%08x, new word=0x%08x\n",*wordptr, word);
0538 
0539     /* Write word */
0540     *wordptr=word;
0541 }
0542 
0543 /* Set certains bits of the APV to val */
0544 STATIC int griommu_apv_set(void * apv, int index, int size, unsigned int val)
0545 {
0546     unsigned int * words = (unsigned int *) apv;
0547     int len = size;
0548     int wordidx = (index/32);
0549     int startbit = (index % 32);
0550     int nbits;
0551     int nwords;
0552 
0553     /* First incomplete word is a special case */
0554     if (startbit != 0){
0555         /* Get how many bits are we changing in this word */
0556         if (startbit + len  < 32){
0557             nbits = len;
0558         }else{
0559             nbits = 32 - startbit;
0560         }
0561         griommu_apv_set_word(&words[wordidx], startbit, nbits, val);
0562         DBG("First word: wordidx=%d, startbit=%d, bits=%d, val=0x%08x\n", 
0563                 wordidx, startbit, nbits, words[wordidx]);
0564 
0565         /* Update wordidx and len */
0566         len = len - nbits;
0567         wordidx++;
0568     }
0569 
0570     /* Write all complete full words */
0571     if (len != 0){
0572         nwords = (len/32);
0573         memset((void *) &words[wordidx], val, nwords*4);
0574         DBG("Middle words: wordidx=%d, nwords=%d\n", wordidx, nwords);
0575         /* Update wordidx and len*/
0576         wordidx = wordidx + nwords;
0577         len = len - nwords*32;
0578     }
0579 
0580     /* Last word is a special case */
0581     if (len != 0){
0582         nbits = len;
0583         griommu_apv_set_word(&words[wordidx], 0, nbits, val);
0584         DBG("First word: wordidx=%d, startbit=%d, bits=%d, val=0x%08x\n", 
0585                 wordidx, 0, nbits, words[wordidx]);
0586         /* Update len */
0587         len = len - (nbits);
0588     }
0589 
0590     return GRIOMMU_ERR_OK;
0591 }
0592 
0593 /* GRIOMMU Interrupt handler, called when there may be a GRIOMMU interrupt.
0594  */
0595 void griommu_isr(void *arg)
0596 {
0597     struct griommu_priv *priv = arg;
0598     unsigned int sts = griommu_reg_status();
0599     unsigned int mask = griommu_reg_imask();
0600     unsigned int access = griommu_reg_ahbfas();
0601 
0602     /* Make sure that the interrupt is pending and unmasked,
0603      * otherwise it migth have been other core
0604      * sharing the same interrupt line */
0605     if ((sts & STS_ALL) & (mask & IMASK_ALL)){
0606         /* Reset error status */
0607         griommu_reg_status_clear(sts);
0608         /* Execute user IRQ (ther will always be one ISR */
0609         (priv->isr)(priv->isr_arg, access, sts);
0610     }
0611 }
0612 
0613 /* Setup IOMMU master:
0614  */
0615 int griommu_master_setup(int master, int group, int options)
0616 {
0617     struct griommu_priv * priv = griommupriv;
0618 
0619     if (priv == NULL){
0620         DBG("GRIOMMU not initialized.\n");
0621         return GRIOMMU_ERR_NOINIT;
0622     }
0623 
0624     if ((master < 0) || (master >= priv->masters)){
0625         DBG("Wrong master id.\n");
0626         return GRIOMMU_ERR_EINVAL;
0627     }
0628 
0629     if ((group < 0) || (group >= priv->groups)){
0630         DBG("Wrong group id.\n");
0631         return GRIOMMU_ERR_EINVAL;
0632     }
0633 
0634     griommu_reg_master_set(master,
0635             ((options & GRIOMMU_OPTIONS_BUS1)? MASTER_BS_BUS1: MASTER_BS_BUS0)|
0636             ((group << MASTER_GROUP_BIT) & MASTER_GROUP)
0637             );
0638 
0639     DBG("IOMMU master setup: master %d, traffic routed %s, group %d\n",
0640             master,
0641             (options & GRIOMMU_OPTIONS_BUS1) ? 
0642                     "to Secondary bus":"to Primary bus",
0643             group);
0644 
0645     return GRIOMMU_ERR_OK;
0646 }
0647 
0648 
0649 /* Get IOMMU master info:
0650  */
0651 int griommu_master_info(int master, uint32_t * info)
0652 {
0653     struct griommu_priv * priv = griommupriv;
0654 
0655     if (priv == NULL){
0656         DBG("GRIOMMU not initialized.\n");
0657         return GRIOMMU_ERR_NOINIT;
0658     }
0659 
0660     if ((master < 0) || (master >= priv->masters)){
0661         DBG("Wrong master id.\n");
0662         return GRIOMMU_ERR_EINVAL;
0663     }
0664 
0665     if (info == NULL){
0666         DBG("Wrong pointer.\n");
0667         return GRIOMMU_ERR_EINVAL;
0668     }
0669 
0670     /* Get master */
0671     *info = griommu_reg_master(master);
0672 
0673     return GRIOMMU_ERR_OK;
0674 }
0675 
0676 /* Find IOMMU master:
0677  */
0678 int griommu_master_find(int vendor, int device, int instance)
0679 {
0680     struct griommu_priv * priv = griommupriv;
0681     int i, gotvendor, gotdevice;
0682     unsigned int master;
0683     int found;
0684 
0685     if (priv == NULL){
0686         DBG("GRIOMMU not initialized.\n");
0687         return GRIOMMU_ERR_NOINIT;
0688     }
0689 
0690     /* Find which master */
0691     found=0;
0692     for (i=0; i< priv->masters; i++){
0693         master = griommu_reg_master(i);
0694         gotvendor = (master & MASTER_VENDOR) >> MASTER_VENDOR_BIT;
0695         gotdevice = (master & MASTER_DEVICE) >> MASTER_DEVICE_BIT;
0696         if ((gotvendor == vendor) && (gotdevice == device)){
0697             if(found == instance){
0698                 DBG("Found master %d: VENDOR=%s(0x%02x), DEVICE=%s(0x%03x), "
0699                     "Instance=%d\n",
0700                     i,
0701                     ambapp_vendor_id2str(vendor), vendor,
0702                     ambapp_device_id2str(vendor,device), device, instance
0703                     );
0704                 return i;
0705             }
0706             found++;
0707         }
0708     }
0709 
0710     DBG("Master not found: VENDOR=%s(0x%02x), DEVICE=%s(0x%03x), "
0711         "Instance=%d\n",
0712         ambapp_vendor_id2str(vendor), vendor,
0713         ambapp_device_id2str(vendor,device), device, instance
0714         );
0715     return GRIOMMU_ERR_NOTFOUND;
0716 }
0717 
0718 /* Setup IOMMU:
0719  */
0720 int griommu_setup(int options)
0721 {
0722     struct griommu_priv * priv = griommupriv;
0723     unsigned int ctrl;
0724 
0725     if (priv == NULL){
0726         DBG("GRIOMMU not initialized.\n");
0727         return GRIOMMU_ERR_NOINIT;
0728     }
0729 
0730     /* Check Cache */
0731     if (options & GRIOMMU_OPTIONS_CACHE_ENABLE) {
0732         if (priv->apv_cache){
0733             /* Flush cache */
0734             griommu_reg_flush_set(FLUSH_F);
0735             priv->cache_enabled = 1;
0736         }else{
0737             DBG("GRIOMMU APV cache not supported.\n");
0738             return GRIOMMU_ERR_IMPLEMENTED;
0739         }
0740     }else{
0741         priv->cache_enabled = 0;
0742     }
0743 
0744     /* Check group addressing */
0745     if (options & GRIOMMU_OPTIONS_GROUPADDRESSING_ENABLE){
0746         if (priv->apv_cache_addr){
0747             priv->group_addressing = 1;
0748         }else{
0749             DBG("GRIOMMU APV cache group addressing not supported.\n");
0750             return GRIOMMU_ERR_IMPLEMENTED;
0751         }
0752     }else{
0753         priv->group_addressing = 0;
0754     }
0755 
0756     /* Check pagesize */
0757     if ((options & CTRL_PGSZ) != GRIOMMU_OPTIONS_PAGESIZE_4KIB){
0758         if (priv->conf_pagesize == 0){
0759             DBG("GRIOMMU Configurable pagesize not supported.\n");
0760             return GRIOMMU_ERR_IMPLEMENTED;
0761         }
0762     }
0763 
0764     /* Get CTRL IOMMU */
0765     ctrl = griommu_reg_ctrl();
0766 
0767     /* Clear used fields */
0768     ctrl &= ~(CTRL_CE | CTRL_GS | CTRL_PGSZ | CTRL_LB | 
0769             CTRL_DP | CTRL_AU | CTRL_WP);
0770 
0771     /* Clear not used fields */
0772     options &= (CTRL_CE | CTRL_GS | CTRL_PGSZ | CTRL_LB | 
0773             CTRL_DP | CTRL_AU | CTRL_WP);
0774 
0775     /* Set new values */
0776     ctrl |= options;
0777 
0778     /* Set CTRL IOMMU */
0779     griommu_reg_ctrl_set(ctrl);
0780 
0781     DBG("IOMMU setup: prefetching %s, cache %s, groupaddr %s, "
0782         "lookup bus %s, ahb update %s,\nwprot only %s, pagesize %d KiB\n",
0783             ((options & GRIOMMU_OPTIONS_PREFETCH_DISABLE)? 
0784                     "disabled":"enabled"),
0785             ((options & GRIOMMU_OPTIONS_CACHE_ENABLE)? "enabled":"disabled"),
0786             ((options & GRIOMMU_OPTIONS_GROUPADDRESSING_ENABLE)? 
0787                     "enabled":"disabled"),
0788             ((options & GRIOMMU_OPTIONS_LOOKUPBUS_BUS1)? "bus1":"bus0"),
0789             ((options & GRIOMMU_OPTIONS_AHBUPDATE_ENABLE)? 
0790                     "enabled":"disabled"),
0791             ((options & GRIOMMU_OPTIONS_WPROTONLY_ENABLE)? 
0792                     "enabled":"disabled"),
0793             (4 << ((options & GRIOMMU_OPTIONS_PAGESIZE_512KIB) >> 18))
0794         );
0795 
0796     return GRIOMMU_ERR_OK;
0797 }
0798 
0799 /* Status IOMMU:
0800  */
0801 int griommu_status(void)
0802 {
0803     struct griommu_priv * priv = griommupriv;
0804     unsigned int ctrl;
0805 
0806     if (priv == NULL){
0807         DBG("GRIOMMU not initialized.\n");
0808         return GRIOMMU_ERR_NOINIT;
0809     }
0810 
0811     /* Get CTRL IOMMU */
0812     ctrl = griommu_reg_ctrl();
0813 
0814     DBG("IOMMU status: prefetching %s, cache %s, groupaddr %s, "
0815         "lookup bus %s, ahb update %s,\nwprot only %s, pagesize %d KiB\n",
0816             ((ctrl & CTRL_DP)? "disabled":"enabled"),
0817             ((ctrl & CTRL_CE)? "enabled":"disabled"),
0818             ((ctrl & CTRL_GS)? "enabled":"disabled"),
0819             ((ctrl & CTRL_LB)? "bus1":"bus0"),
0820             ((ctrl & CTRL_AU)? "enabled":"disabled"),
0821             ((ctrl & CTRL_WP)? "enabled":"disabled"),
0822             (4 << ((ctrl & CTRL_PGSZ) >> CTRL_PGSZ_BIT))
0823         );
0824 
0825     return ctrl;
0826 }
0827 
0828 int griommu_isr_register(griommu_isr_t isr, void * arg, int options)
0829 {
0830     struct griommu_priv *priv = griommupriv;
0831     unsigned int mask;
0832 
0833     if (priv == NULL){
0834         DBG("GRIOMMU not initialized.\n");
0835         return GRIOMMU_ERR_NOINIT;
0836     }
0837 
0838     if (isr == NULL){
0839         DBG("GRIOMMU wrong isr.\n");
0840         return GRIOMMU_ERR_EINVAL;
0841     }
0842 
0843     /* Get mask */
0844     mask = 0 |
0845         ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
0846         ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
0847         ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
0848         ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
0849         ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
0850 
0851     /* Clear previous interrupts and mask them*/
0852     griommu_reg_status_clear(STS_ALL);
0853     griommu_reg_imask_set(0);
0854 
0855     /* First time registering an ISR */
0856     if (priv->isr == NULL){
0857         /* Install and Enable GRIOMMU interrupt handler */
0858         drvmgr_interrupt_register(priv->dev, 0, priv->devname, griommu_isr, 
0859                 priv);
0860     }
0861 
0862     /* Install user ISR */
0863     priv->isr=isr;
0864     priv->isr_arg=arg;
0865 
0866     /* Now it is safe to unmask interrupts */
0867     griommu_reg_imask_set(mask);
0868 
0869     return GRIOMMU_ERR_OK;
0870 }
0871 
0872 int griommu_isr_unregister(void)
0873 {
0874     struct griommu_priv *priv = griommupriv;
0875 
0876     if (priv == NULL){
0877         DBG("GRIOMMU not initialized.\n");
0878         return GRIOMMU_ERR_NOINIT;
0879     }
0880 
0881     if (priv->isr == NULL){
0882         DBG("GRIOMMU wrong isr.\n");
0883         return GRIOMMU_ERR_EINVAL;
0884     }
0885 
0886     /* Clear previous interrupts and mask them*/
0887     griommu_reg_status_clear(STS_ALL);
0888     griommu_reg_imask_set(0);
0889 
0890     /* Uninstall and disable GRIOMMU interrupt handler */
0891     drvmgr_interrupt_unregister(priv->dev, 0, griommu_isr, priv);
0892 
0893     /* Uninstall user ISR */
0894     priv->isr=NULL;
0895     priv->isr_arg=NULL;
0896 
0897     return GRIOMMU_ERR_OK;
0898 }
0899 
0900 int griommu_interrupt_unmask(int options)
0901 {
0902     struct griommu_priv *priv = griommupriv;
0903     unsigned int mask, irq;
0904 
0905     if (priv == NULL){
0906         DBG("GRIOMMU not initialized.\n");
0907         return GRIOMMU_ERR_NOINIT;
0908     }
0909 
0910     if (priv->isr == NULL){
0911         DBG("GRIOMMU wrong isr.\n");
0912         return GRIOMMU_ERR_EINVAL;
0913     }
0914 
0915     /* Unmask interrupts in GRIOMMU */
0916     mask = 0 |
0917         ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
0918         ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
0919         ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
0920         ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
0921         ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
0922 
0923     /* Clear previous interrupts*/
0924     griommu_reg_status_clear(STS_ALL);
0925 
0926     /* Get previous mask */
0927     irq = griommu_reg_imask() & IMASK_ALL;
0928 
0929     /* Set new mask */
0930     griommu_reg_imask_set(irq | mask);
0931 
0932     return GRIOMMU_ERR_OK;
0933 }
0934 
0935 int griommu_interrupt_mask(int options)
0936 {
0937     struct griommu_priv *priv = griommupriv;
0938     unsigned int mask, irq;
0939 
0940     if (priv == NULL){
0941         DBG("GRIOMMU not initialized.\n");
0942         return GRIOMMU_ERR_NOINIT;
0943     }
0944 
0945     if (priv->isr == NULL){
0946         DBG("GRIOMMU wrong isr.\n");
0947         return GRIOMMU_ERR_EINVAL;
0948     }
0949 
0950     /* Mask interrupts in GRIOMMU */
0951     mask = 0 |
0952         ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
0953         ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
0954         ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
0955         ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
0956         ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
0957 
0958     /* Clear previous interrupts*/
0959     griommu_reg_status_clear(STS_ALL);
0960 
0961     /* Get previous mask */
0962     irq = griommu_reg_imask() & IMASK_ALL;
0963 
0964     /* Set new mask */
0965     griommu_reg_imask_set(irq & ~(mask));
0966 
0967     return GRIOMMU_ERR_OK;
0968 }
0969 
0970 int griommu_error_status(uint32_t * access)
0971 {
0972     struct griommu_priv *priv = griommupriv;
0973     int status;
0974 
0975     if (priv == NULL){
0976         DBG("GRIOMMU not initialized.\n");
0977         return GRIOMMU_ERR_NOINIT;
0978     }
0979 
0980     /* Get status mask */
0981     status = griommu_reg_status();
0982 
0983     if (status != 0){
0984         /* Update pointed value */
0985         if (access != NULL){
0986             *access = griommu_reg_ahbfas();
0987         }
0988         /* Clear errors */
0989         griommu_reg_status_clear(status);
0990     }
0991 
0992     return status;
0993 }
0994 
0995 /* Print IOMMU masters
0996  * DEBUG function
0997  */
0998 int griommu_print(void)
0999 {
1000     #ifdef DEBUG
1001     struct griommu_priv * priv = griommupriv;
1002     unsigned int ctrl;
1003 
1004     if (priv == NULL){
1005         DBG("GRIOMMU not initialized.\n");
1006         return GRIOMMU_ERR_NOINIT;
1007     }
1008 
1009     /* Print IOMMU status */
1010     ctrl = griommu_reg_ctrl();
1011 
1012     printf("IOMMU status: prefetching %s, lookup bus %s, ahb update %s,\n"
1013             "wprot only %s, pagesize %d KiB\n",
1014             ((ctrl & CTRL_DP)? "disabled":"enabled"),
1015             ((ctrl & CTRL_LB)? "bus1":"bus0"),
1016             ((ctrl & CTRL_AU)? "enabled":"disabled"),
1017             ((ctrl & CTRL_WP)? "enabled":"disabled"),
1018             (4 << ((ctrl & CTRL_PGSZ) >> CTRL_PGSZ_BIT))
1019         );
1020 
1021     /* Print each master configuration */
1022     int i, vendor, device, routing;
1023     unsigned int master;
1024     for (i=0; i < priv->masters; i++){
1025         master = griommu_reg_master(i);
1026         vendor = (master & MASTER_VENDOR) >> MASTER_VENDOR_BIT;
1027         device = (master & MASTER_DEVICE) >> MASTER_DEVICE_BIT;
1028         routing = (master & MASTER_BS);
1029         printf("IOMMU master %d: VENDOR=%s(0x%02x), DEVICE=%s(0x%03x), "
1030                 "BS=%s\n",
1031                 i,
1032                 ambapp_vendor_id2str(vendor), vendor,
1033                 ambapp_device_id2str(vendor,device), device,
1034                 (routing == MASTER_BS_BUS0? "Primary bus" : "Secondary bus")
1035                 );
1036     }
1037     #endif
1038     return GRIOMMU_ERR_OK;
1039 }
1040 
1041 void * griommu_apv_new(void)
1042 {
1043     struct griommu_priv * priv = griommupriv;
1044 
1045     if (priv == NULL){
1046         DBG("GRIOMMU not initialized.\n");
1047         return NULL;
1048     }
1049 
1050     /* Allocate APV */
1051     unsigned int * orig_ptr = grlib_malloc(
1052             (GRIOMMU_APV_SIZE/priv->pagesize) + GRIOMMU_APV_ALIGN);
1053     if (orig_ptr == NULL) return NULL;
1054 
1055     /* Get the aligned pointer */
1056     unsigned int aligned_ptr = (
1057         ((unsigned int) orig_ptr + GRIOMMU_APV_ALIGN) &
1058         ~(GRIOMMU_APV_ALIGN - 1));
1059 
1060     /* Save the original pointer before the aligned pointer */
1061     unsigned int ** tmp_ptr = 
1062         (unsigned int **) (aligned_ptr - sizeof(orig_ptr));
1063     *tmp_ptr= orig_ptr;
1064 
1065     /* Return aligned pointer */
1066     return (void *) aligned_ptr;
1067 }
1068 
1069 void griommu_apv_delete(void * apv)
1070 {
1071     /* Recover orignal pointer placed just before the aligned pointer */
1072     unsigned int * orig_ptr;
1073     unsigned int ** tmp_ptr =  (unsigned int **) (apv - sizeof(orig_ptr));
1074     orig_ptr = *tmp_ptr;
1075 
1076     /* Deallocate memory */
1077     free(orig_ptr);
1078 }
1079 
1080 int griommu_enable(int mode)
1081 {
1082     struct griommu_priv * priv = griommupriv;
1083     unsigned int ctrl;
1084 
1085     if (priv == NULL){
1086         DBG("GRIOMMU not initialized.\n");
1087         return GRIOMMU_ERR_NOINIT;
1088     }
1089 
1090     switch (mode){
1091         case GRIOMMU_MODE_IOMMU:
1092         default:
1093             DBG("IOMMU mode not implemented in driver.\n");
1094             return GRIOMMU_ERR_EINVAL;
1095             break;
1096         case GRIOMMU_MODE_GROUPAPV:
1097             if (priv->apv == 0){
1098                 DBG("IOMMU APV not supported.\n");
1099                 return GRIOMMU_ERR_IMPLEMENTED;
1100             }
1101             /* Enable IOMMU */
1102             ctrl = (griommu_reg_ctrl() & ~(CTRL_PM));
1103             griommu_reg_ctrl_set(ctrl | CTRL_PM_APV | CTRL_EN);
1104 
1105             /* Wait until change has effect */
1106             while((griommu_reg_ctrl() & CTRL_EN)==0){};
1107 
1108             DBG("IOMMU enabled.\n");
1109             return GRIOMMU_ERR_OK;
1110             break;
1111     }
1112     return GRIOMMU_ERR_OK;
1113 }
1114 
1115 int griommu_disable(void)
1116 {
1117     struct griommu_priv * priv = griommupriv;
1118     unsigned int ctrl;
1119 
1120     if (priv == NULL){
1121         DBG("GRIOMMU not initialized.\n");
1122         return GRIOMMU_ERR_NOINIT;
1123     }
1124 
1125     /* Disable IOMMU */
1126     ctrl = (griommu_reg_ctrl() & ~(CTRL_EN));
1127     griommu_reg_ctrl_set(ctrl);
1128 
1129     /* Wait until change has effect */
1130     while(griommu_reg_ctrl() & CTRL_EN){};
1131 
1132     return GRIOMMU_ERR_OK;
1133 }
1134 
1135 int griommu_group_setup(int group, void * apv, int options)
1136 {
1137     struct griommu_priv * priv = griommupriv;
1138 
1139     if (priv == NULL){
1140         DBG("GRIOMMU not initialized.\n");
1141         return GRIOMMU_ERR_NOINIT;
1142     }
1143 
1144     if ((group < 0) || (group >= priv->groups)){
1145         DBG("Wrong group id.\n");
1146         return GRIOMMU_ERR_EINVAL;
1147     }
1148 
1149     if ((options < 0) || (options > GRIOMMU_OPTIONS_GROUP_PASSTHROUGH)){
1150         DBG("Wrong options.\n");
1151         return GRIOMMU_ERR_EINVAL;
1152     }
1153 
1154     if (options == GRIOMMU_OPTIONS_GROUP_DISABLE){
1155         if ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1)){
1156             DBG("Wrong pointer.\n");
1157             return GRIOMMU_ERR_EINVAL;
1158         }
1159 
1160         /* Disable GROUP */
1161         griommu_reg_group_set(group, (((unsigned int) apv) & GRP_BASE) | 0);
1162         DBG("GROUP[%d] DISABLED.\n", group);
1163         return GRIOMMU_ERR_OK;
1164     }else if (options == GRIOMMU_OPTIONS_GROUP_PASSTHROUGH){
1165         if ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1)){
1166             DBG("Wrong pointer.\n");
1167             return GRIOMMU_ERR_EINVAL;
1168         }
1169 
1170         /* Group in passthrough */
1171         griommu_reg_group_set(group, 
1172                 (((unsigned int) apv) & GRP_BASE) | GRP_P | GRP_AG);
1173         DBG("GROUP[%d] set to PASSTHROUGH.\n", group);
1174         return GRIOMMU_ERR_OK;
1175     }else{
1176         if (priv->apv == 0){
1177             DBG("IOMMU APV not supported.\n");
1178             return GRIOMMU_ERR_IMPLEMENTED;
1179         }
1180 
1181         if ((apv == NULL) || ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1))){
1182             DBG("Wrong pointer.\n");
1183             return GRIOMMU_ERR_EINVAL;
1184         }
1185 
1186         /* Set up base and enable */
1187         griommu_reg_group_set(group, 
1188                 (((unsigned int) apv) & GRP_BASE) | GRP_AG);
1189         DBG("GROUP[%d] set to APV (0x%08x).\n", group, (unsigned int) apv);
1190         return GRIOMMU_ERR_OK;
1191     }
1192 }
1193 
1194 int griommu_group_apv_init(int group, int options)
1195 {
1196     struct griommu_priv * priv = griommupriv;
1197     void * apv;
1198     int val;
1199     int ret;
1200     size_t len;
1201 
1202     /* Flush APV cache if needed.
1203      * This function checks for priv and group being valid.*/
1204     ret = griommu_group_apv_flush(group);
1205     if (ret < 0){
1206         return ret;
1207     }
1208 
1209     /* Get APV group */
1210     apv = (void *) (griommu_reg_group(group) & GRP_BASE);
1211 
1212     if (apv == NULL){
1213         DBG("Wrong pointer.\n");
1214         return GRIOMMU_ERR_NOTFOUND;
1215     }
1216 
1217     /* Get init value (is a char) */
1218     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1219         val = 0x00;
1220     }else{
1221         val = 0xff;
1222     }
1223 
1224     /* Get APV length */
1225     len = GRIOMMU_APV_SIZE/priv->pagesize;
1226 
1227     /* Initialize structure */
1228     memset(apv, val, len);
1229 
1230     return GRIOMMU_ERR_OK;
1231 }
1232 
1233 int griommu_group_apv_page_set(int group, int index, int size, int options)
1234 {
1235     void * apv;
1236     unsigned int val;
1237     int ret;
1238 
1239     /* Flush APV cache if needed.
1240      * This function checks for priv and group being valid.*/
1241     ret = griommu_group_apv_flush(group);
1242     if (ret < 0){
1243         return ret;
1244     }
1245 
1246     /* Get APV group */
1247     apv = (void *) (griommu_reg_group(group) & GRP_BASE);
1248 
1249     if (apv == NULL){
1250         DBG("Wrong pointer.\n");
1251         return GRIOMMU_ERR_NOTFOUND;
1252     }
1253 
1254     /* Get init value */
1255     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1256         val = 0x0;
1257     }else{
1258         val = 0xffffffff;
1259     }
1260 
1261     return griommu_apv_set(apv, index, size, val);
1262 }
1263 
1264 int griommu_group_apv_address_set(int group, uint32_t addr, int size, 
1265         int options)
1266 {
1267     struct griommu_priv * priv = griommupriv;
1268     void * apv;
1269     unsigned int val;
1270     int ret;
1271     int startpage;
1272     int endpage;
1273     int npages;
1274 
1275     /* Flush APV cache if needed.
1276      * This function checks for priv and group being valid.*/
1277     ret = griommu_group_apv_flush(group);
1278     if (ret < 0){
1279         return ret;
1280     }
1281 
1282     /* Get APV group */
1283     apv = (void *) (griommu_reg_group(group) & GRP_BASE);
1284 
1285     if (apv == NULL){
1286         DBG("Wrong pointer.\n");
1287         return GRIOMMU_ERR_NOTFOUND;
1288     }
1289 
1290     /* Get init value */
1291     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1292         val = 0x0;
1293     }else{
1294         val = 0xffffffff;
1295     }
1296 
1297     /* Get start page */
1298     startpage = (addr / priv->pagesize);
1299 
1300     /* Get end page */
1301     endpage = ((addr + size)/ priv->pagesize);
1302 
1303     /* Get number of pages */
1304     npages = endpage - startpage + 1;
1305 
1306     return griommu_apv_set(apv, startpage, npages, val);
1307 }
1308 
1309 int griommu_apv_init(void * apv, int options)
1310 {
1311     struct griommu_priv * priv = griommupriv;
1312     int val;
1313     size_t len;
1314 
1315     if (priv == NULL){
1316         DBG("GRIOMMU not initialized.\n");
1317         return GRIOMMU_ERR_NOINIT;
1318     }
1319 
1320     if ((apv == NULL) || ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1))){
1321         DBG("Wrong pointer.\n");
1322         return GRIOMMU_ERR_EINVAL;
1323     }
1324 
1325     /* Get init value (is a char) */
1326     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1327         val = 0x00;
1328     }else{
1329         val = 0xff;
1330     }
1331 
1332     /* Get APV length */
1333     len = GRIOMMU_APV_SIZE/priv->pagesize;
1334 
1335     /* Initialize structure */
1336     memset(apv, val, len);
1337 
1338     return GRIOMMU_ERR_OK;
1339 }
1340 
1341 int griommu_apv_page_set(void * apv, int index, int size, int options)
1342 {
1343     struct griommu_priv * priv = griommupriv;
1344     unsigned int val;
1345 
1346     if (priv == NULL){
1347         DBG("GRIOMMU not initialized.\n");
1348         return GRIOMMU_ERR_NOINIT;
1349     }
1350 
1351     if ((apv == NULL) || ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1))){
1352         DBG("Wrong pointer.\n");
1353         return GRIOMMU_ERR_EINVAL;
1354     }
1355 
1356     /* Get init value */
1357     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1358         val = 0x0;
1359     }else{
1360         val = 0xffffffff;
1361     }
1362 
1363     return griommu_apv_set(apv, index, size, val);
1364 }
1365 
1366 int griommu_apv_address_set(void * apv, uint32_t addr, int size, int options)
1367 {
1368     struct griommu_priv * priv = griommupriv;
1369     unsigned int val;
1370     int startpage;
1371     int endpage;
1372     int npages;
1373 
1374     if (priv == NULL){
1375         DBG("GRIOMMU not initialized.\n");
1376         return GRIOMMU_ERR_NOINIT;
1377     }
1378 
1379     if ((apv == NULL) || ((unsigned int) apv & (GRIOMMU_APV_ALIGN -1))){
1380         DBG("Wrong pointer.\n");
1381         return GRIOMMU_ERR_EINVAL;
1382     }
1383 
1384     /* Get init value */
1385     if (options == GRIOMMU_OPTIONS_APV_ALLOW){
1386         val = 0x0;
1387     }else{
1388         val = 0xffffffff;
1389     }
1390 
1391     /* Get start page */
1392     startpage = (addr / priv->pagesize);
1393 
1394     /* Get end page */
1395     endpage = ((addr + size)/ priv->pagesize);
1396 
1397     /* Get number of pages */
1398     npages = endpage - startpage + 1;
1399 
1400     return griommu_apv_set(apv, startpage, npages, val);
1401 }
1402 
1403 int griommu_group_info(int group, uint32_t * info)
1404 {
1405     struct griommu_priv * priv = griommupriv;
1406 
1407     if (priv == NULL){
1408         DBG("GRIOMMU not initialized.\n");
1409         return GRIOMMU_ERR_NOINIT;
1410     }
1411 
1412     if ((group < 0) || (group >= priv->groups)){
1413         DBG("Wrong group id.\n");
1414         return GRIOMMU_ERR_EINVAL;
1415     }
1416 
1417     if (info == NULL){
1418         DBG("Wrong pointer.\n");
1419         return GRIOMMU_ERR_EINVAL;
1420     }
1421 
1422     /* Get group */
1423     *info = griommu_reg_group(group);
1424 
1425     return GRIOMMU_ERR_OK;
1426 }
1427 
1428 /* Flush APV cache group:
1429  */
1430 int griommu_group_apv_flush(int group)
1431 {
1432     struct griommu_priv * priv = griommupriv;
1433 
1434     if (priv == NULL){
1435         DBG("GRIOMMU not initialized.\n");
1436         return GRIOMMU_ERR_NOINIT;
1437     }
1438 
1439     if ((group < 0) || (group >= priv->groups)){
1440         DBG("Wrong group id.\n");
1441         return GRIOMMU_ERR_EINVAL;
1442     }
1443 
1444     /* Flush cache  */
1445     if (priv->cache_enabled){
1446         if (priv->group_addressing){
1447             griommu_reg_flush_set(((group << FLUSH_FGRP_BIT) & FLUSH_FGRP) | 
1448                     FLUSH_GF | FLUSH_F);
1449         }else{
1450             griommu_reg_flush_set(FLUSH_F);
1451         }
1452         DBG("GRIOMMU APV cache flushed.\n");
1453     }
1454 
1455     return GRIOMMU_ERR_OK;
1456 }
1457 
1458 /* Flush APV cache:
1459  */
1460 int griommu_apv_flush(void)
1461 {
1462     struct griommu_priv * priv = griommupriv;
1463 
1464     if (priv == NULL){
1465         DBG("GRIOMMU not initialized.\n");
1466         return GRIOMMU_ERR_NOINIT;
1467     }
1468 
1469     /* Flush cache  */
1470     if (priv->cache_enabled){
1471         griommu_reg_flush_set(FLUSH_F);
1472         DBG("GRIOMMU APV cache flushed.\n");
1473     }
1474 
1475     return GRIOMMU_ERR_OK;
1476 }
1477