summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWei Fu <wefu@redhat.com>2021-09-19 09:13:15 +0300
committerTekkaman Ninja <tekkamanninja@163.com>2022-02-15 12:48:24 +0300
commit954644d8f5008610e21ef289b22979fdd737fbcc (patch)
tree27f8fc0273a449678c608d36df5d77a06f2e3bd3
parent28db513a7dd4dd56eb40f764aa674308c97f21ee (diff)
downloadu-boot-954644d8f5008610e21ef289b22979fdd737fbcc.tar.xz
sifive_cache: add flush_range func in sifive cache driver
Signed-off-by: Wei Fu <wefu@redhat.com>
-rw-r--r--arch/riscv/lib/sifive_cache.c21
-rw-r--r--drivers/cache/cache-sifive-ccache.c61
2 files changed, 81 insertions, 1 deletions
diff --git a/arch/riscv/lib/sifive_cache.c b/arch/riscv/lib/sifive_cache.c
index 28154878fc..de4aba6630 100644
--- a/arch/riscv/lib/sifive_cache.c
+++ b/arch/riscv/lib/sifive_cache.c
@@ -25,3 +25,24 @@ void enable_caches(void)
log_debug("ccache enable failed");
}
}
+
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+ struct udevice *dev;
+ int ret;
+
+ /* Enable ways of ccache */
+ ret = uclass_get_device_by_driver(UCLASS_CACHE,
+ DM_DRIVER_GET(sifive_ccache),
+ &dev);
+ if (ret) {
+ log_debug("Cannot flush dcache in %p - %p",
+ (void *)start, (void *)end);
+ } else {
+ ret = flush_range(dev, start, end);
+ if (ret)
+ log_debug("ccache flush failed in %p - %p",
+ (void *)start, (void *)end);
+ }
+} \ No newline at end of file
diff --git a/drivers/cache/cache-sifive-ccache.c b/drivers/cache/cache-sifive-ccache.c
index c8766f6242..a4889f1bc5 100644
--- a/drivers/cache/cache-sifive-ccache.c
+++ b/drivers/cache/cache-sifive-ccache.c
@@ -7,16 +7,22 @@
#include <cache.h>
#include <dm.h>
#include <asm/io.h>
-#include <dm/device.h>
#include <linux/bitfield.h>
+#include <fdt_support.h>
#define SIFIVE_CCACHE_CONFIG 0x000
#define SIFIVE_CCACHE_CONFIG_WAYS GENMASK(15, 8)
#define SIFIVE_CCACHE_WAY_ENABLE 0x008
+#define SIFIVE_CCACHE_FLUSH64 0x200
+
+static bool range_check = false;
struct sifive_ccache {
void __iomem *base;
+ int cache_line_size;
+ phys_addr_t flush_start; /* Start physical address of flush range limit. */
+ phys_addr_t flush_end; /* End physical address of flush range limit. */
};
static int sifive_ccache_enable(struct udevice *dev)
@@ -43,19 +49,72 @@ static int sifive_ccache_get_info(struct udevice *dev, struct cache_info *info)
return 0;
}
+static int sifive_ccache_flush_range(struct udevice *dev,
+ unsigned long start, unsigned long end)
+{
+ unsigned long line;
+ volatile unsigned long *flush64;
+ struct sifive_ccache *priv = dev_get_priv(dev);
+
+ if (range_check) {
+ /* make sure the address is in the range */
+ if(start > end ||
+ start < priv->flush_start || end > priv->flush_end)
+ return -EINVAL;
+ } else {
+ pr_warn("skip checking range.");
+ }
+
+ /* make sure we won't get into infinite loop below */
+ if (!priv->cache_line_size) {
+ pr_warn("missing cache_line_size, skip flush.");
+ return -EINVAL;
+ }
+
+ flush64 = (volatile unsigned long *)(priv->base + SIFIVE_CCACHE_FLUSH64);
+
+ /* memory barrier */
+ mb();
+ for (line = start; line < end; line += priv->cache_line_size)
+ (*flush64) = line;
+ /* memory barrier */
+ mb();
+
+ return 0;
+}
+
static const struct cache_ops sifive_ccache_ops = {
.enable = sifive_ccache_enable,
.get_info = sifive_ccache_get_info,
+ .flush_range = sifive_ccache_flush_range,
};
static int sifive_ccache_probe(struct udevice *dev)
{
+ int ret;
+ uint64_t addr, len;
struct sifive_ccache *priv = dev_get_priv(dev);
priv->base = dev_read_addr_ptr(dev);
if (!priv->base)
return -EINVAL;
+ priv->cache_line_size =
+ dev_read_u32_default(dev, "cache-line-size",
+ CONFIG_SYS_CACHELINE_SIZE);
+
+ /* only read range index 0 */
+ ret = fdt_read_range((void *)gd->fdt_blob, dev_of_offset(dev), 0,
+ NULL, &addr, &len);
+ if (ret) {
+ pr_warn("missing flush range, ignore range check.");
+ return 0;
+ }
+
+ range_check = true;
+ priv->flush_start = addr;
+ priv->flush_end = addr + len - 1;
+
return 0;
}