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