|
@@ -15,10 +15,96 @@
|
|
|
|
|
|
#define SIFIVE_CCACHE_WAY_ENABLE 0x008
|
|
|
|
|
|
+
|
|
|
+/* Prefetch */
|
|
|
+#define SIFIVE_PREFET_HARD_BASE(hart) ((hart)*0x2000)
|
|
|
+/* Prefetch Control Register */
|
|
|
+#define SIFIVE_PREFT_EN_MASK BIT(0)
|
|
|
+#define SIFIVE_PREFT_CROSS_PAGE_DIS_MASK BIT(1)
|
|
|
+#define SIFIVE_PREFT_DIST_MASK GENMASK(7, 2)
|
|
|
+#define SIFIVE_PREFT_MAX_ALLOC_DIST_MASK GENMASK(13, 8)
|
|
|
+#define SIFIVE_PREFT_LIN_TO_EXP_THRD_MASK GENMASK(19, 14)
|
|
|
+#define SIFIVE_PREFT_AGE_OUT_EN_MASK BIT(20)
|
|
|
+#define SIFIVE_PREFT_NUM_LDS_AGE_OUT_MASK GENMASK(27, 21)
|
|
|
+#define SIFIVE_PREFT_CROSS_PAGE_EN_MASK BIT(28)
|
|
|
+
|
|
|
+/* Prefetch Advanced Control Register */
|
|
|
+#define SIFIVE_PREFT_ADV_Q_FULL_THRD GENMASK(3, 0)
|
|
|
+#define SIFIVE_PREFT_ADV_HIT_CACHE_THRD GENMASK(8, 4)
|
|
|
+#define SIFIVE_PREFT_ADV_HIT_MSHR_THRD GENMASK(12, 9)
|
|
|
+#define SIFIVE_PREFT_ADV_WINDOW_MASK GENMASK(18, 13)
|
|
|
+
|
|
|
+#define SIFIVE_PREFET_HARD_MASK 0x1e
|
|
|
+#define SIFIVE_MAX_HART_ID 0x20
|
|
|
+#define SIFIVE_PREFT_DIST_VAL 0x3
|
|
|
+#define SIFIVE_PREFT_DIST_MAX 0x3f
|
|
|
+#define SIFIVE_PREFT_EN 0x1
|
|
|
+
|
|
|
struct sifive_ccache {
|
|
|
void __iomem *base;
|
|
|
+ void __iomem *pre_base;
|
|
|
+ u32 pre_hart_mask;
|
|
|
+ u32 pre_dist_size;
|
|
|
};
|
|
|
|
|
|
+static int sifive_prefetcher_parse(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct sifive_ccache *priv = dev_get_priv(dev);
|
|
|
+
|
|
|
+ if (!priv->pre_base)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!dev_read_bool(dev, "prefetch-enable"))
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ priv->pre_hart_mask = dev_read_u32_default(dev, "prefetch-hart-mask",
|
|
|
+ SIFIVE_PREFET_HARD_MASK);
|
|
|
+ priv->pre_dist_size = dev_read_u32_default(dev, "prefetch-dist-size",
|
|
|
+ SIFIVE_PREFT_DIST_VAL);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void sifive_prefetcher_cfg_by_id(struct udevice *dev, u32 hart)
|
|
|
+{
|
|
|
+ struct sifive_ccache *priv = dev_get_priv(dev);
|
|
|
+ void __iomem *reg;
|
|
|
+ u32 val;
|
|
|
+
|
|
|
+ /* Prefetch Control Register */
|
|
|
+ reg = priv->pre_base + SIFIVE_PREFET_HARD_BASE(hart);
|
|
|
+
|
|
|
+ val = readl(reg);
|
|
|
+ val &= ~SIFIVE_PREFT_MAX_ALLOC_DIST_MASK;
|
|
|
+ val |= SIFIVE_PREFT_DIST_MAX << __ffs(SIFIVE_PREFT_MAX_ALLOC_DIST_MASK);
|
|
|
+ writel(val, reg);
|
|
|
+
|
|
|
+ val = readl(reg);
|
|
|
+ val &= ~SIFIVE_PREFT_DIST_MASK;
|
|
|
+ val |= priv->pre_dist_size << __ffs(SIFIVE_PREFT_DIST_MASK);
|
|
|
+ writel(val, reg);
|
|
|
+
|
|
|
+ val |= SIFIVE_PREFT_EN << __ffs(SIFIVE_PREFT_EN_MASK);
|
|
|
+ writel(val, reg);
|
|
|
+}
|
|
|
+
|
|
|
+static int sifive_prefetcher_enable(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct sifive_ccache *priv = dev_get_priv(dev);
|
|
|
+ u32 hart;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = sifive_prefetcher_parse(dev);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ for (hart = 0; hart < SIFIVE_MAX_HART_ID; hart++) {
|
|
|
+ if (BIT(hart) & priv->pre_hart_mask)
|
|
|
+ sifive_prefetcher_cfg_by_id(dev, hart);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int sifive_ccache_enable(struct udevice *dev)
|
|
|
{
|
|
|
struct sifive_ccache *priv = dev_get_priv(dev);
|
|
@@ -31,6 +117,8 @@ static int sifive_ccache_enable(struct udevice *dev)
|
|
|
|
|
|
writel(ways - 1, priv->base + SIFIVE_CCACHE_WAY_ENABLE);
|
|
|
|
|
|
+ sifive_prefetcher_enable(dev);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -51,11 +139,16 @@ static const struct cache_ops sifive_ccache_ops = {
|
|
|
static int sifive_ccache_probe(struct udevice *dev)
|
|
|
{
|
|
|
struct sifive_ccache *priv = dev_get_priv(dev);
|
|
|
+ fdt_addr_t addr;
|
|
|
|
|
|
priv->base = dev_read_addr_ptr(dev);
|
|
|
if (!priv->base)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ addr = dev_read_addr_name(dev, "prefetcher");
|
|
|
+ if (addr != FDT_ADDR_T_NONE)
|
|
|
+ priv->pre_base = (void *)(uintptr_t)addr;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|