| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright (C) 2013-2014, 2018 Synopsys, Inc. All rights reserved. |
| */ |
| |
| #include <common.h> |
| #include <clock_legacy.h> |
| #include <init.h> |
| #include <malloc.h> |
| #include <vsprintf.h> |
| #include <asm/arcregs.h> |
| #include <asm/cache.h> |
| #include <asm/global_data.h> |
| #include <linux/bitops.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| int arch_cpu_init(void) |
| { |
| timer_init(); |
| |
| gd->cpu_clk = get_board_sys_clk(); |
| gd->ram_size = CFG_SYS_SDRAM_SIZE; |
| |
| cache_init(); |
| |
| return 0; |
| } |
| |
| /* This is a dummy function on arc */ |
| int dram_init(void) |
| { |
| return 0; |
| } |
| |
| #ifdef CONFIG_DISPLAY_CPUINFO |
| const char *arc_700_version(int arcver, char *name, int name_len) |
| { |
| const char *arc_ver; |
| |
| switch (arcver) { |
| case 0x32: |
| arc_ver = "v4.4-4.5"; |
| break; |
| case 0x33: |
| arc_ver = "v4.6-v4.9"; |
| break; |
| case 0x34: |
| arc_ver = "v4.10"; |
| break; |
| case 0x35: |
| arc_ver = "v4.11"; |
| break; |
| default: |
| arc_ver = "unknown version"; |
| } |
| |
| snprintf(name, name_len, "ARC 700 %s", arc_ver); |
| |
| return name; |
| } |
| |
| struct em_template_t { |
| const bool cache; |
| const bool dsp; |
| const bool xymem; |
| const char name[8]; |
| }; |
| |
| static const struct em_template_t em_versions[] = { |
| {false, false, false, "EM4"}, |
| {true, false, false, "EM6"}, |
| {false, true, false, "EM5D"}, |
| {true, true, false, "EM7D"}, |
| {false, true, true, "EM9D"}, |
| {true, true, true, "EM11D"}, |
| }; |
| |
| const char *arc_em_version(int arcver, char *name, int name_len) |
| { |
| const char *arc_name = "EM"; |
| const char *arc_ver; |
| bool cache = ARC_FEATURE_EXISTS(ARC_BCR_IC_BUILD); |
| bool dsp = ARC_FEATURE_EXISTS(ARC_AUX_DSP_BUILD); |
| bool xymem = ARC_FEATURE_EXISTS(ARC_AUX_XY_BUILD); |
| int i; |
| |
| for (i = 0; i < sizeof(em_versions) / sizeof(struct em_template_t); i++) { |
| if (em_versions[i].cache == cache && |
| em_versions[i].dsp == dsp && |
| em_versions[i].xymem == xymem) { |
| arc_name = em_versions[i].name; |
| break; |
| } |
| } |
| |
| switch (arcver) { |
| case 0x41: |
| arc_ver = "v1.1a"; |
| break; |
| case 0x42: |
| arc_ver = "v3.0"; |
| break; |
| case 0x43: |
| arc_ver = "v4.0"; |
| break; |
| case 0x44: |
| arc_ver = "v5.0"; |
| break; |
| default: |
| arc_ver = "unknown version"; |
| } |
| |
| snprintf(name, name_len, "ARC %s %s", arc_name, arc_ver); |
| |
| return name; |
| } |
| |
| struct hs_template_t { |
| const bool cache; |
| const bool mmu; |
| const bool dual_issue; |
| const bool dsp; |
| const char name[8]; |
| }; |
| |
| static const struct hs_template_t hs_versions[] = { |
| {false, false, false, false, "HS34"}, |
| {true, false, false, false, "HS36"}, |
| {true, true, false, false, "HS38"}, |
| {false, false, true, false, "HS44"}, |
| {true, false, true, false, "HS46"}, |
| {true, true, true, false, "HS48"}, |
| {false, false, true, true, "HS45D"}, |
| {true, false, true, true, "HS47D"}, |
| }; |
| |
| const char *arc_hs_version(int arcver, char *name, int name_len) |
| { |
| const char *arc_name = "HS"; |
| const char *arc_ver; |
| bool cache = ARC_FEATURE_EXISTS(ARC_BCR_IC_BUILD); |
| bool dsp = ARC_FEATURE_EXISTS(ARC_AUX_DSP_BUILD); |
| bool mmu = !!read_aux_reg(ARC_AUX_MMU_BCR); |
| bool dual_issue = arcver == 0x54 ? true : false; |
| int i; |
| |
| for (i = 0; i < sizeof(hs_versions) / sizeof(struct hs_template_t); i++) { |
| if (hs_versions[i].cache == cache && |
| hs_versions[i].mmu == mmu && |
| hs_versions[i].dual_issue == dual_issue && |
| hs_versions[i].dsp == dsp) { |
| arc_name = hs_versions[i].name; |
| break; |
| } |
| } |
| |
| switch (arcver) { |
| case 0x50: |
| arc_ver = "v1.0"; |
| break; |
| case 0x51: |
| arc_ver = "v2.0"; |
| break; |
| case 0x52: |
| arc_ver = "v2.1c"; |
| break; |
| case 0x53: |
| arc_ver = "v3.0"; |
| break; |
| case 0x54: |
| arc_ver = "v4.0"; |
| break; |
| default: |
| arc_ver = "unknown version"; |
| } |
| |
| snprintf(name, name_len, "ARC %s %s", arc_name, arc_ver); |
| |
| return name; |
| } |
| |
| const char *decode_identity(void) |
| { |
| #define MAX_CPU_NAME_LEN 64 |
| |
| int arcver = read_aux_reg(ARC_AUX_IDENTITY) & 0xff; |
| char *name = malloc(MAX_CPU_NAME_LEN); |
| |
| if (arcver >= 0x50) |
| return arc_hs_version(arcver, name, MAX_CPU_NAME_LEN); |
| else if (arcver >= 0x40) |
| return arc_em_version(arcver, name, MAX_CPU_NAME_LEN); |
| else if (arcver >= 0x30) |
| return arc_700_version(arcver, name, MAX_CPU_NAME_LEN); |
| else |
| return "Unknown ARC core"; |
| } |
| |
| const char *decode_subsystem(void) |
| { |
| int subsys_type = read_aux_reg(ARC_AUX_SUBSYS_BUILD) & GENMASK(3, 0); |
| |
| switch (subsys_type) { |
| case 0: return NULL; |
| case 2: return "ARC Sensor & Control IP Subsystem"; |
| case 3: return "ARC Data Fusion IP Subsystem"; |
| case 4: return "ARC Secure Subsystem"; |
| default: return "Unknown subsystem"; |
| }; |
| } |
| |
| __weak int print_cpuinfo(void) |
| { |
| const char *subsys_name = decode_subsystem(); |
| char mhz[8]; |
| |
| printf("CPU: %s at %s MHz\n", decode_identity(), |
| strmhz(mhz, gd->cpu_clk)); |
| |
| if (subsys_name) |
| printf("Subsys:%s\n", subsys_name); |
| |
| return 0; |
| } |
| #endif /* CONFIG_DISPLAY_CPUINFO */ |