1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2007,2009-2014 Freescale Semiconductor, Inc.
4 * Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
5 */
6
7 #include <config.h>
8 #include <command.h>
9 #include <cpu_func.h>
10 #include <dm.h>
11 #include <env.h>
12 #include <event.h>
13 #include <init.h>
14 #include <log.h>
15 #include <net.h>
16 #include <pci.h>
17 #include <time.h>
18 #include <dm/simple_bus.h>
19 #include <dm/uclass-internal.h>
20 #include <asm/global_data.h>
21 #include <asm/processor.h>
22 #include <asm/mmu.h>
23 #include <asm/fsl_pci.h>
24 #include <asm/io.h>
25 #include <linux/libfdt.h>
26 #include <fdt_support.h>
27 #include <netdev.h>
28 #include <fdtdec.h>
29 #include <errno.h>
30 #include <malloc.h>
31 #include <virtio_types.h>
32 #include <virtio.h>
33
34 DECLARE_GLOBAL_DATA_PTR;
35
36 /* Virtual address range for PCI region maps */
37 #define SYS_PCI_MAP_START 0x80000000
38 #define SYS_PCI_MAP_END 0xe0000000
39
get_fdt_virt(void)40 static void *get_fdt_virt(void)
41 {
42 if (gd->flags & GD_FLG_RELOC)
43 return (void *)gd->fdt_blob;
44 else
45 return (void *)CFG_SYS_TMPVIRT;
46 }
47
get_fdt_phys(void)48 static uint64_t get_fdt_phys(void)
49 {
50 return (uint64_t)(uintptr_t)gd->fdt_blob;
51 }
52
map_fdt_as(int esel)53 static void map_fdt_as(int esel)
54 {
55 u32 mas0, mas1, mas2, mas3, mas7;
56 uint64_t fdt_phys = get_fdt_phys();
57 unsigned long fdt_phys_tlb = fdt_phys & ~0xffffful;
58 unsigned long fdt_virt_tlb = (ulong)get_fdt_virt() & ~0xffffful;
59
60 mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(esel);
61 mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
62 mas2 = FSL_BOOKE_MAS2(fdt_virt_tlb, 0);
63 mas3 = FSL_BOOKE_MAS3(fdt_phys_tlb, 0, MAS3_SW|MAS3_SR);
64 mas7 = FSL_BOOKE_MAS7(fdt_phys_tlb);
65
66 write_tlb(mas0, mas1, mas2, mas3, mas7);
67 }
68
get_phys_ccsrbar_addr_early(void)69 uint64_t get_phys_ccsrbar_addr_early(void)
70 {
71 void *fdt = get_fdt_virt();
72 uint64_t r;
73 int size, node;
74 u32 naddr;
75 const fdt32_t *prop;
76
77 /*
78 * To be able to read the FDT we need to create a temporary TLB
79 * map for it.
80 */
81 map_fdt_as(10);
82 node = fdt_path_offset(fdt, "/soc");
83 naddr = fdt_address_cells(fdt, node);
84 prop = fdt_getprop(fdt, node, "ranges", &size);
85 r = fdt_translate_address(fdt, node, prop + naddr);
86 disable_tlb(10);
87
88 return r;
89 }
90
checkboard(void)91 int checkboard(void)
92 {
93 return 0;
94 }
95
pci_map_region(phys_addr_t paddr,phys_size_t size,ulong * pmap_addr)96 static int pci_map_region(phys_addr_t paddr, phys_size_t size, ulong *pmap_addr)
97 {
98 ulong map_addr;
99
100 if (!pmap_addr)
101 return 0;
102
103 map_addr = *pmap_addr;
104
105 /* Align map_addr */
106 map_addr += size - 1;
107 map_addr &= ~(size - 1);
108
109 if (map_addr + size >= SYS_PCI_MAP_END)
110 return -1;
111
112 /* Map virtual memory for range */
113 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
114 *pmap_addr = map_addr + size;
115
116 return 0;
117 }
118
platform_bus_map_region(ulong map_addr,phys_addr_t paddr,phys_size_t size)119 static void platform_bus_map_region(ulong map_addr, phys_addr_t paddr,
120 phys_size_t size)
121 {
122 /* Align map_addr */
123 map_addr += size - 1;
124 map_addr &= ~(size - 1);
125
126 /* Map virtual memory for range */
127 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
128 }
129
misc_init_r(void)130 int misc_init_r(void)
131 {
132 struct udevice *dev;
133 struct pci_region *io;
134 struct pci_region *mem;
135 struct pci_region *pre;
136 ulong map_addr;
137 int ret;
138
139 /* Ensure PCI is probed */
140 uclass_first_device(UCLASS_PCI, &dev);
141
142 pci_get_regions(dev, &io, &mem, &pre);
143
144 /* Start MMIO and PIO range maps above RAM */
145 map_addr = SYS_PCI_MAP_START;
146
147 /* Map MMIO range */
148 ret = pci_map_region(mem->phys_start, mem->size, &map_addr);
149 if (ret)
150 return ret;
151
152 /* Map PIO range */
153 ret = pci_map_region(io->phys_start, io->size, &map_addr);
154 if (ret)
155 return ret;
156
157 /*
158 * Make sure virtio bus is enumerated so that peripherals
159 * on the virtio bus can be discovered by their drivers.
160 */
161 virtio_init();
162
163 /*
164 * U-Boot is relocated to RAM already, let's delete the temporary FDT
165 * virtual-physical mapping that was used in the pre-relocation phase.
166 */
167 disable_tlb(find_tlb_idx((void *)CFG_SYS_TMPVIRT, 1));
168
169 /*
170 * Detect the presence of the platform bus node, and
171 * create a virtual memory mapping for it.
172 */
173 for (uclass_find_first_device(UCLASS_SIMPLE_BUS, &dev);
174 dev;
175 uclass_find_next_device(&dev)) {
176 if (device_is_compatible(dev, "qemu,platform")) {
177 struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
178
179 platform_bus_map_region(CONFIG_PLATFORM_BUS_MAP_ADDR,
180 plat->target, plat->size);
181 break;
182 }
183 }
184
185 return 0;
186 }
187
last_stage_init(void)188 static int last_stage_init(void)
189 {
190 void *fdt = get_fdt_virt();
191 int len = 0;
192 const uint64_t *prop;
193 int chosen;
194
195 chosen = fdt_path_offset(fdt, "/chosen");
196 if (chosen < 0) {
197 printf("Couldn't find /chosen node in fdt\n");
198 return -EIO;
199 }
200
201 /* -kernel boot */
202 prop = fdt_getprop(fdt, chosen, "qemu,boot-kernel", &len);
203 if (prop && (len >= 8))
204 env_set_hex("qemu_kernel_addr", *prop);
205
206 return 0;
207 }
208 EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, last_stage_init);
209
get_linear_ram_size(void)210 static uint64_t get_linear_ram_size(void)
211 {
212 void *fdt = get_fdt_virt();
213 const void *prop;
214 int memory;
215 int len;
216
217 memory = fdt_path_offset(fdt, "/memory");
218 prop = fdt_getprop(fdt, memory, "reg", &len);
219
220 if (prop && len >= 16)
221 return *(uint64_t *)(prop+8);
222
223 panic("Couldn't determine RAM size");
224 }
225
fsl_ddr_sdram_size(void)226 phys_size_t fsl_ddr_sdram_size(void)
227 {
228 return get_linear_ram_size();
229 }
230
init_tlbs(void)231 void init_tlbs(void)
232 {
233 phys_size_t ram_size;
234
235 /*
236 * Create a temporary AS=1 map for the fdt
237 *
238 * We use ESEL=0 here to overwrite the previous AS=0 map for ourselves
239 * which was only 4k big. This way we don't have to clear any other maps.
240 */
241 map_fdt_as(0);
242
243 /* Fetch RAM size from the fdt */
244 ram_size = get_linear_ram_size();
245
246 /* And remove our fdt map again */
247 disable_tlb(0);
248
249 /* Create an internal map of manually created TLB maps */
250 init_used_tlb_cams();
251
252 /* Create a dynamic AS=0 CCSRBAR mapping */
253 assert(!tlb_map_range(CFG_SYS_CCSRBAR, CFG_SYS_CCSRBAR_PHYS,
254 1024 * 1024, TLB_MAP_IO));
255
256 /* Create a RAM map that spans all accessible RAM */
257 setup_ddr_tlbs(ram_size >> 20);
258
259 /* Create a map for the TLB */
260 assert(!tlb_map_range((ulong)get_fdt_virt(), get_fdt_phys(),
261 1024 * 1024, TLB_MAP_RAM));
262 }
263
get_cpu_freq(void)264 static uint32_t get_cpu_freq(void)
265 {
266 void *fdt = get_fdt_virt();
267 int cpus_node = fdt_path_offset(fdt, "/cpus");
268 int cpu_node = fdt_first_subnode(fdt, cpus_node);
269 const char *prop = "clock-frequency";
270 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
271 }
272
get_sys_info(sys_info_t * sys_info)273 void get_sys_info(sys_info_t *sys_info)
274 {
275 int freq = get_cpu_freq();
276
277 memset(sys_info, 0, sizeof(sys_info_t));
278 sys_info->freq_systembus = freq;
279 sys_info->freq_ddrbus = freq;
280 sys_info->freq_processor[0] = freq;
281 }
282
get_clocks(void)283 int get_clocks(void)
284 {
285 sys_info_t sys_info;
286
287 get_sys_info(&sys_info);
288
289 gd->cpu_clk = sys_info.freq_processor[0];
290 gd->bus_clk = sys_info.freq_systembus;
291 gd->mem_clk = sys_info.freq_ddrbus;
292 gd->arch.lbc_clk = sys_info.freq_ddrbus;
293
294 return 0;
295 }
296
get_tbclk(void)297 unsigned long get_tbclk(void)
298 {
299 void *fdt = get_fdt_virt();
300 int cpus_node = fdt_path_offset(fdt, "/cpus");
301 int cpu_node = fdt_first_subnode(fdt, cpus_node);
302 const char *prop = "timebase-frequency";
303 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
304 }
305
306 /********************************************
307 * get_bus_freq
308 * return system bus freq in Hz
309 *********************************************/
get_bus_freq(ulong dummy)310 ulong get_bus_freq(ulong dummy)
311 {
312 sys_info_t sys_info;
313 get_sys_info(&sys_info);
314 return sys_info.freq_systembus;
315 }
316
317 /*
318 * Return the number of cores on this SOC.
319 */
cpu_numcores(void)320 int cpu_numcores(void)
321 {
322 /*
323 * The QEMU U-Boot target only needs to drive the first core,
324 * spinning and device tree nodes get driven by QEMU itself
325 */
326 return 1;
327 }
328
329 /*
330 * Return a 32-bit mask indicating which cores are present on this SOC.
331 */
cpu_mask(void)332 u32 cpu_mask(void)
333 {
334 return (1 << cpu_numcores()) - 1;
335 }
336
board_fdt_blob_setup(void ** fdtp)337 int board_fdt_blob_setup(void **fdtp)
338 {
339 *fdtp = get_fdt_virt();
340
341 return 0;
342 }
343
344 /* See CFG_SYS_NS16550_CLK in arch/powerpc/include/asm/config.h */
get_serial_clock(void)345 int get_serial_clock(void)
346 {
347 return get_bus_freq(0);
348 }
349