summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWindsome Zeng <windsome.zeng@starfivetech.com>2024-01-09 06:42:16 +0300
committerWindsome Zeng <windsome.zeng@starfivetech.com>2024-01-11 11:45:34 +0300
commitd8e951fa4d36c72b81810a105d7de3f8edb0902a (patch)
treedf1be5568eff88f80a60725d122dea1cb173ee12
parentd0237157652606535fdc0a5414154fa48dfd16f2 (diff)
downloadlinux-d8e951fa4d36c72b81810a105d7de3f8edb0902a.tar.xz
riscv: cpu: cache: Implement a new method to flush the entire L2 cache
According to the manual of SiFive U74, implement a new method to flush the entire L2 cache by using the Zero Device. After testing, 512KB is the critical point between the old and new way. It's better to use sifive_ccache_flush_entire function while data size is larger than cache size. Or it will improve more at 512KB when you know what you are doing. Signed-off-by: Windsome Zeng <windsome.zeng@starfivetech.com>
-rwxr-xr-xarch/riscv/boot/dts/starfive/jh7110.dtsi2
-rw-r--r--drivers/gpu/drm/verisilicon/vs_dc.c7
-rw-r--r--drivers/soc/sifive/sifive_l2_cache.c102
-rw-r--r--include/soc/sifive/sifive_l2_cache.h1
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);