1*db0ae91cSAndrew Jones // SPDX-License-Identifier: GPL-2.0-only
2*db0ae91cSAndrew Jones /*
3*db0ae91cSAndrew Jones * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
4*db0ae91cSAndrew Jones */
5*db0ae91cSAndrew Jones #include <libcflat.h>
6*db0ae91cSAndrew Jones #include <bitops.h>
7*db0ae91cSAndrew Jones #include <devicetree.h>
8*db0ae91cSAndrew Jones #include <string.h>
9*db0ae91cSAndrew Jones #include <asm/isa.h>
10*db0ae91cSAndrew Jones #include <asm/setup.h>
11*db0ae91cSAndrew Jones
12*db0ae91cSAndrew Jones typedef void (*isa_func_t)(const char *, int, void *);
13*db0ae91cSAndrew Jones
14*db0ae91cSAndrew Jones struct isa_info {
15*db0ae91cSAndrew Jones unsigned long hartid;
16*db0ae91cSAndrew Jones isa_func_t func;
17*db0ae91cSAndrew Jones void *data;
18*db0ae91cSAndrew Jones };
19*db0ae91cSAndrew Jones
isa_match(const char * ext,const char * name,int len)20*db0ae91cSAndrew Jones static bool isa_match(const char *ext, const char *name, int len)
21*db0ae91cSAndrew Jones {
22*db0ae91cSAndrew Jones return len == strlen(ext) && !strncasecmp(name, ext, len);
23*db0ae91cSAndrew Jones }
24*db0ae91cSAndrew Jones
25*db0ae91cSAndrew Jones struct isa_check {
26*db0ae91cSAndrew Jones const char *ext;
27*db0ae91cSAndrew Jones bool found;
28*db0ae91cSAndrew Jones };
29*db0ae91cSAndrew Jones
isa_name(const char * name,int len,void * data)30*db0ae91cSAndrew Jones static void isa_name(const char *name, int len, void *data)
31*db0ae91cSAndrew Jones {
32*db0ae91cSAndrew Jones struct isa_check *check = (struct isa_check *)data;
33*db0ae91cSAndrew Jones
34*db0ae91cSAndrew Jones if (isa_match(check->ext, name, len))
35*db0ae91cSAndrew Jones check->found = true;
36*db0ae91cSAndrew Jones }
37*db0ae91cSAndrew Jones
isa_bit(const char * name,int len,void * data)38*db0ae91cSAndrew Jones static void isa_bit(const char *name, int len, void *data)
39*db0ae91cSAndrew Jones {
40*db0ae91cSAndrew Jones struct thread_info *info = (struct thread_info *)data;
41*db0ae91cSAndrew Jones
42*db0ae91cSAndrew Jones if (isa_match("sstc", name, len))
43*db0ae91cSAndrew Jones set_bit(ISA_SSTC, info->isa);
44*db0ae91cSAndrew Jones }
45*db0ae91cSAndrew Jones
isa_parse(const char * isa_string,int len,struct isa_info * info)46*db0ae91cSAndrew Jones static void isa_parse(const char *isa_string, int len, struct isa_info *info)
47*db0ae91cSAndrew Jones {
48*db0ae91cSAndrew Jones assert(isa_string[0] == 'r' && isa_string[1] == 'v');
49*db0ae91cSAndrew Jones #if __riscv_xlen == 32
50*db0ae91cSAndrew Jones assert(isa_string[2] == '3' && isa_string[3] == '2');
51*db0ae91cSAndrew Jones #else
52*db0ae91cSAndrew Jones assert(isa_string[2] == '6' && isa_string[3] == '4');
53*db0ae91cSAndrew Jones #endif
54*db0ae91cSAndrew Jones
55*db0ae91cSAndrew Jones for (int i = 4; i < len; ++i) {
56*db0ae91cSAndrew Jones if (isa_string[i] == '_') {
57*db0ae91cSAndrew Jones const char *multi = &isa_string[++i];
58*db0ae91cSAndrew Jones int start = i;
59*db0ae91cSAndrew Jones
60*db0ae91cSAndrew Jones while (i < len - 1 && isa_string[i] != '_')
61*db0ae91cSAndrew Jones ++i;
62*db0ae91cSAndrew Jones info->func(multi, i - start, info->data);
63*db0ae91cSAndrew Jones if (i < len - 1)
64*db0ae91cSAndrew Jones --i;
65*db0ae91cSAndrew Jones } else {
66*db0ae91cSAndrew Jones info->func(&isa_string[i], 1, info->data);
67*db0ae91cSAndrew Jones }
68*db0ae91cSAndrew Jones }
69*db0ae91cSAndrew Jones }
70*db0ae91cSAndrew Jones
isa_parse_fdt(int cpu_node,u64 hartid,void * data)71*db0ae91cSAndrew Jones static void isa_parse_fdt(int cpu_node, u64 hartid, void *data)
72*db0ae91cSAndrew Jones {
73*db0ae91cSAndrew Jones struct isa_info *info = (struct isa_info *)data;
74*db0ae91cSAndrew Jones const struct fdt_property *prop;
75*db0ae91cSAndrew Jones int len;
76*db0ae91cSAndrew Jones
77*db0ae91cSAndrew Jones if (hartid != info->hartid)
78*db0ae91cSAndrew Jones return;
79*db0ae91cSAndrew Jones
80*db0ae91cSAndrew Jones prop = fdt_get_property(dt_fdt(), cpu_node, "riscv,isa", &len);
81*db0ae91cSAndrew Jones assert(prop);
82*db0ae91cSAndrew Jones
83*db0ae91cSAndrew Jones isa_parse(prop->data, len, info);
84*db0ae91cSAndrew Jones }
85*db0ae91cSAndrew Jones
isa_init_acpi(void)86*db0ae91cSAndrew Jones static void isa_init_acpi(void)
87*db0ae91cSAndrew Jones {
88*db0ae91cSAndrew Jones assert_msg(false, "ACPI not available");
89*db0ae91cSAndrew Jones }
90*db0ae91cSAndrew Jones
isa_init(struct thread_info * ti)91*db0ae91cSAndrew Jones void isa_init(struct thread_info *ti)
92*db0ae91cSAndrew Jones {
93*db0ae91cSAndrew Jones struct isa_info info = {
94*db0ae91cSAndrew Jones .hartid = ti->hartid,
95*db0ae91cSAndrew Jones .func = isa_bit,
96*db0ae91cSAndrew Jones .data = ti,
97*db0ae91cSAndrew Jones };
98*db0ae91cSAndrew Jones int ret;
99*db0ae91cSAndrew Jones
100*db0ae91cSAndrew Jones if (dt_available()) {
101*db0ae91cSAndrew Jones ret = dt_for_each_cpu_node(isa_parse_fdt, &info);
102*db0ae91cSAndrew Jones assert(ret == 0);
103*db0ae91cSAndrew Jones } else {
104*db0ae91cSAndrew Jones isa_init_acpi();
105*db0ae91cSAndrew Jones }
106*db0ae91cSAndrew Jones }
107*db0ae91cSAndrew Jones
cpu_has_extension_name(int cpu,const char * ext)108*db0ae91cSAndrew Jones bool cpu_has_extension_name(int cpu, const char *ext)
109*db0ae91cSAndrew Jones {
110*db0ae91cSAndrew Jones struct isa_info info = {
111*db0ae91cSAndrew Jones .hartid = cpus[cpu].hartid,
112*db0ae91cSAndrew Jones .func = isa_name,
113*db0ae91cSAndrew Jones .data = &(struct isa_check){ .ext = ext, },
114*db0ae91cSAndrew Jones };
115*db0ae91cSAndrew Jones struct isa_check *check = info.data;
116*db0ae91cSAndrew Jones int ret;
117*db0ae91cSAndrew Jones
118*db0ae91cSAndrew Jones if (dt_available()) {
119*db0ae91cSAndrew Jones ret = dt_for_each_cpu_node(isa_parse_fdt, &info);
120*db0ae91cSAndrew Jones assert(ret == 0);
121*db0ae91cSAndrew Jones } else {
122*db0ae91cSAndrew Jones assert_msg(false, "ACPI not available");
123*db0ae91cSAndrew Jones }
124*db0ae91cSAndrew Jones
125*db0ae91cSAndrew Jones return check->found;
126*db0ae91cSAndrew Jones }
127