blob: 924cc02c4be87327461428c97e3121bd22d89a1c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Grafc3468482014-04-11 17:09:45 +02002/*
3 * Copyright 2007,2009-2014 Freescale Semiconductor, Inc.
Bin Meng2076d992021-02-25 17:22:58 +08004 * Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
Alexander Grafc3468482014-04-11 17:09:45 +02005 */
6
7#include <common.h>
8#include <command.h>
Simon Glass33d1e702019-11-14 12:57:32 -07009#include <cpu_func.h>
Bin Mengf9c9ffc2021-02-25 17:22:43 +080010#include <dm.h>
Simon Glass313112a2019-08-01 09:46:46 -060011#include <env.h>
Simon Glass18afe102019-11-14 12:57:47 -070012#include <init.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Simon Glass274e0b02020-05-10 11:39:56 -060014#include <net.h>
Alexander Grafc3468482014-04-11 17:09:45 +020015#include <pci.h>
Simon Glassa9dc0682019-12-28 10:44:59 -070016#include <time.h>
Bin Meng0f68ea42021-03-14 20:15:04 +080017#include <dm/simple_bus.h>
18#include <dm/uclass-internal.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060019#include <asm/global_data.h>
Alexander Grafc3468482014-04-11 17:09:45 +020020#include <asm/processor.h>
21#include <asm/mmu.h>
22#include <asm/fsl_pci.h>
23#include <asm/io.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090024#include <linux/libfdt.h>
Alexander Grafc3468482014-04-11 17:09:45 +020025#include <fdt_support.h>
26#include <netdev.h>
27#include <fdtdec.h>
28#include <errno.h>
29#include <malloc.h>
Bin Mengc46215c2021-02-25 17:22:46 +080030#include <virtio_types.h>
31#include <virtio.h>
Alexander Grafc3468482014-04-11 17:09:45 +020032
33DECLARE_GLOBAL_DATA_PTR;
34
35static void *get_fdt_virt(void)
36{
Bin Meng8a804dc2021-02-25 17:22:55 +080037 if (gd->flags & GD_FLG_RELOC)
38 return (void *)gd->fdt_blob;
39 else
40 return (void *)CONFIG_SYS_TMPVIRT;
Alexander Grafc3468482014-04-11 17:09:45 +020041}
42
43static uint64_t get_fdt_phys(void)
44{
45 return (uint64_t)(uintptr_t)gd->fdt_blob;
46}
47
48static void map_fdt_as(int esel)
49{
50 u32 mas0, mas1, mas2, mas3, mas7;
51 uint64_t fdt_phys = get_fdt_phys();
52 unsigned long fdt_phys_tlb = fdt_phys & ~0xffffful;
53 unsigned long fdt_virt_tlb = (ulong)get_fdt_virt() & ~0xffffful;
54
55 mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(esel);
56 mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
57 mas2 = FSL_BOOKE_MAS2(fdt_virt_tlb, 0);
58 mas3 = FSL_BOOKE_MAS3(fdt_phys_tlb, 0, MAS3_SW|MAS3_SR);
59 mas7 = FSL_BOOKE_MAS7(fdt_phys_tlb);
60
61 write_tlb(mas0, mas1, mas2, mas3, mas7);
62}
63
64uint64_t get_phys_ccsrbar_addr_early(void)
65{
66 void *fdt = get_fdt_virt();
67 uint64_t r;
Tom Rini661d6d82017-08-03 08:53:36 -040068 int size, node;
69 u32 naddr;
70 const fdt32_t *prop;
Alexander Grafc3468482014-04-11 17:09:45 +020071
72 /*
73 * To be able to read the FDT we need to create a temporary TLB
74 * map for it.
75 */
76 map_fdt_as(10);
Tom Rini661d6d82017-08-03 08:53:36 -040077 node = fdt_path_offset(fdt, "/soc");
78 naddr = fdt_address_cells(fdt, node);
79 prop = fdt_getprop(fdt, node, "ranges", &size);
80 r = fdt_translate_address(fdt, node, prop + naddr);
Alexander Grafc3468482014-04-11 17:09:45 +020081 disable_tlb(10);
82
83 return r;
84}
85
Alexander Grafc3468482014-04-11 17:09:45 +020086int checkboard(void)
87{
88 return 0;
89}
90
Bin Mengf9c9ffc2021-02-25 17:22:43 +080091static int pci_map_region(phys_addr_t paddr, phys_size_t size, ulong *pmap_addr)
Alexander Grafc3468482014-04-11 17:09:45 +020092{
Alexander Grafc3468482014-04-11 17:09:45 +020093 ulong map_addr;
Alexander Grafc3468482014-04-11 17:09:45 +020094
95 if (!pmap_addr)
96 return 0;
97
98 map_addr = *pmap_addr;
99
100 /* Align map_addr */
101 map_addr += size - 1;
102 map_addr &= ~(size - 1);
103
104 if (map_addr + size >= CONFIG_SYS_PCI_MAP_END)
105 return -1;
106
107 /* Map virtual memory for range */
Bin Mengd8632422021-02-25 17:22:25 +0800108 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
Alexander Grafc3468482014-04-11 17:09:45 +0200109 *pmap_addr = map_addr + size;
110
Alexander Grafc3468482014-04-11 17:09:45 +0200111 return 0;
112}
113
Bin Meng0f68ea42021-03-14 20:15:04 +0800114static void platform_bus_map_region(ulong map_addr, phys_addr_t paddr,
115 phys_size_t size)
116{
117 /* Align map_addr */
118 map_addr += size - 1;
119 map_addr &= ~(size - 1);
120
121 /* Map virtual memory for range */
122 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
123}
124
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800125int misc_init_r(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200126{
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800127 struct udevice *dev;
128 struct pci_region *io;
129 struct pci_region *mem;
130 struct pci_region *pre;
Alexander Grafc3468482014-04-11 17:09:45 +0200131 ulong map_addr;
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800132 int ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200133
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800134 /* Ensure PCI is probed */
135 uclass_first_device(UCLASS_PCI, &dev);
136
137 pci_get_regions(dev, &io, &mem, &pre);
Alexander Grafc3468482014-04-11 17:09:45 +0200138
139 /* Start MMIO and PIO range maps above RAM */
140 map_addr = CONFIG_SYS_PCI_MAP_START;
141
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800142 /* Map MMIO range */
143 ret = pci_map_region(mem->phys_start, mem->size, &map_addr);
144 if (ret)
145 return ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200146
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800147 /* Map PIO range */
148 ret = pci_map_region(io->phys_start, io->size, &map_addr);
149 if (ret)
150 return ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200151
Bin Mengc46215c2021-02-25 17:22:46 +0800152 /*
153 * Make sure virtio bus is enumerated so that peripherals
154 * on the virtio bus can be discovered by their drivers.
155 */
156 virtio_init();
157
Bin Meng8a804dc2021-02-25 17:22:55 +0800158 /*
159 * U-Boot is relocated to RAM already, let's delete the temporary FDT
160 * virtual-physical mapping that was used in the pre-relocation phase.
161 */
162 disable_tlb(find_tlb_idx((void *)CONFIG_SYS_TMPVIRT, 1));
163
Bin Meng0f68ea42021-03-14 20:15:04 +0800164 /*
165 * Detect the presence of the platform bus node, and
166 * create a virtual memory mapping for it.
167 */
168 for (ret = uclass_find_first_device(UCLASS_SIMPLE_BUS, &dev);
169 dev;
170 ret = uclass_find_next_device(&dev)) {
171 if (device_is_compatible(dev, "qemu,platform")) {
172 struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
173
174 platform_bus_map_region(CONFIG_PLATFORM_BUS_MAP_ADDR,
175 plat->target, plat->size);
176 break;
177 }
178 }
179
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800180 return 0;
Alexander Grafc3468482014-04-11 17:09:45 +0200181}
182
183int last_stage_init(void)
184{
185 void *fdt = get_fdt_virt();
186 int len = 0;
187 const uint64_t *prop;
188 int chosen;
189
190 chosen = fdt_path_offset(fdt, "/chosen");
191 if (chosen < 0) {
192 printf("Couldn't find /chosen node in fdt\n");
193 return -EIO;
194 }
195
196 /* -kernel boot */
197 prop = fdt_getprop(fdt, chosen, "qemu,boot-kernel", &len);
198 if (prop && (len >= 8))
Simon Glass4d949a22017-08-03 12:22:10 -0600199 env_set_hex("qemu_kernel_addr", *prop);
Alexander Grafc3468482014-04-11 17:09:45 +0200200
Alexander Grafc3468482014-04-11 17:09:45 +0200201 return 0;
202}
203
204static uint64_t get_linear_ram_size(void)
205{
206 void *fdt = get_fdt_virt();
207 const void *prop;
208 int memory;
209 int len;
210
211 memory = fdt_path_offset(fdt, "/memory");
212 prop = fdt_getprop(fdt, memory, "reg", &len);
213
214 if (prop && len >= 16)
215 return *(uint64_t *)(prop+8);
216
217 panic("Couldn't determine RAM size");
218}
219
Alexander Grafc3468482014-04-11 17:09:45 +0200220phys_size_t fsl_ddr_sdram_size(void)
221{
222 return get_linear_ram_size();
223}
224
225void init_tlbs(void)
226{
227 phys_size_t ram_size;
228
229 /*
230 * Create a temporary AS=1 map for the fdt
231 *
232 * We use ESEL=0 here to overwrite the previous AS=0 map for ourselves
233 * which was only 4k big. This way we don't have to clear any other maps.
234 */
235 map_fdt_as(0);
236
237 /* Fetch RAM size from the fdt */
238 ram_size = get_linear_ram_size();
239
240 /* And remove our fdt map again */
241 disable_tlb(0);
242
243 /* Create an internal map of manually created TLB maps */
244 init_used_tlb_cams();
245
246 /* Create a dynamic AS=0 CCSRBAR mapping */
247 assert(!tlb_map_range(CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS,
248 1024 * 1024, TLB_MAP_IO));
249
250 /* Create a RAM map that spans all accessible RAM */
251 setup_ddr_tlbs(ram_size >> 20);
252
253 /* Create a map for the TLB */
254 assert(!tlb_map_range((ulong)get_fdt_virt(), get_fdt_phys(),
255 1024 * 1024, TLB_MAP_RAM));
256}
257
Alexander Grafc3468482014-04-11 17:09:45 +0200258static uint32_t get_cpu_freq(void)
259{
260 void *fdt = get_fdt_virt();
261 int cpus_node = fdt_path_offset(fdt, "/cpus");
262 int cpu_node = fdt_first_subnode(fdt, cpus_node);
263 const char *prop = "clock-frequency";
264 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
265}
266
267void get_sys_info(sys_info_t *sys_info)
268{
269 int freq = get_cpu_freq();
270
271 memset(sys_info, 0, sizeof(sys_info_t));
272 sys_info->freq_systembus = freq;
273 sys_info->freq_ddrbus = freq;
274 sys_info->freq_processor[0] = freq;
275}
276
Simon Glass85d65312019-12-28 10:44:58 -0700277int get_clocks(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200278{
279 sys_info_t sys_info;
280
281 get_sys_info(&sys_info);
282
283 gd->cpu_clk = sys_info.freq_processor[0];
284 gd->bus_clk = sys_info.freq_systembus;
285 gd->mem_clk = sys_info.freq_ddrbus;
286 gd->arch.lbc_clk = sys_info.freq_ddrbus;
287
288 return 0;
289}
290
Simon Glassa9dc0682019-12-28 10:44:59 -0700291unsigned long get_tbclk(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200292{
293 void *fdt = get_fdt_virt();
294 int cpus_node = fdt_path_offset(fdt, "/cpus");
295 int cpu_node = fdt_first_subnode(fdt, cpus_node);
296 const char *prop = "timebase-frequency";
297 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
298}
299
300/********************************************
301 * get_bus_freq
302 * return system bus freq in Hz
303 *********************************************/
Simon Glass85d65312019-12-28 10:44:58 -0700304ulong get_bus_freq(ulong dummy)
Alexander Grafc3468482014-04-11 17:09:45 +0200305{
306 sys_info_t sys_info;
307 get_sys_info(&sys_info);
308 return sys_info.freq_systembus;
309}
Alexander Graf5b9e18c2014-04-30 19:21:10 +0200310
311/*
312 * Return the number of cores on this SOC.
313 */
314int cpu_numcores(void)
315{
316 /*
317 * The QEMU u-boot target only needs to drive the first core,
318 * spinning and device tree nodes get driven by QEMU itself
319 */
320 return 1;
321}
322
323/*
324 * Return a 32-bit mask indicating which cores are present on this SOC.
325 */
326u32 cpu_mask(void)
327{
328 return (1 << cpu_numcores()) - 1;
329}
Bin Meng11f7a3f2021-02-25 17:22:30 +0800330
331/**
332 * Return the virtual address of FDT that was passed by QEMU
333 *
334 * @return virtual address of FDT received from QEMU in r3 register
335 */
336void *board_fdt_blob_setup(void)
337{
338 return get_fdt_virt();
339}
Bin Meng285d1e22021-02-25 17:22:39 +0800340
341/* See CONFIG_SYS_NS16550_CLK in arch/powerpc/include/asm/config.h */
342int get_serial_clock(void)
343{
344 return get_bus_freq(0);
345}