source: rtems/bsps/shared/grlib/iommu/griommu.c

Last change on this file was 5d5b9ee, checked in by Daniel Cederman <cederman@…>, on 11/14/22 at 09:59:08

bsps/shared/grlib: Change license to BSD-2 for files with Gaisler copyright

This patch changes the license to BSD-2 for all source files where the
copyright is held by Aeroflex Gaisler, Cobham Gaisler, or Gaisler Research.
Some files also includes copyright right statements from OAR and/or
embedded Brains in addition to Gaisler.

Updates #3053.

  • Property mode set to 100644
File size: 34.8 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*
4 *  GRIOMMU Driver Interface
5 *
6 *  COPYRIGHT (c) 2017
7 *  Cobham Gaisler AB
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <stdlib.h>
32#include <string.h>
33#include <drvmgr/drvmgr.h>
34#include <grlib/ambapp_bus.h>
35#include <grlib/ambapp.h>
36#include <rtems.h>
37#include <rtems/bspIo.h>
38#include <bsp.h>
39#include <grlib/griommu.h>
40
41#include <grlib/grlib_impl.h>
42
43/*#define STATIC*/
44#define STATIC static
45
46/*#define INLINE*/
47#define INLINE inline
48
49#define UNUSED __attribute__((unused))
50
51/*#define DEBUG 1*/
52
53#ifdef DEBUG
54#define DBG(x...) printf(x)
55#else
56#define DBG(x...)
57#endif
58
59/*
60 * GRIOMMU CAP0 register fields
61 */
62#define CAP0_A (0x1 << CAP0_A_BIT)
63#define CAP0_AC (0x1 << CAP0_AC_BIT)
64#define CAP0_CA (0x1 << CAP0_CA_BIT)
65#define CAP0_CP (0x1 << CAP0_CP_BIT)
66#define CAP0_NARB (0xf << CAP0_NARB_BIT)
67#define CAP0_CS (0x1 << CAP0_CS_BIT)
68#define CAP0_FT (0x3 << CAP0_FT_BIT)
69#define CAP0_ST (0x1 << CAP0_ST_BIT)
70#define CAP0_I (0x1 << CAP0_I_BIT)
71#define CAP0_IT (0x1 << CAP0_IT_BIT)
72#define CAP0_IA (0x1 << CAP0_IA_BIT)
73#define CAP0_IP (0x1 << CAP0_IP_BIT)
74#define CAP0_MB (0x1 << CAP0_MB_BIT)
75#define CAP0_GRPS (0xf << CAP0_GRPS_BIT)
76#define CAP0_MSTS (0xf << CAP0_MSTS_BIT)
77
78#define CAP0_A_BIT 31
79#define CAP0_AC_BIT 30
80#define CAP0_CA_BIT 29
81#define CAP0_CP_BIT 28
82#define CAP0_NARB_BIT 20
83#define CAP0_CS_BIT 19
84#define CAP0_FT_BIT 17
85#define CAP0_ST_BIT 16
86#define CAP0_I_BIT 15
87#define CAP0_IT_BIT 14
88#define CAP0_IA_BIT 13
89#define CAP0_IP_BIT 12
90#define CAP0_MB_BIT 8
91#define CAP0_GRPS_BIT 4
92#define CAP0_MSTS_BIT 0
93
94/*
95 * GRIOMMU CAP1 register fields
96 */
97#define CAP1_CADDR (0xfff << CAP1_CADDR_BIT)
98#define CAP1_CMASK (0xf << CAP1_CMASK_BIT)
99#define CAP1_CTAGBITS (0xff << CAP1_CTAGBITS_BIT)
100#define CAP1_CISIZE (0x7 << CAP1_CISIZE_BIT)
101#define CAP1_CLINES (0x1f << CAP1_CLINES_BIT)
102
103#define CAP1_CADDR_BIT 20
104#define CAP1_CMASK_BIT 16
105#define CAP1_CTAGBITS_BIT 8
106#define CAP1_CISIZE_BIT 5
107#define CAP1_CLINES_BIT 0
108
109/*
110 * GRIOMMU CTRL register fields
111 * DEFINED IN HEADER FILE
112 */
113
114/*
115 * GRIOMMU FLUSH register fields
116 */
117#define FLUSH_FGRP (0xf << FLUSH_FGRP_BIT)
118#define FLUSH_GF (0x1 << FLUSH_GF_BIT)
119#define FLUSH_F (0x1 << FLUSH_F_BIT)
120
121#define FLUSH_FGRP_BIT 4
122#define FLUSH_GF_BIT 1
123#define FLUSH_F_BIT 0
124
125/*
126 * GRIOMMU STATUS register fields
127 */
128#define STS_PE (0x1 << STS_PE_BIT)
129#define STS_DE (0x1 << STS_DE_BIT)
130#define STS_FC (0x1 << STS_FC_BIT)
131#define STS_FL (0x1 << STS_FL_BIT)
132#define STS_AD (0x1 << STS_AD_BIT)
133#define STS_TE (0x1 << STS_TE_BIT)
134#define STS_ALL (STS_PE | STS_DE | STS_FC | STS_FL | STS_AD | STS_TE)
135
136#define STS_PE_BIT 5
137#define STS_DE_BIT 4
138#define STS_FC_BIT 3
139#define STS_FL_BIT 2
140#define STS_AD_BIT 1
141#define STS_TE_BIT 0
142
143/*
144 * GRIOMMU IMASK register fields
145 */
146#define IMASK_PEI (0x1 << IMASK_PEI_BIT)
147#define IMASK_FCI (0x1 << IMASK_FCI_BIT)
148#define IMASK_FLI (0x1 << IMASK_FLI_BIT)
149#define IMASK_ADI (0x1 << IMASK_ADI_BIT)
150#define IMASK_TEI (0x1 << IMASK_TEI_BIT)
151#define IMASK_ALL (IMASK_PEI | IMASK_FCI | IMASK_FLI | IMASK_ADI | IMASK_TEI)
152
153#define IMASK_PEI_BIT 5
154#define IMASK_FCI_BIT 3
155#define IMASK_FLI_BIT 2
156#define IMASK_ADI_BIT 1
157#define IMASK_TEI_BIT 0
158
159/*
160 * GRIOMMU MASTER register fields
161 */
162/* DEFINED IN HEADER FILE
163#define MASTER_VENDOR (0xff << MASTER_VENDOR_BIT)
164#define MASTER_DEVICE (0xfff << MASTER_DEVICE_BIT)
165#define MASTER_BS (0x1 << MASTER_BS_BIT)
166#define MASTER_GROUP (0xf << MASTER_GROUP_BIT)
167
168#define MASTER_VENDOR_BIT 24
169#define MASTER_DEVICE_BIT 12
170#define MASTER_BS_BIT 4
171#define MASTER_GROUP_BIT 0
172*/
173
174#define MASTER_BS_BUS0 0
175#define MASTER_BS_BUS1 MASTER_BS
176
177/*
178 * GRIOMMU GROUP register fields
179 */
180#define GRP_BASE (0xfffffff << GRP_BASE_BIT)
181#define GRP_P (0x1 << GRP_P_BIT)
182#define GRP_AG (0x1 << GRP_AG_BIT)
183
184#define GRP_BASE_BIT 4
185#define GRP_P_BIT 1
186#define GRP_AG_BIT 0
187
188
189#define REG_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (unsigned int)(val))
190#define REG_READ(addr) (*(volatile unsigned int *)(addr))
191
192/*
193 * GRIOMMU APB Register MAP
194 */
195struct griommu_regs {
196        volatile unsigned int cap0;                     /* 0x00 - Capability 0 */
197        volatile unsigned int cap1;                     /* 0x04 - Capability 1 */
198        volatile unsigned int cap2;                     /* 0x08 - Capability 2 */
199        volatile unsigned int resv1;            /* 0x0c - Reserved */
200        volatile unsigned int ctrl;                     /* 0x10 - Control */
201        volatile unsigned int flush;            /* 0x14 - TLB/cache flush */
202        volatile unsigned int status;           /* 0x18 - Status */
203        volatile unsigned int imask;            /* 0x1c - Interrupt mask */
204        volatile unsigned int ahbstat;          /* 0x20 - AHB Failing Access */
205        volatile unsigned int resv2[7];         /* 0x24-0x3c - Reserved. No access */
206        volatile unsigned int master[16];       /* 0x40-0x7c - Master configuration */
207        volatile unsigned int grp_ctrl[16]; /* 0x80-0xbc - Group control */
208        volatile unsigned int diag_ca;          /* 0xc0 - Diagnostic cache access */
209        volatile unsigned int diag_cad[8];      /* 0xc4-0xe0 - Diagnostic cache data */
210        volatile unsigned int diag_cat;         /* 0xe4 - Diagnostic cache tag */
211        volatile unsigned int ei_data;          /* 0xe8 - Data RAM error injection */
212        volatile unsigned int ei_tag;           /* 0xec - Tag RAM error injection */
213        volatile unsigned int resv3[4];         /* 0xf0-0xfc - Reserved. No access */
214        volatile unsigned int asmpctrl[16]; /* 0x100-0x13c - ASMP access control */
215};
216
217#define DEVNAME_LEN 9
218/*
219 * GRIOMMU Driver private data struture
220 */
221struct griommu_priv {
222        struct drvmgr_dev       *dev;
223        char devname[DEVNAME_LEN];
224        /* GRIOMMU control registers */
225        struct griommu_regs     *regs;
226
227        /* GRIOMMU capabilities */
228        int apv;
229        int apv_cache;
230        int apv_cache_addr;
231        int conf_pagesize;
232
233        int groups;
234        int masters;
235
236        /* GRIOMMU page size */
237        int pagesize;
238
239        /* GRIOMMU APV cache */
240        int cache_enabled;
241        int group_addressing;
242
243        /* User defined ISR */
244        griommu_isr_t isr;
245        void *isr_arg;
246};
247
248/*
249 * GRIOMMU internal prototypes
250 */
251/* -Register access functions */
252STATIC INLINE unsigned int griommu_reg_cap0(void);
253STATIC INLINE unsigned int griommu_reg_cap1(void);
254STATIC INLINE unsigned int griommu_reg_ctrl(void);
255STATIC INLINE int griommu_reg_ctrl_set(unsigned int val);
256STATIC INLINE int griommu_reg_flush_set(unsigned int val);
257STATIC INLINE unsigned int griommu_reg_status(void);
258STATIC INLINE int griommu_reg_status_clear(unsigned int val);
259STATIC INLINE unsigned int griommu_reg_imask(void);
260STATIC INLINE int griommu_reg_imask_set(int mask);
261STATIC INLINE unsigned int griommu_reg_ahbfas(void);
262STATIC INLINE unsigned int griommu_reg_master(int master);
263STATIC INLINE int griommu_reg_master_set(int master, unsigned int val);
264STATIC INLINE unsigned int griommu_reg_group(int group);
265STATIC INLINE int griommu_reg_group_set(int group, unsigned int val);
266
267/* APV helper functions */
268STATIC void griommu_apv_set_word(unsigned int * wordptr, int startbitidx,
269                int nbits, unsigned int val);
270STATIC int griommu_apv_set(void * apv, int index, int size, unsigned int val);
271
272/* -Init function called by drvmgr */
273int griommu_init1(struct drvmgr_dev *dev);
274STATIC int griommu_init(struct griommu_priv *priv);
275
276
277/* -IRQ handler */
278void griommu_isr(void *arg);
279
280/*
281 * GRIOMMU static members
282 */
283static struct griommu_priv *griommupriv = NULL;
284
285/* GRIOMMU DRIVER */
286
287struct drvmgr_drv_ops griommu_ops =
288{
289        .init = {griommu_init1, NULL, NULL, NULL},
290        .remove = NULL,
291        .info = NULL
292};
293
294struct amba_dev_id griommu_ids[] =
295{
296        {VENDOR_GAISLER, GAISLER_GRIOMMU},
297        {0, 0}          /* Mark end of table */
298};
299
300struct amba_drv_info griommu_info =
301{
302        {
303                DRVMGR_OBJ_DRV,                                 /* Driver */
304                NULL,                           /* Next driver */
305                NULL,                           /* Device list */
306                DRIVER_AMBAPP_GAISLER_GRIOMMU_ID,/* Driver ID */
307                "GRIOMMU_DRV",                  /* Driver Name */
308                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
309                &griommu_ops,
310                NULL,                           /* Funcs */
311                0,                              /* No devices yet */
312                sizeof(struct griommu_priv),    /* Make drvmgr alloc private */
313        },
314        &griommu_ids[0]
315};
316
317void griommu_register_drv(void)
318{
319        DBG("Registering GRIOMMU driver\n");
320        drvmgr_drv_register(&griommu_info.general);
321}
322
323/* Initializes the GRIOMMU core and driver
324 *
325 * Return values
326 *      0                         Successful initalization
327 */
328STATIC int griommu_init(struct griommu_priv *priv)
329{
330        struct ambapp_ahb_info *ahb;
331        struct amba_dev_info *ainfo = priv->dev->businfo;
332
333        /* Find GRIOMMU core from Plug&Play information */
334        ahb = ainfo->info.ahb_slv;
335
336        /* Found GRIOMMU core, init private structure */
337        priv->regs = (struct griommu_regs *)ahb->start[0];
338
339        /* Mask all interrupts */
340        griommu_reg_imask_set(0);
341
342        /* Initialize GRIOMMU capabilities */
343        uint32_t cap0 = griommu_reg_cap0();
344        priv->apv = (cap0 & CAP0_A) >> CAP0_A_BIT;
345        priv->apv_cache = (cap0 & CAP0_AC) >> CAP0_AC_BIT;
346        priv->apv_cache_addr = (cap0 & CAP0_CA) >> CAP0_CA_BIT;
347        priv->conf_pagesize = (cap0 & CAP0_CS) >> CAP0_CS_BIT;
348        priv->groups = ((cap0 & CAP0_GRPS) >> CAP0_GRPS_BIT) + 1;
349        priv->masters = ((cap0 & CAP0_MSTS) >> CAP0_MSTS_BIT) + 1;
350
351        /* Get GRIOMMU pagesize */
352        uint32_t ctrl = griommu_reg_ctrl();
353        if (priv->conf_pagesize){
354                priv->pagesize = (4*1024 << ((ctrl & CTRL_PGSZ) >> CTRL_PGSZ_BIT));
355        }else{
356                priv->pagesize = 4*1024;
357        }
358        priv->cache_enabled = (ctrl & CTRL_CE);
359        priv->group_addressing = (ctrl & CTRL_GS);
360
361        DBG("GRIOMMU Capabilities: APV=%d, APVC=%d, APVCA=%d, CS=%d, "
362                        "GRPS=%d, MSTS=%d\n",
363                        priv->apv, priv->apv_cache, priv->apv_cache_addr,
364                        priv->conf_pagesize, priv->groups, priv->masters);
365        DBG("GRIOMMU driver initialized\n");
366
367        return 0;
368}
369
370/* Called when a core is found with the AMBA device and vendor ID
371 * given in griommu_ids[]. IRQ, Console does not work here
372 */
373int griommu_init1(struct drvmgr_dev *dev)
374{
375        int status;
376        struct griommu_priv *priv;
377
378        DBG("GRIOMMU[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
379
380        if (griommupriv) {
381                DBG("Driver only supports one GRIOMMU core\n");
382                return DRVMGR_FAIL;
383        }
384
385        priv = dev->priv;
386        if (!priv)
387                return DRVMGR_NOMEM;
388
389        priv->dev = dev;
390        strncpy(&priv->devname[0], "griommu0", DEVNAME_LEN);
391        griommupriv = priv;
392
393        /* Initialize GRIOMMU Hardware */
394        status = griommu_init(priv);
395        if (status) {
396                printk("Failed to initialize griommu driver %d\n", status);
397                return -1;
398        }
399
400        return DRVMGR_OK;
401}
402
403STATIC INLINE unsigned int griommu_reg_cap0(void)
404{
405        struct griommu_priv *priv = griommupriv;
406
407        return REG_READ(&priv->regs->cap0);
408}
409
410STATIC INLINE unsigned int griommu_reg_cap1(void)
411{
412        struct griommu_priv *priv = griommupriv;
413
414        return REG_READ(&priv->regs->cap1);
415}
416
417STATIC INLINE unsigned int griommu_reg_ctrl(void)
418{
419        struct griommu_priv *priv = griommupriv;
420
421        return REG_READ(&priv->regs->ctrl);
422}
423
424STATIC INLINE int griommu_reg_ctrl_set(unsigned int val)
425{
426        struct griommu_priv *priv = griommupriv;
427
428        REG_WRITE(&priv->regs->ctrl, val);
429        return 0;
430}
431
432STATIC INLINE int griommu_reg_flush_set(unsigned int val)
433{
434        struct griommu_priv *priv = griommupriv;
435
436        REG_WRITE(&priv->regs->flush, val);
437        return 0;
438}
439
440STATIC INLINE unsigned int griommu_reg_status(void)
441{
442        struct griommu_priv *priv = griommupriv;
443
444   return REG_READ(&priv->regs->status);
445}
446
447STATIC INLINE int griommu_reg_status_clear(unsigned int val)
448{
449        struct griommu_priv *priv = griommupriv;
450
451        /* Clear errors */
452        REG_WRITE(&priv->regs->status, (val & STS_ALL));
453        return 0;
454}
455
456STATIC INLINE unsigned int griommu_reg_imask(void)
457{
458        struct griommu_priv *priv = griommupriv;
459
460   return REG_READ(&priv->regs->imask);
461}
462
463STATIC INLINE int griommu_reg_imask_set(int mask)
464{
465        struct griommu_priv *priv = griommupriv;
466
467        /* Clear errors */
468        REG_WRITE(&priv->regs->imask, (mask & IMASK_ALL));
469        return 0;
470}
471
472STATIC INLINE unsigned int griommu_reg_ahbfas(void)
473{
474        struct griommu_priv *priv = griommupriv;
475
476   return REG_READ(&priv->regs->ahbstat);
477}
478
479STATIC INLINE int griommu_reg_master_set(int master, unsigned int val)
480{
481        struct griommu_priv *priv = griommupriv;
482
483        /* Change master conf */
484        REG_WRITE(&priv->regs->master[master], val);
485        return 0;
486}
487
488STATIC INLINE unsigned int griommu_reg_master(int master)
489{
490        struct griommu_priv *priv = griommupriv;
491
492        return REG_READ(&priv->regs->master[master]);
493}
494
495STATIC INLINE unsigned int griommu_reg_group(int group)
496{
497        struct griommu_priv *priv = griommupriv;
498
499        return REG_READ(&priv->regs->grp_ctrl[group]);
500}
501
502STATIC INLINE int griommu_reg_group_set(int group, unsigned int val)
503{
504        struct griommu_priv *priv = griommupriv;
505
506        REG_WRITE(&priv->regs->grp_ctrl[group], val);
507        return 0;
508}
509
510STATIC void griommu_apv_set_word(unsigned int * wordptr, int startbitidx,
511                int nbits, unsigned int val)
512{
513        unsigned int mask;
514        unsigned int word = *wordptr;
515        int endbitidx = startbitidx + nbits - 1;
516
517        /* Set initial mask */
518        mask = 0xffffffff;
519
520        /* Adjust mask for the starting bit */
521        mask >>= startbitidx;
522
523        /* Adjust mask for the end bit */
524        mask >>= (31 - endbitidx);
525        mask <<= (31 - endbitidx);
526
527        DBG("Setting word: startbitdx=%d, endbitidx=%d, mask=0x%02x",
528                        startbitidx, endbitidx, (unsigned int) mask);
529
530        /* Clear written bits with mask */
531        word &= ~(mask);
532
533        /* Set bits in val with mask */
534        mask &= val;
535        word |= mask;
536
537        DBG(", old word=0x%08x, new word=0x%08x\n",*wordptr, word);
538
539        /* Write word */
540        *wordptr=word;
541}
542
543/* Set certains bits of the APV to val */
544STATIC int griommu_apv_set(void * apv, int index, int size, unsigned int val)
545{
546        unsigned int * words = (unsigned int *) apv;
547        int len = size;
548        int wordidx = (index/32);
549        int startbit = (index % 32);
550        int nbits;
551        int nwords;
552
553        /* First incomplete word is a special case */
554        if (startbit != 0){
555                /* Get how many bits are we changing in this word */
556                if (startbit + len  < 32){
557                        nbits = len;
558                }else{
559                        nbits = 32 - startbit;
560                }
561                griommu_apv_set_word(&words[wordidx], startbit, nbits, val);
562                DBG("First word: wordidx=%d, startbit=%d, bits=%d, val=0x%08x\n",
563                                wordidx, startbit, nbits, words[wordidx]);
564
565                /* Update wordidx and len */
566                len = len - nbits;
567                wordidx++;
568        }
569
570        /* Write all complete full words */
571        if (len != 0){
572                nwords = (len/32);
573                memset((void *) &words[wordidx], val, nwords*4);
574                DBG("Middle words: wordidx=%d, nwords=%d\n", wordidx, nwords);
575                /* Update wordidx and len*/
576                wordidx = wordidx + nwords;
577                len = len - nwords*32;
578        }
579
580        /* Last word is a special case */
581        if (len != 0){
582                nbits = len;
583                griommu_apv_set_word(&words[wordidx], 0, nbits, val);
584                DBG("First word: wordidx=%d, startbit=%d, bits=%d, val=0x%08x\n",
585                                wordidx, 0, nbits, words[wordidx]);
586                /* Update len */
587                len = len - (nbits);
588        }
589
590        return GRIOMMU_ERR_OK;
591}
592
593/* GRIOMMU Interrupt handler, called when there may be a GRIOMMU interrupt.
594 */
595void griommu_isr(void *arg)
596{
597        struct griommu_priv *priv = arg;
598        unsigned int sts = griommu_reg_status();
599        unsigned int mask = griommu_reg_imask();
600        unsigned int access = griommu_reg_ahbfas();
601
602        /* Make sure that the interrupt is pending and unmasked,
603         * otherwise it migth have been other core
604         * sharing the same interrupt line */
605        if ((sts & STS_ALL) & (mask & IMASK_ALL)){
606                /* Reset error status */
607                griommu_reg_status_clear(sts);
608                /* Execute user IRQ (ther will always be one ISR */
609                (priv->isr)(priv->isr_arg, access, sts);
610        }
611}
612
613/* Setup IOMMU master:
614 */
615int griommu_master_setup(int master, int group, int options)
616{
617        struct griommu_priv * priv = griommupriv;
618
619        if (priv == NULL){
620                DBG("GRIOMMU not initialized.\n");
621                return GRIOMMU_ERR_NOINIT;
622        }
623
624        if ((master < 0) || (master >= priv->masters)){
625                DBG("Wrong master id.\n");
626                return GRIOMMU_ERR_EINVAL;
627        }
628
629        if ((group < 0) || (group >= priv->groups)){
630                DBG("Wrong group id.\n");
631                return GRIOMMU_ERR_EINVAL;
632        }
633
634        griommu_reg_master_set(master,
635                        ((options & GRIOMMU_OPTIONS_BUS1)? MASTER_BS_BUS1: MASTER_BS_BUS0)|
636                        ((group << MASTER_GROUP_BIT) & MASTER_GROUP)
637                        );
638
639        DBG("IOMMU master setup: master %d, traffic routed %s, group %d\n",
640                        master,
641                        (options & GRIOMMU_OPTIONS_BUS1) ?
642                                        "to Secondary bus":"to Primary bus",
643                        group);
644
645        return GRIOMMU_ERR_OK;
646}
647
648
649/* Get IOMMU master info:
650 */
651int griommu_master_info(int master, uint32_t * info)
652{
653        struct griommu_priv * priv = griommupriv;
654
655        if (priv == NULL){
656                DBG("GRIOMMU not initialized.\n");
657                return GRIOMMU_ERR_NOINIT;
658        }
659
660        if ((master < 0) || (master >= priv->masters)){
661                DBG("Wrong master id.\n");
662                return GRIOMMU_ERR_EINVAL;
663        }
664
665        if (info == NULL){
666                DBG("Wrong pointer.\n");
667                return GRIOMMU_ERR_EINVAL;
668        }
669
670        /* Get master */
671        *info = griommu_reg_master(master);
672
673        return GRIOMMU_ERR_OK;
674}
675
676/* Find IOMMU master:
677 */
678int griommu_master_find(int vendor, int device, int instance)
679{
680        struct griommu_priv * priv = griommupriv;
681        int i, gotvendor, gotdevice;
682        unsigned int master;
683        int found;
684
685        if (priv == NULL){
686                DBG("GRIOMMU not initialized.\n");
687                return GRIOMMU_ERR_NOINIT;
688        }
689
690        /* Find which master */
691        found=0;
692        for (i=0; i< priv->masters; i++){
693                master = griommu_reg_master(i);
694                gotvendor = (master & MASTER_VENDOR) >> MASTER_VENDOR_BIT;
695                gotdevice = (master & MASTER_DEVICE) >> MASTER_DEVICE_BIT;
696                if ((gotvendor == vendor) && (gotdevice == device)){
697                        if(found == instance){
698                                DBG("Found master %d: VENDOR=%s(0x%02x), DEVICE=%s(0x%03x), "
699                                        "Instance=%d\n",
700                                        i,
701                                        ambapp_vendor_id2str(vendor), vendor,
702                                        ambapp_device_id2str(vendor,device), device, instance
703                                        );
704                                return i;
705                        }
706                        found++;
707                }
708        }
709
710        DBG("Master not found: VENDOR=%s(0x%02x), DEVICE=%s(0x%03x), "
711                "Instance=%d\n",
712                ambapp_vendor_id2str(vendor), vendor,
713                ambapp_device_id2str(vendor,device), device, instance
714                );
715        return GRIOMMU_ERR_NOTFOUND;
716}
717
718/* Setup IOMMU:
719 */
720int griommu_setup(int options)
721{
722        struct griommu_priv * priv = griommupriv;
723        unsigned int ctrl;
724
725        if (priv == NULL){
726                DBG("GRIOMMU not initialized.\n");
727                return GRIOMMU_ERR_NOINIT;
728        }
729
730        /* Check Cache */
731        if (options & GRIOMMU_OPTIONS_CACHE_ENABLE) {
732                if (priv->apv_cache){
733                        /* Flush cache */
734                        griommu_reg_flush_set(FLUSH_F);
735                        priv->cache_enabled = 1;
736                }else{
737                        DBG("GRIOMMU APV cache not supported.\n");
738                        return GRIOMMU_ERR_IMPLEMENTED;
739                }
740        }else{
741                priv->cache_enabled = 0;
742        }
743
744        /* Check group addressing */
745        if (options & GRIOMMU_OPTIONS_GROUPADDRESSING_ENABLE){
746                if (priv->apv_cache_addr){
747                        priv->group_addressing = 1;
748                }else{
749                        DBG("GRIOMMU APV cache group addressing not supported.\n");
750                        return GRIOMMU_ERR_IMPLEMENTED;
751                }
752        }else{
753                priv->group_addressing = 0;
754        }
755
756        /* Check pagesize */
757        if ((options & CTRL_PGSZ) != GRIOMMU_OPTIONS_PAGESIZE_4KIB){
758                if (priv->conf_pagesize == 0){
759                        DBG("GRIOMMU Configurable pagesize not supported.\n");
760                        return GRIOMMU_ERR_IMPLEMENTED;
761                }
762        }
763
764        /* Get CTRL IOMMU */
765        ctrl = griommu_reg_ctrl();
766
767        /* Clear used fields */
768        ctrl &= ~(CTRL_CE | CTRL_GS | CTRL_PGSZ | CTRL_LB |
769                        CTRL_DP | CTRL_AU | CTRL_WP);
770
771        /* Clear not used fields */
772        options &= (CTRL_CE | CTRL_GS | CTRL_PGSZ | CTRL_LB |
773                        CTRL_DP | CTRL_AU | CTRL_WP);
774
775        /* Set new values */
776        ctrl |= options;
777
778        /* Set CTRL IOMMU */
779        griommu_reg_ctrl_set(ctrl);
780
781        DBG("IOMMU setup: prefetching %s, cache %s, groupaddr %s, "
782                "lookup bus %s, ahb update %s,\nwprot only %s, pagesize %d KiB\n",
783                        ((options & GRIOMMU_OPTIONS_PREFETCH_DISABLE)?
784                                        "disabled":"enabled"),
785                        ((options & GRIOMMU_OPTIONS_CACHE_ENABLE)? "enabled":"disabled"),
786                        ((options & GRIOMMU_OPTIONS_GROUPADDRESSING_ENABLE)?
787                                        "enabled":"disabled"),
788                        ((options & GRIOMMU_OPTIONS_LOOKUPBUS_BUS1)? "bus1":"bus0"),
789                        ((options & GRIOMMU_OPTIONS_AHBUPDATE_ENABLE)?
790                                        "enabled":"disabled"),
791                        ((options & GRIOMMU_OPTIONS_WPROTONLY_ENABLE)?
792                                        "enabled":"disabled"),
793                        (4 << ((options & GRIOMMU_OPTIONS_PAGESIZE_512KIB) >> 18))
794                );
795
796        return GRIOMMU_ERR_OK;
797}
798
799/* Status IOMMU:
800 */
801int griommu_status(void)
802{
803        struct griommu_priv * priv = griommupriv;
804        unsigned int ctrl;
805
806        if (priv == NULL){
807                DBG("GRIOMMU not initialized.\n");
808                return GRIOMMU_ERR_NOINIT;
809        }
810
811        /* Get CTRL IOMMU */
812        ctrl = griommu_reg_ctrl();
813
814        DBG("IOMMU status: prefetching %s, cache %s, groupaddr %s, "
815                "lookup bus %s, ahb update %s,\nwprot only %s, pagesize %d KiB\n",
816                        ((ctrl & CTRL_DP)? "disabled":"enabled"),
817                        ((ctrl & CTRL_CE)? "enabled":"disabled"),
818                        ((ctrl & CTRL_GS)? "enabled":"disabled"),
819                        ((ctrl & CTRL_LB)? "bus1":"bus0"),
820                        ((ctrl & CTRL_AU)? "enabled":"disabled"),
821                        ((ctrl & CTRL_WP)? "enabled":"disabled"),
822                        (4 << ((ctrl & CTRL_PGSZ) >> CTRL_PGSZ_BIT))
823                );
824
825        return ctrl;
826}
827
828int griommu_isr_register(griommu_isr_t isr, void * arg, int options)
829{
830        struct griommu_priv *priv = griommupriv;
831        unsigned int mask;
832
833        if (priv == NULL){
834                DBG("GRIOMMU not initialized.\n");
835                return GRIOMMU_ERR_NOINIT;
836        }
837
838        if (isr == NULL){
839                DBG("GRIOMMU wrong isr.\n");
840                return GRIOMMU_ERR_EINVAL;
841        }
842
843        /* Get mask */
844        mask = 0 |
845                ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
846                ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
847                ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
848                ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
849                ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
850
851        /* Clear previous interrupts and mask them*/
852        griommu_reg_status_clear(STS_ALL);
853        griommu_reg_imask_set(0);
854
855        /* First time registering an ISR */
856        if (priv->isr == NULL){
857                /* Install and Enable GRIOMMU interrupt handler */
858                drvmgr_interrupt_register(priv->dev, 0, priv->devname, griommu_isr,
859                                priv);
860        }
861
862        /* Install user ISR */
863        priv->isr=isr;
864        priv->isr_arg=arg;
865
866        /* Now it is safe to unmask interrupts */
867        griommu_reg_imask_set(mask);
868
869        return GRIOMMU_ERR_OK;
870}
871
872int griommu_isr_unregister(void)
873{
874        struct griommu_priv *priv = griommupriv;
875
876        if (priv == NULL){
877                DBG("GRIOMMU not initialized.\n");
878                return GRIOMMU_ERR_NOINIT;
879        }
880
881        if (priv->isr == NULL){
882                DBG("GRIOMMU wrong isr.\n");
883                return GRIOMMU_ERR_EINVAL;
884        }
885
886        /* Clear previous interrupts and mask them*/
887        griommu_reg_status_clear(STS_ALL);
888        griommu_reg_imask_set(0);
889
890        /* Uninstall and disable GRIOMMU interrupt handler */
891        drvmgr_interrupt_unregister(priv->dev, 0, griommu_isr, priv);
892
893        /* Uninstall user ISR */
894        priv->isr=NULL;
895        priv->isr_arg=NULL;
896
897        return GRIOMMU_ERR_OK;
898}
899
900int griommu_interrupt_unmask(int options)
901{
902        struct griommu_priv *priv = griommupriv;
903        unsigned int mask, irq;
904
905        if (priv == NULL){
906                DBG("GRIOMMU not initialized.\n");
907                return GRIOMMU_ERR_NOINIT;
908        }
909
910        if (priv->isr == NULL){
911                DBG("GRIOMMU wrong isr.\n");
912                return GRIOMMU_ERR_EINVAL;
913        }
914
915        /* Unmask interrupts in GRIOMMU */
916        mask = 0 |
917                ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
918                ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
919                ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
920                ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
921                ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
922
923        /* Clear previous interrupts*/
924        griommu_reg_status_clear(STS_ALL);
925
926        /* Get previous mask */
927        irq = griommu_reg_imask() & IMASK_ALL;
928
929        /* Set new mask */
930        griommu_reg_imask_set(irq | mask);
931
932        return GRIOMMU_ERR_OK;
933}
934
935int griommu_interrupt_mask(int options)
936{
937        struct griommu_priv *priv = griommupriv;
938        unsigned int mask, irq;
939
940        if (priv == NULL){
941                DBG("GRIOMMU not initialized.\n");
942                return GRIOMMU_ERR_NOINIT;
943        }
944
945        if (priv->isr == NULL){
946                DBG("GRIOMMU wrong isr.\n");
947                return GRIOMMU_ERR_EINVAL;
948        }
949
950        /* Mask interrupts in GRIOMMU */
951        mask = 0 |
952                ((options & GRIOMMU_INTERRUPT_PARITY_ERROR)? IMASK_PEI:0) |
953                ((options & GRIOMMU_INTERRUPT_FLUSH_COMPLETED)? IMASK_FCI:0) |
954                ((options & GRIOMMU_INTERRUPT_FLUSH_START)? IMASK_FLI:0) |
955                ((options & GRIOMMU_INTERRUPT_ACCESS_DENIED)? IMASK_ADI:0) |
956                ((options & GRIOMMU_INTERRUPT_TRANSLATION_ERROR)? IMASK_TEI:0);
957
958        /* Clear previous interrupts*/
959        griommu_reg_status_clear(STS_ALL);
960
961        /* Get previous mask */
962        irq = griommu_reg_imask() & IMASK_ALL;
963
964        /* Set new mask */
965        griommu_reg_imask_set(irq & ~(mask));
966
967        return GRIOMMU_ERR_OK;
968}
969
970int griommu_error_status(uint32_t * access)
971{
972        struct griommu_priv *priv = griommupriv;
973        int status;
974
975        if (priv == NULL){
976                DBG("GRIOMMU not initialized.\n");
977                return GRIOMMU_ERR_NOINIT;
978        }
979
980        /* Get status mask */
981        status = griommu_reg_status();
982
983        if (status != 0){
984                /* Update pointed value */
985                if (access != NULL){
986                        *access = griommu_reg_ahbfas();
987                }
988                /* Clear errors */
989                griommu_reg_status_clear(status);
990        }
991
992        return status;
993}
994
995/* Print IOMMU masters
996 * DEBUG function
997 */
998int griommu_print(void)
999{
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
1041void * 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
1069void 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
1080int 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
1115int 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
1135int 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
1194int 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
1233int 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
1264int 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
1309int 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
1341int 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
1366int 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
1403int 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 */
1430int 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 */
1460int 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
Note: See TracBrowser for help on using the repository browser.