source: rtems/bsps/sparc/shared/amba/ahbstat.c @ a7267241

Last change on this file since a7267241 was a7267241, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 26, 2018 at 2:44:25 PM

bsps/sparc: Add and use <grlib_impl.h>

Reduce copy and paste.

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*  AHB Status register driver
2 *
3 *  COPYRIGHT (c) 2009 - 2017.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.org/license/LICENSE.
9 */
10
11#include <stdint.h>
12#include <string.h>
13#include <rtems.h>
14#include <rtems/bspIo.h>
15#include <drvmgr/drvmgr.h>
16#include <drvmgr/ambapp_bus.h>
17
18#include <bsp/ahbstat.h>
19
20#include <grlib_impl.h>
21
22#define REG_WRITE(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
23#define REG_READ(addr) (*(volatile uint32_t *)(addr))
24
25void ahbstat_isr(void *arg);
26
27/* AHB fail interrupt callback to user. This function is declared weak so that
28 * the user can define a function pointer variable containing the address
29 * responsible for handling errors
30 *
31 * minor              Index of AHBSTAT hardware
32 * regs               Register address of AHBSTAT
33 * status             AHBSTAT status register at IRQ
34 * failing_address    AHBSTAT Failing address register at IRQ
35 *
36 * * User return
37 *  0: print error onto terminal with printk and reenable AHBSTAT
38 *  1: just re-enable AHBSTAT
39 *  2: just print error
40 *  3: do nothing, let user do custom handling
41 */
42int (*ahbstat_error)(
43        int minor,
44        struct ahbstat_regs *regs,
45        uint32_t status,
46        uint32_t failing_address
47        ) __attribute__((weak)) = NULL;
48
49#define AHBSTAT_STS_CE_BIT 9
50#define AHBSTAT_STS_NE_BIT 8
51#define AHBSTAT_STS_HW_BIT 7
52#define AHBSTAT_STS_HM_BIT 3
53#define AHBSTAT_STS_HS_BIT 0
54
55#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
56#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
57#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)
58#define AHBSTAT_STS_HM (0xf << AHBSTAT_STS_HM_BIT)
59#define AHBSTAT_STS_HS (0x7 << AHBSTAT_STS_HS_BIT)
60
61enum { DEVNAME_LEN = 9 };
62struct ahbstat_priv {
63        struct drvmgr_dev *dev;
64        struct ahbstat_regs *regs;
65        char devname[DEVNAME_LEN];
66        int minor;
67        /* Cached error */
68        uint32_t last_status;
69        uint32_t last_address;
70        /* Spin-lock ISR protection */
71        SPIN_DECLARE(devlock);
72};
73
74static int ahbstat_init2(struct drvmgr_dev *dev);
75
76struct drvmgr_drv_ops ahbstat_ops =
77{
78        .init = {NULL, ahbstat_init2, NULL, NULL},
79        .remove = NULL,
80        .info = NULL
81};
82
83struct amba_dev_id ahbstat_ids[] =
84{
85        {VENDOR_GAISLER, GAISLER_AHBSTAT},
86        {0, 0}          /* Mark end of table */
87};
88
89struct amba_drv_info ahbstat_drv_info =
90{
91        {
92                DRVMGR_OBJ_DRV,                 /* Driver */
93                NULL,                           /* Next driver */
94                NULL,                           /* Device list */
95                DRIVER_AMBAPP_GAISLER_AHBSTAT_ID,/* Driver ID */
96                "AHBSTAT_DRV",                  /* Driver Name */
97                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
98                &ahbstat_ops,
99                NULL,                           /* Funcs */
100                0,                              /* No devices yet */
101                sizeof(struct ahbstat_priv),
102        },
103        &ahbstat_ids[0]
104};
105
106void ahbstat_register_drv (void)
107{
108        drvmgr_drv_register(&ahbstat_drv_info.general);
109}
110
111static int ahbstat_init2(struct drvmgr_dev *dev)
112{
113        struct ahbstat_priv *priv;
114        struct amba_dev_info *ambadev;
115
116        priv = dev->priv;
117        if (!priv)
118                return DRVMGR_NOMEM;
119        priv->dev = dev;
120
121        /* Get device information from AMBA PnP information */
122        ambadev = (struct amba_dev_info *)dev->businfo;
123        if (ambadev == NULL)
124                return DRVMGR_FAIL;
125        priv->regs = (struct ahbstat_regs *)ambadev->info.apb_slv->start;
126        priv->minor = dev->minor_drv;
127
128        strncpy(&priv->devname[0], "ahbstat0", DEVNAME_LEN);
129        priv->devname[7] += priv->minor;
130        /*
131         * Initialize spinlock for AHBSTAT Device. It is used to protect user
132         * API calls involivng priv structure from updates in ISR.
133         */
134        SPIN_INIT(&priv->devlock, priv->devname);
135
136        /* Initialize hardware */
137        REG_WRITE(&priv->regs->status, 0);
138
139        /* Install IRQ handler */
140        drvmgr_interrupt_register(dev, 0, priv->devname, ahbstat_isr, priv);
141
142        return DRVMGR_OK;
143}
144
145void ahbstat_isr(void *arg)
146{
147        struct ahbstat_priv *priv = arg;
148        uint32_t fadr, status;
149        int rc;
150        SPIN_ISR_IRQFLAGS(lock_context);
151
152        /* Get hardware status */
153        status = REG_READ(&priv->regs->status);
154        if ((status & AHBSTAT_STS_NE) == 0)
155                return;
156
157        /* IRQ generated by AHBSTAT core... handle it here */
158
159        /* Get Failing address */
160        fadr = REG_READ(&priv->regs->failing);
161
162        SPIN_LOCK(&priv->devlock, lock_context);
163        priv->last_status = status;
164        priv->last_address = fadr;
165        SPIN_UNLOCK(&priv->devlock, lock_context);
166
167        /* Let user handle error, default to print the error and reenable HW
168         *
169         * User return
170         *  0: print error and reenable AHBSTAT
171         *  1: just reenable AHBSTAT
172         *  2: just print error
173         *  3: do nothing
174         */
175        rc = 0;
176        if (ahbstat_error != NULL)
177                rc = ahbstat_error(priv->minor, priv->regs, status, fadr);
178
179        if ((rc & 0x1) == 0) {
180                printk("\n### AHBSTAT: %s %s error of size %ld by master %ld"
181                        " at 0x%08lx\n",
182                        status & AHBSTAT_STS_CE ? "single" : "non-correctable",
183                        status & AHBSTAT_STS_HW ? "write" : "read",
184                        (status & AHBSTAT_STS_HS) >> AHBSTAT_STS_HS_BIT,
185                        (status & AHBSTAT_STS_HM) >> AHBSTAT_STS_HM_BIT,
186                        fadr);
187        }
188
189        if ((rc & 0x2) == 0) {
190                /* Trigger new interrupts */
191                REG_WRITE(&priv->regs->status, 0);
192        }
193}
194
195/* Get Last received AHB Error
196 *
197 * Return
198 *   0: No error received
199 *   1: Error Received, last status and address stored into argument pointers
200 *  -1: No such AHBSTAT device
201 */
202int ahbstat_last_error(int minor, uint32_t *status, uint32_t *address)
203{
204        struct drvmgr_dev *dev;
205        struct ahbstat_priv *priv;
206        uint32_t last_status;
207        uint32_t last_address;
208        SPIN_IRQFLAGS(lock_context);
209
210        if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
211                return -1;
212        }
213        priv = (struct ahbstat_priv *)dev->priv;
214
215        /* Read information cached by ISR */
216        SPIN_LOCK_IRQ(&priv->devlock, lock_context);
217        last_status = REG_READ(&priv->last_status);
218        last_address = REG_READ(&priv->last_address);
219        SPIN_UNLOCK_IRQ(&priv->devlock, lock_context);
220
221        *status = last_status;
222        *address = last_address;
223
224        return (last_status & AHBSTAT_STS_NE) >> AHBSTAT_STS_NE_BIT;
225}
226
227/* Get AHBSTAT registers address from minor. NULL returned if no such device */
228struct ahbstat_regs *ahbstat_get_regs(int minor)
229{
230        struct drvmgr_dev *dev;
231        struct ahbstat_priv *priv;
232
233        if (drvmgr_get_dev(&ahbstat_drv_info.general, minor, &dev)) {
234                return NULL;
235        }
236        priv = (struct ahbstat_priv *)dev->priv;
237
238        return priv->regs;
239}
Note: See TracBrowser for help on using the repository browser.