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 28struct loongson_board_info b_info; 29static const char dmi_empty_string[] = " "; 30extern void __init arch_reserve_vmcore(void); 31extern void __init arch_parse_crashkernel(void); 32 33static 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 59static 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 75static 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 82static 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 94static 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 104void __init early_init(void) 105{ 106 init_environ(); 107 efi_init(); 108 memblock_init(); 109} 110 111void __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