summaryrefslogtreecommitdiff
path: root/drivers/cache/cache-sifive-ccache.c
blob: 5e6d3a58af9d8a17e694cdf89bf83b4d9baa12b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 SiFive
 */

#include <common.h>
#include <cache.h>
#include <dm.h>
#include <asm/io.h>
#include <dm/device.h>
#include <linux/bitfield.h>

#define SIFIVE_CCACHE_CONFIG		0x000
#define SIFIVE_CCACHE_CONFIG_WAYS	GENMASK(15, 8)

#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);
	u32 config;
	u32 ways;

	/* Enable all ways of composable cache */
	config = readl(priv->base + SIFIVE_CCACHE_CONFIG);
	ways = FIELD_GET(SIFIVE_CCACHE_CONFIG_WAYS, config);

	writel(ways - 1, priv->base + SIFIVE_CCACHE_WAY_ENABLE);

	sifive_prefetcher_enable(dev);

	return 0;
}

static int sifive_ccache_get_info(struct udevice *dev, struct cache_info *info)
{
	struct sifive_ccache *priv = dev_get_priv(dev);

	info->base = (phys_addr_t)priv->base;

	return 0;
}

static const struct cache_ops sifive_ccache_ops = {
	.enable = sifive_ccache_enable,
	.get_info = sifive_ccache_get_info,
};

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;
}

static const struct udevice_id sifive_ccache_ids[] = {
	{ .compatible = "sifive,fu540-c000-ccache" },
	{ .compatible = "sifive,fu740-c000-ccache" },
	{}
};

U_BOOT_DRIVER(sifive_ccache) = {
	.name = "sifive_ccache",
	.id = UCLASS_CACHE,
	.of_match = sifive_ccache_ids,
	.probe = sifive_ccache_probe,
	.priv_auto = sizeof(struct sifive_ccache),
	.ops = &sifive_ccache_ops,
};