Merge remote-tracking branch 'spi/for-5.14' into spi-next
[linux-2.6-microblaze.git] / drivers / firmware / efi / fdtparams.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #define pr_fmt(fmt) "efi: " fmt
4
5 #include <linux/module.h>
6 #include <linux/init.h>
7 #include <linux/efi.h>
8 #include <linux/libfdt.h>
9 #include <linux/of_fdt.h>
10
11 #include <asm/unaligned.h>
12
13 enum {
14         SYSTAB,
15         MMBASE,
16         MMSIZE,
17         DCSIZE,
18         DCVERS,
19
20         PARAMCOUNT
21 };
22
23 static __initconst const char name[][22] = {
24         [SYSTAB] = "System Table         ",
25         [MMBASE] = "MemMap Address       ",
26         [MMSIZE] = "MemMap Size          ",
27         [DCSIZE] = "MemMap Desc. Size    ",
28         [DCVERS] = "MemMap Desc. Version ",
29 };
30
31 static __initconst const struct {
32         const char      path[17];
33         const char      params[PARAMCOUNT][26];
34 } dt_params[] = {
35         {
36 #ifdef CONFIG_XEN    //  <-------17------>
37                 .path = "/hypervisor/uefi",
38                 .params = {
39                         [SYSTAB] = "xen,uefi-system-table",
40                         [MMBASE] = "xen,uefi-mmap-start",
41                         [MMSIZE] = "xen,uefi-mmap-size",
42                         [DCSIZE] = "xen,uefi-mmap-desc-size",
43                         [DCVERS] = "xen,uefi-mmap-desc-ver",
44                 }
45         }, {
46 #endif
47                 .path = "/chosen",
48                 .params = {     //  <-----------26----------->
49                         [SYSTAB] = "linux,uefi-system-table",
50                         [MMBASE] = "linux,uefi-mmap-start",
51                         [MMSIZE] = "linux,uefi-mmap-size",
52                         [DCSIZE] = "linux,uefi-mmap-desc-size",
53                         [DCVERS] = "linux,uefi-mmap-desc-ver",
54                 }
55         }
56 };
57
58 static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
59                                    const char *rname, void *var, int size)
60 {
61         const void *prop;
62         int len;
63         u64 val;
64
65         prop = fdt_getprop(fdt, node, pname, &len);
66         if (!prop)
67                 return 1;
68
69         val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
70
71         if (size == 8)
72                 *(u64 *)var = val;
73         else
74                 *(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
75
76         if (efi_enabled(EFI_DBG))
77                 pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
78
79         return 0;
80 }
81
82 u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
83 {
84         const void *fdt = initial_boot_params;
85         unsigned long systab;
86         int i, j, node;
87         struct {
88                 void    *var;
89                 int     size;
90         } target[] = {
91                 [SYSTAB] = { &systab,           sizeof(systab) },
92                 [MMBASE] = { &mm->phys_map,     sizeof(mm->phys_map) },
93                 [MMSIZE] = { &mm->size,         sizeof(mm->size) },
94                 [DCSIZE] = { &mm->desc_size,    sizeof(mm->desc_size) },
95                 [DCVERS] = { &mm->desc_version, sizeof(mm->desc_version) },
96         };
97
98         BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
99         BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
100
101         if (!fdt)
102                 return 0;
103
104         for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
105                 node = fdt_path_offset(fdt, dt_params[i].path);
106                 if (node < 0)
107                         continue;
108
109                 if (efi_enabled(EFI_DBG))
110                         pr_info("Getting UEFI parameters from %s in DT:\n",
111                                 dt_params[i].path);
112
113                 for (j = 0; j < ARRAY_SIZE(target); j++) {
114                         const char *pname = dt_params[i].params[j];
115
116                         if (!efi_get_fdt_prop(fdt, node, pname, name[j],
117                                               target[j].var, target[j].size))
118                                 continue;
119                         if (!j)
120                                 goto notfound;
121                         pr_err("Can't find property '%s' in DT!\n", pname);
122                         return 0;
123                 }
124                 return systab;
125         }
126 notfound:
127         pr_info("UEFI not found.\n");
128         return 0;
129 }