add ability to do intr-binding based on given device tree node
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / gic_dt.c
1 #include <lunaix/types.h>
2 #include <asm/soc/gic.h>
3
4 #include <klibc/string.h>
5
6 static bool
7 __gic_predicate(struct dt_node_iter* iter, struct dt_node_base* pos)
8 {
9     if (likely(!pos->intr_controll)) {
10         return false;
11     }
12
13     return strneq(pos->compat.str_val, "arm,gic-", 8);
14 }
15
16 static bool
17 __its_predicate(struct dt_node_iter* iter, struct dt_node_base* pos)
18 {
19     return strneq(pos->compat.str_val, "arm,gic-v3-its", 14);
20 }
21
22 static void
23 __setup_pe_rdist(struct arm_gic* gic, struct dt_prop_iter* prop)
24 {
25     ptr_t base;
26     size_t len, off;
27     int i;
28
29     base = dtprop_reg_nextaddr(prop);
30     len  = dtprop_reg_nextlen(prop);
31
32     assert(len >= NR_CPU * FRAME_SIZE * 2);
33
34     i = 0;
35     base = ioremap(base, len);
36     off = base;
37
38     for (; i < NR_CPU; i++) {
39         gic->pes[i]._rd = (struct gic_rd*) (base + off);
40         off += sizeof(struct gic_rd);
41     }
42 }
43
44 static void
45 __create_its(struct arm_gic* gic, struct dt_node* gic_node)
46 {
47     struct dt_node* its_node;
48     struct dt_node_iter iter;
49     struct dt_prop_iter prop;
50     ptr_t its_base;
51     size_t its_size;
52
53     dt_begin_find(&iter, gic_node, __its_predicate, NULL);
54
55     if (!dt_find_next(&iter, (struct dt_node_base**)&its_node)) {
56         return;
57     }
58
59     dt_end_find(&iter);
60
61     dt_decode_reg(&prop, its_node, reg);
62
63     its_base = dtprop_reg_nextaddr(&prop);
64     its_size = dtprop_reg_nextlen(&prop);
65
66     assert(its_size >= sizeof(struct gic_its));
67
68     gic->mmrs.its = (struct gic_its*)ioremap(its_base, its_size);
69 }
70
71 void
72 gic_create_from_dt(struct arm_gic* gic)
73 {
74     struct dt_node* gic_node;
75     struct dt_node_iter iter;
76     struct dt_prop_iter prop;
77     ptr_t ptr;
78     size_t sz;
79
80     dt_begin_find(&iter, NULL, __gic_predicate, NULL);
81
82     if (!dt_find_next(&iter, (struct dt_node_base**)&gic_node)) {
83         fail("expected 'arm,gic-*' compatible node, but found none");
84     }
85
86     dt_end_find(&iter);
87
88     dt_decode_reg(&prop, gic_node, reg);
89
90     ptr = dtprop_reg_nextaddr(&prop);
91     sz  = dtprop_reg_nextlen(&prop);
92     gic->mmrs.dist_base = (gicreg_t*)ioremap(ptr, sz);
93
94     __setup_pe_rdist(gic, &prop);
95     
96     // ignore cpu_if, as we use sysreg to access them
97     dtprop_next_n(&prop, 2);
98     
99     // ignore vcpu_if, as we dont do any EL2 stuff
100
101     __create_its(gic, gic_node);
102
103     dt_bind_object(&gic_node->base, gic);
104 }
105
106 unsigned int;
107 gic_dtprop_interpret(struct gic_int_param* param, 
108                      struct dt_prop_val* val, int width)
109 {
110     struct dt_prop_iter* iter;
111     unsigned int v;
112
113     dt_decode(&iter, NULL, val, 1);
114
115     v = dtprop_u32_at(&iter, 0);
116     switch (v)
117     {
118     case 0:
119         param->class = GIC_SPI;
120         break;
121     case 1:
122         param->class = GIC_PPI;
123         break;
124     case 2:
125         param->class = GIC_SPI;
126         param->ext_range = true;
127     
128     default:
129         fail("invalid interrupt type");
130         break;
131     }
132
133     v = dtprop_u32_at(&iter, 2);
134     param->trigger = v == 1 ? GIC_TRIG_EDGE : GIC_TRIG_LEVEL;
135
136     param->group = GIC_G1NS;
137     param->rel_intid = dtprop_u32_at(&iter, 1);
138
139     return param->rel_intid;
140 }