summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSamin Guo <samin.guo@starfivetech.com>2023-04-03 06:33:40 +0300
committerSamin Guo <samin.guo@starfivetech.com>2023-04-04 04:33:28 +0300
commit5755db49a8814116d2c7eaa7a44c2676e7d566c4 (patch)
tree06d248665e0822eee67749ac552582ff01ab77d3 /drivers
parent0c7da4bebe1889ca2b802e0577a1e8cd816a8d4d (diff)
downloadu-boot-5755db49a8814116d2c7eaa7a44c2676e7d566c4.tar.xz
cache: sifive: Configure the l2 prefetcher parameter
The default configuration of the SIFIVE L2 Prefetcher may not be the best combination on the JH7110, and some parameters need to be modified to achieve the best performance. Signed-off-by: Samin Guo <samin.guo@starfivetech.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cache/cache-sifive-ccache.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/cache/cache-sifive-ccache.c b/drivers/cache/cache-sifive-ccache.c
index 76c0ab26ae..5e6d3a58af 100644
--- a/drivers/cache/cache-sifive-ccache.c
+++ b/drivers/cache/cache-sifive-ccache.c
@@ -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;
}