From 07d84f4f3486825dcfd25a854bca39e5f7335c8d Mon Sep 17 00:00:00 2001 From: Dongyan Qian Date: Mon, 12 May 2025 19:56:30 +0800 Subject: [PATCH] loongarch: Supports 2K2000/3B6000M (#512) * loongarch: adjust 2K/3B6000M DDR rate factor * loongarch: Supports fewer cache layers than L3 For example: 2K2000 chip does not have L3, but has L2. If L2Cache is not flushed to memory, it will cause read and write data errors after cache_off. --- system/cache.h | 32 ++++++++++++++++++++++++------ system/imc/loongarch/loongson_la.c | 6 ++++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/system/cache.h b/system/cache.h index 81074af..148e31f 100644 --- a/system/cache.h +++ b/system/cache.h @@ -94,12 +94,22 @@ static inline void cache_flush(void) : "memory" ); #elif defined (__loongarch_lp64) - if (!(__cpucfg(0x10) & (1 << 10))) { - return; // No L3 + uint64_t cache_present, cache_info_reg; + /*detect_max_cache_level*/ + if (__cpucfg(0x10) & (1 << 10)) { + cache_present = 3; //L3 unified cache + } else if (__cpucfg(0x10) & (1 << 3)) { + cache_present = 2; //L2 unified cache + } else if (__cpucfg(0x10) & (1 << 0)) { + cache_present = 1; //L1 data cache + } else { + return; //No Cache present } - uint64_t ways = (__cpucfg(0x14) & 0xFFFF) + 1; - uint64_t sets = 1 << ((__cpucfg(0x14) >> 16) & 0xFF); - uint64_t line_size = 1 << ((__cpucfg(0x14) >> 24) & 0x7F); + cache_info_reg = 0x11 + cache_present; //cache last leaf + + uint64_t ways = (__cpucfg(cache_info_reg) & 0xFFFF) + 1; + uint64_t sets = 1 << ((__cpucfg(cache_info_reg) >> 16) & 0xFF); + uint64_t line_size = 1 << ((__cpucfg(cache_info_reg) >> 24) & 0x7F); uint64_t va, i, j; uint64_t cpu_module[1]; va = 0; @@ -119,7 +129,17 @@ static inline void cache_flush(void) } else { for (i = 0; i < sets; i++) { for (j = 0; j < ways; j++) { - cache_op(0xB, va); + switch (cache_present) { + case 1: + cache_op(0x9,va); //Flush L1 + break; + case 2: + cache_op(0xA,va); //Flush L2 + break; + case 3: + cache_op(0xB,va); //Flush L3 + break; + } va++; } va -= ways; diff --git a/system/imc/loongarch/loongson_la.c b/system/imc/loongarch/loongson_la.c index e6deb1a..ba0a4cc 100644 --- a/system/imc/loongarch/loongson_la.c +++ b/system/imc/loongarch/loongson_la.c @@ -123,11 +123,12 @@ void get_imc_config_loongson_ddr4(void) { uint32_t val; uint16_t refc, loopc, div, div_mode, ref_clk; - uint8_t max_mc, node_num; + uint8_t max_mc, node_num, ddr_rate_factor; bool route_flag; imc.type = "DDR4"; node_num = 1; + ddr_rate_factor = 4; if (strstr(cpuid_info.brand_id.str, "3C") || (strstr(cpuid_info.brand_id.str, "3B6000") && @@ -150,6 +151,7 @@ void get_imc_config_loongson_ddr4(void) strstr(cpuid_info.brand_id.str, "3B6000M")) { route_flag = false; max_mc = 1; + ddr_rate_factor = 2; } else { route_flag = false; max_mc = 0; @@ -164,7 +166,7 @@ void get_imc_config_loongson_ddr4(void) div_mode = 0x1 << ((val >> 4) & 0x3); refc = (val >> 8) & 0x1f; ref_clk = (uint16_t)(((__cpucfg(0x4) * (__cpucfg(0x5) & 0xFFFF)) / ((__cpucfg(0x5) >> 16) & 0xFFFF)) / 1000000); - imc.freq = (ref_clk * loopc / refc / div / div_mode) * 4; + imc.freq = (ref_clk * loopc / refc / div / div_mode) * ddr_rate_factor; } else { imc.freq = 0; }