1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Author: Huacai Chen <chenhuacai@loongson.cn>
4 * Copyright (C) 2020 Loongson Technology Corporation Limited
5 */
6
7 #include <linux/acpi.h>
8 #include <linux/dmi.h>
9 #include <linux/efi.h>
10 #include <linux/memblock.h>
11 #include <asm/acpi.h>
12 #include <asm/bootinfo.h>
13 #include <asm/cacheflush.h>
14 #include <asm/efi.h>
15 #include <asm/smp.h>
16 #include <asm/time.h>
17
18 #include <loongson.h>
19
20 #define SMBIOS_BIOSSIZE_OFFSET 0x09
21 #define SMBIOS_BIOSEXTERN_OFFSET 0x13
22 #define SMBIOS_FREQLOW_OFFSET 0x16
23 #define SMBIOS_FREQHIGH_OFFSET 0x17
24 #define SMBIOS_FREQLOW_MASK 0xFF
25 #define SMBIOS_CORE_PACKAGE_OFFSET 0x23
26 #define LOONGSON_EFI_ENABLE (1 << 3)
27
28 struct loongson_board_info b_info;
29 static const char dmi_empty_string[] = " ";
30 extern void __init arch_reserve_vmcore(void);
31 extern void __init arch_parse_crashkernel(void);
32
dmi_string_parse(const struct dmi_header * dm,u8 s)33 static const char *dmi_string_parse(const struct dmi_header *dm, u8 s)
34 {
35 const u8 *bp = ((u8 *) dm) + dm->length;
36
37 if (s) {
38 s--;
39 while (s > 0 && *bp) {
40 bp += strlen(bp) + 1;
41 s--;
42 }
43
44 if (*bp != 0) {
45 size_t len = strlen(bp)+1;
46 size_t cmp_len = len > 8 ? 8 : len;
47
48 if (!memcmp(bp, dmi_empty_string, cmp_len))
49 return dmi_empty_string;
50
51 return bp;
52 }
53 }
54
55 return "";
56
57 }
58
parse_cpu_table(const struct dmi_header * dm)59 static void __init parse_cpu_table(const struct dmi_header *dm)
60 {
61 long freq_temp = 0;
62 char *dmi_data = (char *)dm;
63
64 freq_temp = ((*(dmi_data + SMBIOS_FREQHIGH_OFFSET) << 8) + \
65 ((*(dmi_data + SMBIOS_FREQLOW_OFFSET)) & SMBIOS_FREQLOW_MASK));
66 cpu_clock_freq = freq_temp * 1000000;
67
68 loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]);
69 loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET);
70
71 pr_info("CpuClock = %llu\n", cpu_clock_freq);
72
73 }
74
parse_bios_table(const struct dmi_header * dm)75 static void __init parse_bios_table(const struct dmi_header *dm)
76 {
77 char *dmi_data = (char *)dm;
78
79 b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
80 }
81
find_tokens(const struct dmi_header * dm,void * dummy)82 static void __init find_tokens(const struct dmi_header *dm, void *dummy)
83 {
84 switch (dm->type) {
85 case 0x0: /* Extern BIOS */
86 parse_bios_table(dm);
87 break;
88 case 0x4: /* Calling interface */
89 parse_cpu_table(dm);
90 break;
91 }
92 }
93
smbios_parse(void)94 static void __init smbios_parse(void)
95 {
96 b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
97 b_info.bios_version = (void *)dmi_get_system_info(DMI_BIOS_VERSION);
98 b_info.bios_release_date = (void *)dmi_get_system_info(DMI_BIOS_DATE);
99 b_info.board_vendor = (void *)dmi_get_system_info(DMI_BOARD_VENDOR);
100 b_info.board_name = (void *)dmi_get_system_info(DMI_BOARD_NAME);
101 dmi_walk(find_tokens, NULL);
102 }
103
early_init(void)104 void __init early_init(void)
105 {
106 init_environ();
107 efi_init();
108 memblock_init();
109 }
110
platform_init(void)111 void __init platform_init(void)
112 {
113 arch_reserve_vmcore();
114 arch_parse_crashkernel();
115
116 #ifdef CONFIG_ACPI_TABLE_UPGRADE
117 acpi_table_upgrade();
118 #endif
119 #ifdef CONFIG_ACPI
120 acpi_gbl_use_default_register_widths = false;
121 acpi_boot_table_init();
122 #endif
123
124 #ifdef CONFIG_NUMA
125 init_numa_memory();
126 #endif
127 dmi_setup();
128 smbios_parse();
129 pr_info("The BIOS Version: %s\n",b_info.bios_version);
130
131 efi_runtime_init();
132
133 register_smp_ops(&loongson3_smp_ops);
134 }
135