1 /*
2  * Copyright (C) 2016 Stefan Roese <sr@denx.de>
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <fdtdec.h>
10 #include <libfdt.h>
11 #include <asm/io.h>
12 #include <asm/system.h>
13 #include <asm/arch/cpu.h>
14 #include <asm/arch/soc.h>
15 #include <asm/armv8/mmu.h>
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 /*
20  * Not all memory is mapped in the MMU. So we need to restrict the
21  * memory size so that U-Boot does not try to access it. Also, the
22  * internal registers are located at 0xf000.0000 - 0xffff.ffff.
23  * Currently only 2GiB are mapped for system memory. This is what
24  * we pass to the U-Boot subsystem here.
25  */
26 #define USABLE_RAM_SIZE		0x80000000
27 
28 ulong board_get_usable_ram_top(ulong total_size)
29 {
30 	if (gd->ram_size > USABLE_RAM_SIZE)
31 		return USABLE_RAM_SIZE;
32 
33 	return gd->ram_size;
34 }
35 
36 /*
37  * On ARMv8, MBus is not configured in U-Boot. To enable compilation
38  * of the already implemented drivers, lets add a dummy version of
39  * this function so that linking does not fail.
40  */
41 const struct mbus_dram_target_info *mvebu_mbus_dram_info(void)
42 {
43 	return NULL;
44 }
45 
46 /* DRAM init code ... */
47 
48 static const void *get_memory_reg_prop(const void *fdt, int *lenp)
49 {
50 	int offset;
51 
52 	offset = fdt_path_offset(fdt, "/memory");
53 	if (offset < 0)
54 		return NULL;
55 
56 	return fdt_getprop(fdt, offset, "reg", lenp);
57 }
58 
59 int dram_init(void)
60 {
61 	const void *fdt = gd->fdt_blob;
62 	const fdt32_t *val;
63 	int ac, sc, len;
64 
65 	ac = fdt_address_cells(fdt, 0);
66 	sc = fdt_size_cells(fdt, 0);
67 	if (ac < 0 || sc < 1 || sc > 2) {
68 		printf("invalid address/size cells\n");
69 		return -EINVAL;
70 	}
71 
72 	val = get_memory_reg_prop(fdt, &len);
73 	if (len / sizeof(*val) < ac + sc)
74 		return -EINVAL;
75 
76 	val += ac;
77 
78 	gd->ram_size = fdtdec_get_number(val, sc);
79 
80 	debug("DRAM size = %08lx\n", (unsigned long)gd->ram_size);
81 
82 	return 0;
83 }
84 
85 int dram_init_banksize(void)
86 {
87 	const void *fdt = gd->fdt_blob;
88 	const fdt32_t *val;
89 	int ac, sc, cells, len, i;
90 
91 	val = get_memory_reg_prop(fdt, &len);
92 	if (len < 0)
93 		return -ENXIO;
94 
95 	ac = fdt_address_cells(fdt, 0);
96 	sc = fdt_size_cells(fdt, 0);
97 	if (ac < 1 || ac > 2 || sc < 1 || sc > 2) {
98 		printf("invalid address/size cells\n");
99 		return -ENXIO;
100 	}
101 
102 	cells = ac + sc;
103 
104 	len /= sizeof(*val);
105 
106 	for (i = 0; i < CONFIG_NR_DRAM_BANKS && len >= cells;
107 	     i++, len -= cells) {
108 		gd->bd->bi_dram[i].start = fdtdec_get_number(val, ac);
109 		val += ac;
110 		gd->bd->bi_dram[i].size = fdtdec_get_number(val, sc);
111 		val += sc;
112 
113 		debug("DRAM bank %d: start = %08lx, size = %08lx\n",
114 		      i, (unsigned long)gd->bd->bi_dram[i].start,
115 		      (unsigned long)gd->bd->bi_dram[i].size);
116 	}
117 
118 	return 0;
119 }
120 
121 int arch_cpu_init(void)
122 {
123 	/* Nothing to do (yet) */
124 	return 0;
125 }
126 
127 int arch_early_init_r(void)
128 {
129 	struct udevice *dev;
130 	int ret;
131 	int i;
132 
133 	/*
134 	 * Loop over all MISC uclass drivers to call the comphy code
135 	 * and init all CP110 devices enabled in the DT
136 	 */
137 	i = 0;
138 	while (1) {
139 		/* Call the comphy code via the MISC uclass driver */
140 		ret = uclass_get_device(UCLASS_MISC, i++, &dev);
141 
142 		/* We're done, once no further CP110 device is found */
143 		if (ret)
144 			break;
145 	}
146 
147 	/* Cause the SATA device to do its early init */
148 	uclass_first_device(UCLASS_AHCI, &dev);
149 
150 	return 0;
151 }
152