1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2009
4 * Marvell Semiconductor <www.marvell.com>
5 * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
6 */
7
8#include <config.h>
9#include <common.h>
10#include <init.h>
11#include <asm/global_data.h>
12#include <asm/io.h>
13#include <asm/arch/cpu.h>
14#include <asm/arch/soc.h>
15
16#if defined(CONFIG_ARCH_MVEBU)
17/* Use common XOR definitions for A3x and AXP */
18#include "../../../drivers/ddr/marvell/axp/xor.h"
19#include "../../../drivers/ddr/marvell/axp/xor_regs.h"
20#endif
21
22DECLARE_GLOBAL_DATA_PTR;
23
24struct sdram_bank {
25	u32	win_bar;
26	u32	win_sz;
27};
28
29struct sdram_addr_dec {
30	struct sdram_bank sdram_bank[4];
31};
32
33#define REG_CPUCS_WIN_ENABLE		(1 << 0)
34#define REG_CPUCS_WIN_WR_PROTECT	(1 << 1)
35#define REG_CPUCS_WIN_WIN0_CS(x)	(((x) & 0x3) << 2)
36#define REG_CPUCS_WIN_SIZE(x)		(((x) & 0xff) << 24)
37
38#ifndef MVEBU_SDRAM_SIZE_MAX
39#define MVEBU_SDRAM_SIZE_MAX		0xc0000000
40#endif
41
42#define SCRUB_MAGIC		0xbeefdead
43
44#define SCRB_XOR_UNIT		0
45#define SCRB_XOR_CHAN		1
46#define SCRB_XOR_WIN		0
47
48#define XEBARX_BASE_OFFS	16
49
50/*
51 * mvebu_sdram_bar - reads SDRAM Base Address Register
52 */
53u32 mvebu_sdram_bar(enum memory_bank bank)
54{
55	struct sdram_addr_dec *base =
56		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
57	u32 result = 0;
58	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
59
60	if ((!enable) || (bank > BANK3))
61		return 0;
62
63	result = readl(&base->sdram_bank[bank].win_bar);
64	return result;
65}
66
67/*
68 * mvebu_sdram_bs_set - writes SDRAM Bank size
69 */
70static void mvebu_sdram_bs_set(enum memory_bank bank, u32 size)
71{
72	struct sdram_addr_dec *base =
73		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
74	/* Read current register value */
75	u32 reg = readl(&base->sdram_bank[bank].win_sz);
76
77	/* Clear window size */
78	reg &= ~REG_CPUCS_WIN_SIZE(0xFF);
79
80	/* Set new window size */
81	reg |= REG_CPUCS_WIN_SIZE((size - 1) >> 24);
82
83	writel(reg, &base->sdram_bank[bank].win_sz);
84}
85
86/*
87 * mvebu_sdram_bs - reads SDRAM Bank size
88 */
89u32 mvebu_sdram_bs(enum memory_bank bank)
90{
91	struct sdram_addr_dec *base =
92		(struct sdram_addr_dec *)MVEBU_SDRAM_BASE;
93	u32 result = 0;
94	u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz);
95
96	if ((!enable) || (bank > BANK3))
97		return 0;
98	result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz);
99	result += 0x01000000;
100	return result;
101}
102
103void mvebu_sdram_size_adjust(enum memory_bank bank)
104{
105	u32 size;
106
107	/* probe currently equipped RAM size */
108	size = get_ram_size((void *)mvebu_sdram_bar(bank),
109			    mvebu_sdram_bs(bank));
110
111	/* adjust SDRAM window size accordingly */
112	mvebu_sdram_bs_set(bank, size);
113}
114
115#if defined(CONFIG_ARCH_MVEBU)
116static u32 xor_ctrl_save;
117static u32 xor_base_save;
118static u32 xor_mask_save;
119
120static void mv_xor_init2(u32 cs)
121{
122	u32 reg, base, size, base2;
123	u32 bank_attr[4] = { 0xe00, 0xd00, 0xb00, 0x700 };
124
125	xor_ctrl_save = reg_read(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT,
126						     SCRB_XOR_CHAN));
127	xor_base_save = reg_read(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT,
128						   SCRB_XOR_WIN));
129	xor_mask_save = reg_read(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT,
130						   SCRB_XOR_WIN));
131
132	/* Enable Window x for each CS */
133	reg = 0x1;
134	reg |= (0x3 << 16);
135	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN), reg);
136
137	base = 0;
138	size = mvebu_sdram_bs(cs) - 1;
139	if (size) {
140		base2 = ((base / (64 << 10)) << XEBARX_BASE_OFFS) |
141			bank_attr[cs];
142		reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
143			  base2);
144
145		base += size + 1;
146		size = (size / (64 << 10)) << 16;
147		/* Window x - size - 256 MB */
148		reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN), size);
149	}
150
151	mv_xor_hal_init(0);
152
153	return;
154}
155
156static void mv_xor_finish2(void)
157{
158	reg_write(XOR_WINDOW_CTRL_REG(SCRB_XOR_UNIT, SCRB_XOR_CHAN),
159		  xor_ctrl_save);
160	reg_write(XOR_BASE_ADDR_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
161		  xor_base_save);
162	reg_write(XOR_SIZE_MASK_REG(SCRB_XOR_UNIT, SCRB_XOR_WIN),
163		  xor_mask_save);
164}
165
166static void dram_ecc_scrubbing(void)
167{
168	int cs;
169	u32 size, temp;
170	u32 total_mem = 0;
171	u64 total;
172	u32 start_addr;
173
174	/*
175	 * The DDR training code from the bin_hdr / SPL already
176	 * scrubbed the DDR till 0x1000000. And the main U-Boot
177	 * is loaded to an address < 0x1000000. So we need to
178	 * skip this range to not re-scrub this area again.
179	 */
180	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
181	temp |= (1 << REG_SDRAM_CONFIG_IERR_OFFS);
182	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
183
184	for (cs = 0; cs < CONFIG_NR_DRAM_BANKS; cs++) {
185		size = mvebu_sdram_bs(cs);
186		if (size == 0)
187			continue;
188
189		total = (u64)size;
190		total_mem += (u32)(total / (1 << 30));
191		start_addr = 0;
192		mv_xor_init2(cs);
193
194		/* Skip first 16 MiB */
195		if (0 == cs) {
196			start_addr = 0x1000000;
197			size -= start_addr;
198		}
199
200		mv_xor_mem_init(SCRB_XOR_CHAN, start_addr, size - 1,
201				SCRUB_MAGIC, SCRUB_MAGIC);
202
203		/* Wait for previous transfer completion */
204		while (mv_xor_state_get(SCRB_XOR_CHAN) != MV_IDLE)
205			;
206
207		mv_xor_finish2();
208	}
209
210	temp = reg_read(REG_SDRAM_CONFIG_ADDR);
211	temp &= ~(1 << REG_SDRAM_CONFIG_IERR_OFFS);
212	reg_write(REG_SDRAM_CONFIG_ADDR, temp);
213}
214
215static int ecc_enabled(void)
216{
217	if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_ECC_OFFS))
218		return 1;
219
220	return 0;
221}
222
223/* Return the width of the DRAM bus. */
224static int bus_width(void)
225{
226	int full_width = 0;
227
228	if (reg_read(REG_SDRAM_CONFIG_ADDR) & (1 << REG_SDRAM_CONFIG_WIDTH_OFFS))
229		full_width = 1;
230
231#ifdef CONFIG_ARMADA_XP
232	return full_width ? 64 : 32;
233#else
234	return full_width ? 32 : 16;
235#endif
236}
237
238static int cycle_mode(void)
239{
240	int val = reg_read(REG_DUNIT_CTRL_LOW_ADDR);
241
242	return (val >> REG_DUNIT_CTRL_LOW_2T_OFFS) & REG_DUNIT_CTRL_LOW_2T_MASK;
243}
244
245#else
246static void dram_ecc_scrubbing(void)
247{
248}
249
250static int ecc_enabled(void)
251{
252	return 0;
253}
254#endif
255
256int dram_init(void)
257{
258	u64 size = 0;
259	int i;
260
261	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
262		/*
263		 * It is assumed that all memory banks are consecutive
264		 * and without gaps.
265		 * If the gap is found, ram_size will be reported for
266		 * consecutive memory only
267		 */
268		if (mvebu_sdram_bar(i) != size)
269			break;
270
271		/*
272		 * Don't report more than 3GiB of SDRAM, otherwise there is no
273		 * address space left for the internal registers etc.
274		 */
275		size += mvebu_sdram_bs(i);
276		if (size > MVEBU_SDRAM_SIZE_MAX)
277			size = MVEBU_SDRAM_SIZE_MAX;
278	}
279
280	if (ecc_enabled())
281		dram_ecc_scrubbing();
282
283	gd->ram_size = size;
284
285	return 0;
286}
287
288/*
289 * If this function is not defined here,
290 * board.c alters dram bank zero configuration defined above.
291 */
292int dram_init_banksize(void)
293{
294	u64 size = 0;
295	int i;
296
297	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
298		gd->bd->bi_dram[i].start = mvebu_sdram_bar(i);
299		gd->bd->bi_dram[i].size = mvebu_sdram_bs(i);
300
301		/* Clip the banksize to 1GiB if it exceeds the max size */
302		size += gd->bd->bi_dram[i].size;
303		if (size > MVEBU_SDRAM_SIZE_MAX)
304			mvebu_sdram_bs_set(i, 0x40000000);
305	}
306
307	return 0;
308}
309
310#if defined(CONFIG_ARCH_MVEBU)
311void board_add_ram_info(int use_default)
312{
313	struct sar_freq_modes sar_freq;
314	int mode;
315	int width;
316
317	get_sar_freq(&sar_freq);
318	printf(" (%d MHz, ", sar_freq.d_clk);
319
320	width = bus_width();
321	if (width)
322		printf("%d-bit, ", width);
323
324	mode = cycle_mode();
325	/* Mode 0 = Single cycle
326	 * Mode 1 = Two cycles   (2T)
327	 * Mode 2 = Three cycles (3T)
328	 */
329	if (mode == 1)
330		printf("2T, ");
331	if (mode == 2)
332		printf("3T, ");
333
334	if (ecc_enabled())
335		printf("ECC");
336	else
337		printf("ECC not");
338	printf(" enabled)");
339}
340#endif
341