diff options
author | andy.hu <andy.hu@starfivetech.com> | 2024-01-11 13:51:49 +0300 |
---|---|---|
committer | andy.hu <andy.hu@starfivetech.com> | 2024-01-11 13:51:49 +0300 |
commit | c1d57ddbd8dbd3a27bbb79350e5eebf9efa5dcc9 (patch) | |
tree | df1be5568eff88f80a60725d122dea1cb173ee12 | |
parent | d0237157652606535fdc0a5414154fa48dfd16f2 (diff) | |
parent | d8e951fa4d36c72b81810a105d7de3f8edb0902a (diff) | |
download | linux-c1d57ddbd8dbd3a27bbb79350e5eebf9efa5dcc9.tar.xz |
Merge branch 'CR_8959_linux515_Implement_new_flush_L2_cache_method_Windsome.Zeng' into 'jh7110-5.15.y-devel'
CR 8959 Implement a new method to flush the entire L2 cache
See merge request sdk/linux!1006
-rwxr-xr-x | arch/riscv/boot/dts/starfive/jh7110.dtsi | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/verisilicon/vs_dc.c | 7 | ||||
-rw-r--r-- | drivers/soc/sifive/sifive_l2_cache.c | 102 | ||||
-rw-r--r-- | include/soc/sifive/sifive_l2_cache.h | 1 |
4 files changed, 95 insertions, 17 deletions
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 1afd18c13cb2..b6ca7efffbc3 100755 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -245,7 +245,7 @@ cachectrl: cache-controller@2010000 { compatible = "sifive,fu740-c000-ccache", "cache"; - reg = <0x0 0x2010000 0x0 0x4000 0x0 0x8000000 0x0 0x2000000>; + reg = <0x0 0x2010000 0x0 0x4000 0x0 0x8000000 0x0 0x2000000 0x0 0xa000000 0x0 0x2000000>; reg-names = "control", "sideband"; interrupts = <1 3 4 2>; cache-block-size = <64>; diff --git a/drivers/gpu/drm/verisilicon/vs_dc.c b/drivers/gpu/drm/verisilicon/vs_dc.c index f6d8749183e6..b16875aac385 100644 --- a/drivers/gpu/drm/verisilicon/vs_dc.c +++ b/drivers/gpu/drm/verisilicon/vs_dc.c @@ -959,12 +959,7 @@ static void update_fb(struct vs_plane *plane, u8 display_id, update_swizzle(drm_fb->format->format, fb); update_watermark(plane_state->watermark, fb); - sifive_l2_flush64_range(fb->y_address, fb->height * fb->y_stride); - if (fb->u_address) - sifive_l2_flush64_range(fb->u_address, fb->height * fb->u_stride); - if (fb->v_address) - sifive_l2_flush64_range(fb->v_address, fb->height * fb->v_stride); - + sifive_ccache_flush_entire(); plane_state->status.tile_mode = fb->tile_mode; } diff --git a/drivers/soc/sifive/sifive_l2_cache.c b/drivers/soc/sifive/sifive_l2_cache.c index 243bf43edb9c..8af044676c05 100644 --- a/drivers/soc/sifive/sifive_l2_cache.c +++ b/drivers/soc/sifive/sifive_l2_cache.c @@ -35,19 +35,32 @@ #define SIFIVE_L2_FLUSH64 0x200 #define SIFIVE_L2_FLUSH32 0x240 +#define SIFIVE_L2_WAYMASK_BASE 0x800 +#define SIFIVE_L2_MAX_MASTER_ID 32 + #define SIFIVE_L2_CONFIG 0x00 #define SIFIVE_L2_WAYENABLE 0x08 #define SIFIVE_L2_ECCINJECTERR 0x40 #define SIFIVE_L2_MAX_ECCINTR 4 -#define SIFIVE_L2_FLUSH64_LINE_LEN 64 +#define SIFIVE_L2_DEFAULT_WAY_MASK 0xffff + static void __iomem *l2_base; static int g_irq[SIFIVE_L2_MAX_ECCINTR]; static struct riscv_cacheinfo_ops l2_cache_ops; static phys_addr_t uncached_offset; DEFINE_STATIC_KEY_FALSE(sifive_l2_handle_noncoherent_key); +static u32 flush_line_len; +static u32 cache_size; +static u32 cache_size_per_way; +static u32 cache_max_line; +static u32 cache_ways_per_bank; +static u32 cache_size_per_block; +static u32 cache_max_enabled_way; +static void __iomem *l2_zero_device_base; + enum { DIR_CORR = 0, DATA_CORR, @@ -94,15 +107,26 @@ static void l2_config_read(void) regval = readl(l2_base + SIFIVE_L2_CONFIG); val = regval & 0xFF; pr_info("L2CACHE: No. of Banks in the cache: %d\n", val); - val = (regval & 0xFF00) >> 8; - pr_info("L2CACHE: No. of ways per bank: %d\n", val); + cache_ways_per_bank = (regval & 0xFF00) >> 8; + pr_info("L2CACHE: No. of ways per bank: %d\n", cache_ways_per_bank); + val = (regval & 0xFF0000) >> 16; pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val); - val = (regval & 0xFF000000) >> 24; - pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val); - regval = readl(l2_base + SIFIVE_L2_WAYENABLE); - pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval); + cache_size_per_block = (regval & 0xFF000000) >> 24; + cache_size_per_block = 1 << cache_size_per_block; + pr_info("L2CACHE: Bytes per cache block: %u\n", cache_size_per_block); + + flush_line_len = cache_size_per_block; + cache_size_per_way = cache_size / cache_ways_per_bank; + cache_max_line = cache_size_per_way / flush_line_len - 1; + pr_info("L2CACHE: max_line=%u, %u bytes/line, %u bytes/way\n", + cache_max_line, + flush_line_len, + cache_size_per_way); + + cache_max_enabled_way = readl(l2_base + SIFIVE_L2_WAYENABLE); + pr_info("L2CACHE: Index of the largest way enabled: %d\n", cache_max_enabled_way); } static const struct of_device_id sifive_l2_ids[] = { @@ -125,6 +149,52 @@ int unregister_sifive_l2_error_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier); +static void sifive_ccache_flush_range_by_way_index(u32 start_index, u32 end_index) +{ + u32 way, master; + u32 index; + u64 way_mask; + void __iomem *line_addr, *addr; + + mb(); + way_mask = 1; + line_addr = l2_zero_device_base + start_index * flush_line_len; + for (way = 0; way <= cache_max_enabled_way; ++way) { + addr = l2_base + SIFIVE_L2_WAYMASK_BASE; + for (master = 0; master < SIFIVE_L2_MAX_MASTER_ID; ++master) { + writeq_relaxed(way_mask, addr); + addr += 8; + } + + addr = line_addr; + for (index = start_index; index <= end_index; ++index) { +#ifdef CONFIG_32BIT + writel_relaxed(0, addr); +#else + writeq_relaxed(0, addr); +#endif + addr += flush_line_len; + } + + way_mask <<= 1; + line_addr += cache_size_per_way; + mb(); + } + + addr = l2_base + SIFIVE_L2_WAYMASK_BASE; + for (master = 0; master < SIFIVE_L2_MAX_MASTER_ID; ++master) { + writeq_relaxed(SIFIVE_L2_DEFAULT_WAY_MASK, addr); + addr += 8; + } + mb(); +} + +void sifive_ccache_flush_entire(void) +{ + sifive_ccache_flush_range_by_way_index(0, cache_max_line); +} +EXPORT_SYMBOL_GPL(sifive_ccache_flush_entire); + void sifive_l2_flush_range(phys_addr_t start, size_t len) { phys_addr_t end = start + len; @@ -134,8 +204,8 @@ void sifive_l2_flush_range(phys_addr_t start, size_t len) return; mb(); - for (line = ALIGN_DOWN(start, SIFIVE_L2_FLUSH64_LINE_LEN); line < end; - line += SIFIVE_L2_FLUSH64_LINE_LEN) { + for (line = ALIGN_DOWN(start, flush_line_len); line < end; + line += flush_line_len) { #ifdef CONFIG_32BIT writel(line >> 4, l2_base + SIFIVE_L2_FLUSH32); #else @@ -194,7 +264,7 @@ void sifive_l2_flush64_range(unsigned long start, unsigned long len) mb(); /* sync */ for (line = start; line < start + len; - line += SIFIVE_L2_FLUSH64_LINE_LEN) { + line += flush_line_len) { writeq(line, l2_base + SIFIVE_L2_FLUSH64); mb(); } @@ -296,6 +366,18 @@ static int __init sifive_l2_init(void) if (!l2_base) return -ENOMEM; + if (of_address_to_resource(np, 2, &res)) + return -ENODEV; + + l2_zero_device_base = ioremap(res.start, resource_size(&res)); + if (!l2_zero_device_base) + return -ENOMEM; + + if (of_property_read_u32(np, "cache-size", &cache_size)) { + pr_err("L2CACHE: no cache-size property\n"); + return -ENODEV; + } + intr_num = of_property_count_u32_elems(np, "interrupts"); if (!intr_num) { pr_err("L2CACHE: no interrupts property\n"); diff --git a/include/soc/sifive/sifive_l2_cache.h b/include/soc/sifive/sifive_l2_cache.h index f472e4cb1232..79adec5ba3c5 100644 --- a/include/soc/sifive/sifive_l2_cache.h +++ b/include/soc/sifive/sifive_l2_cache.h @@ -27,6 +27,7 @@ static inline bool sifive_l2_handle_noncoherent(void) #endif } +void sifive_ccache_flush_entire(void); void sifive_ccache_flush_range(phys_addr_t start, size_t len); void sifive_l2_flush_range(phys_addr_t start, size_t len); void *sifive_l2_set_uncached(void *addr, size_t size); |