• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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