1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-01-30     GuEe-GUI     first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 
14 #define DBG_TAG "pic.gic*"
15 #define DBG_LVL DBG_LOG
16 #include <rtdbg.h>
17 
18 #include <drivers/pic.h>
19 
20 #include "pic-gicv2.h"
21 #include "pic-gic-common.h"
22 
gic_common_init_quirk_ofw(const struct rt_ofw_node * ic_np,const struct gic_quirk * quirks,void * data)23 void gic_common_init_quirk_ofw(const struct rt_ofw_node *ic_np, const struct gic_quirk *quirks, void *data)
24 {
25     for (; quirks->desc; ++quirks)
26     {
27         if (!quirks->compatible || !rt_ofw_node_is_compatible(ic_np, quirks->compatible))
28         {
29             continue;
30         }
31 
32         RT_ASSERT(quirks->init != RT_NULL);
33 
34         if (!quirks->init(data))
35         {
36             LOG_I("Enable workaround for %s", quirks->desc);
37         }
38     }
39 }
40 
gic_common_init_quirk_hw(rt_uint32_t iidr,const struct gic_quirk * quirks,void * data)41 void gic_common_init_quirk_hw(rt_uint32_t iidr, const struct gic_quirk *quirks, void *data)
42 {
43     for (; quirks->desc; ++quirks)
44     {
45         if (quirks->compatible)
46         {
47             continue;
48         }
49 
50         if (quirks->iidr == (iidr & quirks->iidr_mask))
51         {
52             RT_ASSERT(quirks->init != RT_NULL);
53 
54             if (!quirks->init(data))
55             {
56                 LOG_I("Enable workaround for %s", quirks->desc);
57             }
58         }
59     }
60 }
61 
gic_common_sgi_config(void * base,void * data,int irq_base)62 void gic_common_sgi_config(void *base, void *data, int irq_base)
63 {
64 #ifdef RT_USING_SMP
65     if (irq_base < RT_MAX_IPI)
66     {
67         struct rt_pic_irq *pirq;
68 
69         for (int ipi = 0; ipi < RT_MAX_IPI; ++ipi)
70         {
71             rt_pic_config_ipi(data, ipi, ipi);
72             pirq = rt_pic_find_ipi(data, ipi);
73             pirq->mode = RT_IRQ_MODE_EDGE_RISING;
74         }
75     }
76 #endif /* RT_USING_SMP */
77 }
78 
gic_common_configure_irq(void * base,int irq,rt_uint32_t mode,void (* sync_access)(void *),void * data)79 rt_err_t gic_common_configure_irq(void *base, int irq, rt_uint32_t mode, void (*sync_access)(void *), void *data)
80 {
81     rt_err_t err = RT_EOK;
82     rt_ubase_t level;
83     rt_uint32_t val, oldval;
84     rt_uint32_t confoff = (irq / 16) * 4;
85     rt_uint32_t confmask = 0x2 << ((irq % 16) * 2);
86     static RT_DEFINE_SPINLOCK(ic_lock);
87 
88     level = rt_spin_lock_irqsave(&ic_lock);
89 
90     val = oldval = HWREG32(base + confoff);
91 
92     if (mode & RT_IRQ_MODE_LEVEL_MASK)
93     {
94         /* Level-sensitive */
95         val &= ~confmask;
96     }
97     else if (mode & RT_IRQ_MODE_EDGE_BOTH)
98     {
99         /* Edge-triggered */
100         val |= confmask;
101     }
102 
103     if (val != oldval)
104     {
105         HWREG32(base + confoff) = val;
106 
107         if (HWREG32(base + confoff) != val)
108         {
109             err = -RT_EINVAL;
110         }
111         if (sync_access)
112         {
113             sync_access(data);
114         }
115     }
116 
117     rt_spin_unlock_irqrestore(&ic_lock, level);
118 
119     return err;
120 }
121 
gic_common_dist_config(void * base,int max_irqs,void (* sync_access)(void *),void * data)122 void gic_common_dist_config(void *base, int max_irqs, void (*sync_access)(void *), void *data)
123 {
124     rt_uint32_t i;
125 
126     /* Set all global interrupts to be level triggered, active low. */
127     for (i = 32; i < max_irqs; i += 16)
128     {
129         HWREG32(base + GIC_DIST_CONFIG + i / 4) = GICD_INT_ACTLOW_LVLTRIG;
130     }
131 
132     /* Set priority on all global interrupts. */
133     for (i = 32; i < max_irqs; i += 4)
134     {
135         HWREG32(base + GIC_DIST_PRI + i * 4 / 4) = GICD_INT_DEF_PRI_X4;
136     }
137 
138     /* Disable all SPIs. */
139     for (i = 32; i < max_irqs; i += 32)
140     {
141         HWREG32(base + GIC_DIST_ACTIVE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
142         HWREG32(base + GIC_DIST_ENABLE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
143     }
144 
145     if (sync_access)
146     {
147         sync_access(data);
148     }
149 }
150 
gic_common_cpu_config(void * base,int nr,void (* sync_access)(void *),void * data)151 void gic_common_cpu_config(void *base, int nr, void (*sync_access)(void *), void *data)
152 {
153     rt_uint32_t i;
154 
155     /* Disable all SGIs, PPIs. */
156     for (i = 0; i < nr; i += 32)
157     {
158         HWREG32(base + GIC_DIST_ACTIVE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
159         HWREG32(base + GIC_DIST_ENABLE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
160     }
161 
162     /* Set priority on all PPI and SGI. */
163     for (i = 0; i < nr; i += 4)
164     {
165         HWREG32(base + GIC_DIST_PRI + i * 4 / 4) = GICD_INT_DEF_PRI_X4;
166     }
167 
168     if (sync_access)
169     {
170         sync_access(data);
171     }
172 }
173 
gic_fill_ppi_affinity(rt_bitmap_t * affinity)174 void gic_fill_ppi_affinity(rt_bitmap_t *affinity)
175 {
176     for (int cpuid = 0; cpuid < RT_CPUS_NR; ++cpuid)
177     {
178         RT_IRQ_AFFINITY_SET(affinity, cpuid);
179     }
180 }
181