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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
From f9ee3f28ecb979c77423be965ef9dd313bdb9e9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
Date: Mon, 8 Mar 2021 16:58:34 +0100
Subject: [PATCH] mips: bmips: automatically detect RAM size
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some devices have different amounts of RAM installed depending on HW revision.
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---
arch/mips/bmips/setup.c | 119 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
--- a/arch/mips/bmips/setup.c
+++ b/arch/mips/bmips/setup.c
@@ -18,6 +18,7 @@
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/smp.h>
+#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/bmips.h>
#include <asm/bootinfo.h>
@@ -34,13 +35,16 @@
#define REG_BCM6318_SOB ((void __iomem *)CKSEG1ADDR(0x10000900))
#define BCM6318_FREQ_SHIFT 23
#define BCM6318_FREQ_MASK (0x3 << BCM6318_FREQ_SHIFT)
+#define BCM6318_SDRAM_ADDR ((void __iomem *)CKSEG1ADDR(0x10004000))
#define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
#define BCM6328_TP1_DISABLED BIT(9)
#define REG_BCM6328_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001a40))
#define BCM6328_FCVO_SHIFT 7
#define BCM6328_FCVO_MASK (0x1f << BCM6328_FCVO_SHIFT)
+#define BCM6328_MEMC_ADDR ((void __iomem *)CKSEG1ADDR(0x10003000))
+#define BCM6358_MEMC_ADDR ((void __iomem *)0xfffe1200)
#define REG_BCM6358_DDR_PLLC ((void __iomem *)0xfffe12b8)
#define BCM6358_PLLC_M1_SHIFT 0
#define BCM6358_PLLC_M1_MASK (0xff << BCM6358_PLLC_M1_SHIFT)
@@ -52,7 +56,9 @@
#define REG_BCM6362_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001814))
#define BCM6362_FCVO_SHIFT 1
#define BCM6362_FCVO_MASK (0x1f << BCM6362_FCVO_SHIFT)
+#define BCM6362_MEMC_ADDR ((void __iomem *)CKSEG1ADDR(0x10003000))
+#define BCM6368_MEMC_ADDR ((void __iomem *)CKSEG1ADDR(0x10001200))
#define REG_BCM6368_DDR_PLLC ((void __iomem *)CKSEG1ADDR(0x100012a0))
#define BCM6368_PLLC_P1_SHIFT 0
#define BCM6368_PLLC_P1_MASK (0xf << BCM6368_PLLC_P1_SHIFT)
@@ -67,6 +73,21 @@
#define REG_BCM63268_MISC_SB ((void __iomem *)CKSEG1ADDR(0x10001814))
#define BCM63268_FCVO_SHIFT 21
#define BCM63268_FCVO_MASK (0xf << BCM63268_FCVO_SHIFT)
+#define BCM63268_MEMC_ADDR ((void __iomem *)CKSEG1ADDR(0x10003000))
+
+#define SDRAM_CFG_REG 0x0
+#define SDRAM_SPACE_SHIFT 4
+#define SDRAM_SPACE_MASK (0xf << SDRAM_SPACE_SHIFT)
+
+#define MEMC_CFG_REG 0x4
+#define MEMC_CFG_32B_SHIFT 1
+#define MEMC_CFG_32B_MASK (1 << MEMC_CFG_32B_SHIFT)
+#define MEMC_CFG_COL_SHIFT 3
+#define MEMC_CFG_COL_MASK (0x3 << MEMC_CFG_COL_SHIFT)
+#define MEMC_CFG_ROW_SHIFT 6
+#define MEMC_CFG_ROW_MASK (0x3 << MEMC_CFG_ROW_SHIFT)
+
+#define DDR_CSEND_REG 0x8
/*
* CBR addr doesn't change and we can cache it.
@@ -84,6 +105,11 @@ struct bmips_cpufreq {
u32 (*cpu_freq)(void);
};
+struct bmips_memsize {
+ const char *compatible;
+ phys_addr_t (*mem_size)(void);
+};
+
struct bmips_quirk {
const char *compatible;
void (*quirk_fn)(void);
@@ -361,9 +387,90 @@ void __init plat_time_init(void)
mips_hpt_frequency = freq;
}
+static inline phys_addr_t bmips_dram_size(unsigned int cols,
+ unsigned int rows,
+ unsigned int is_32b,
+ unsigned int banks)
+{
+ rows += 11; /* 0 => 11 address bits ... 2 => 13 address bits */
+ cols += 8; /* 0 => 8 address bits ... 2 => 10 address bits */
+ is_32b += 1;
+
+ return 1 << (cols + rows + is_32b + banks);
+}
+
+static phys_addr_t _bcm6318_memsize(void __iomem *addr)
+{
+ u32 val;
+
+ val = __raw_readl(addr + SDRAM_CFG_REG);
+ val = (val & SDRAM_SPACE_MASK) >> SDRAM_SPACE_SHIFT;
+
+ return (1 << (val + 20));
+}
+
+static phys_addr_t _bcm6328_memsize(void __iomem *addr)
+{
+ return __raw_readl(addr + DDR_CSEND_REG) << 24;
+}
+
+static phys_addr_t _bcm6358_memsize(void __iomem *addr)
+{
+ unsigned int cols, rows, is_32b;
+ u32 val;
+
+ val = __raw_readl(addr + MEMC_CFG_REG);
+ rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
+ cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
+ is_32b = (val & MEMC_CFG_32B_MASK) ? 0 : 1;
+
+ return bmips_dram_size(cols, rows, is_32b, 2);
+}
+
+static phys_addr_t bcm6318_memsize(void)
+{
+ return _bcm6318_memsize(BCM6318_SDRAM_ADDR);
+}
+
+static phys_addr_t bcm6328_memsize(void)
+{
+ return _bcm6328_memsize(BCM6328_MEMC_ADDR);
+}
+
+static phys_addr_t bcm6358_memsize(void)
+{
+ return _bcm6358_memsize(BCM6358_MEMC_ADDR);
+}
+
+static phys_addr_t bcm6362_memsize(void)
+{
+ return _bcm6328_memsize(BCM6362_MEMC_ADDR);
+}
+
+static phys_addr_t bcm6368_memsize(void)
+{
+ return _bcm6358_memsize(BCM6368_MEMC_ADDR);
+}
+
+static phys_addr_t bcm63268_memsize(void)
+{
+ return _bcm6328_memsize(BCM63268_MEMC_ADDR);
+}
+
+static const struct bmips_memsize bmips_memsize_list[] = {
+ { "brcm,bcm6318", &bcm6318_memsize },
+ { "brcm,bcm6328", &bcm6328_memsize },
+ { "brcm,bcm6358", &bcm6358_memsize },
+ { "brcm,bcm6362", &bcm6362_memsize },
+ { "brcm,bcm6368", &bcm6368_memsize },
+ { "brcm,bcm63268", &bcm63268_memsize },
+ { /* sentinel */ }
+};
+
void __init plat_mem_setup(void)
{
void *dtb;
+ const struct bmips_memsize *ms;
const struct bmips_quirk *q;
set_io_port_base(0);
@@ -384,6 +491,18 @@ void __init plat_mem_setup(void)
__dt_setup_arch(dtb);
+ for (ms = bmips_memsize_list; ms->mem_size; ms++) {
+ if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
+ ms->compatible)) {
+ phys_addr_t mem = ms->mem_size();
+ if (mem) {
+ memblock_add(0, mem);
+ printk("%uMB of RAM installed\n", mem >> 20);
+ break;
+ }
+ }
+ }
+
for (q = bmips_quirk_list; q->quirk_fn; q++) {
if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
q->compatible)) {
|