blob: a39bcb4fa0c7f7d8323234ca1e9461b82cf77be3 [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
Tom Rini68ad5752022-06-20 08:07:57 -040035/* Virtual address range for PCI region maps */
36#define SYS_PCI_MAP_START 0x80000000
37#define SYS_PCI_MAP_END 0xe0000000
38
Alexander Grafc3468482014-04-11 17:09:45 +020039static void *get_fdt_virt(void)
40{
Bin Meng8a804dc2021-02-25 17:22:55 +080041 if (gd->flags & GD_FLG_RELOC)
42 return (void *)gd->fdt_blob;
43 else
Tom Rini6a5dccc2022-11-16 13:10:41 -050044 return (void *)CFG_SYS_TMPVIRT;
Alexander Grafc3468482014-04-11 17:09:45 +020045}
46
47static uint64_t get_fdt_phys(void)
48{
49 return (uint64_t)(uintptr_t)gd->fdt_blob;
50}
51
52static void map_fdt_as(int esel)
53{
54 u32 mas0, mas1, mas2, mas3, mas7;
55 uint64_t fdt_phys = get_fdt_phys();
56 unsigned long fdt_phys_tlb = fdt_phys & ~0xffffful;
57 unsigned long fdt_virt_tlb = (ulong)get_fdt_virt() & ~0xffffful;
58
59 mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(esel);
60 mas1 = MAS1_VALID | MAS1_TID(0) | MAS1_TS | MAS1_TSIZE(BOOKE_PAGESZ_1M);
61 mas2 = FSL_BOOKE_MAS2(fdt_virt_tlb, 0);
62 mas3 = FSL_BOOKE_MAS3(fdt_phys_tlb, 0, MAS3_SW|MAS3_SR);
63 mas7 = FSL_BOOKE_MAS7(fdt_phys_tlb);
64
65 write_tlb(mas0, mas1, mas2, mas3, mas7);
66}
67
68uint64_t get_phys_ccsrbar_addr_early(void)
69{
70 void *fdt = get_fdt_virt();
71 uint64_t r;
Tom Rini661d6d82017-08-03 08:53:36 -040072 int size, node;
73 u32 naddr;
74 const fdt32_t *prop;
Alexander Grafc3468482014-04-11 17:09:45 +020075
76 /*
77 * To be able to read the FDT we need to create a temporary TLB
78 * map for it.
79 */
80 map_fdt_as(10);
Tom Rini661d6d82017-08-03 08:53:36 -040081 node = fdt_path_offset(fdt, "/soc");
82 naddr = fdt_address_cells(fdt, node);
83 prop = fdt_getprop(fdt, node, "ranges", &size);
84 r = fdt_translate_address(fdt, node, prop + naddr);
Alexander Grafc3468482014-04-11 17:09:45 +020085 disable_tlb(10);
86
87 return r;
88}
89
Alexander Grafc3468482014-04-11 17:09:45 +020090int checkboard(void)
91{
92 return 0;
93}
94
Bin Mengf9c9ffc2021-02-25 17:22:43 +080095static int pci_map_region(phys_addr_t paddr, phys_size_t size, ulong *pmap_addr)
Alexander Grafc3468482014-04-11 17:09:45 +020096{
Alexander Grafc3468482014-04-11 17:09:45 +020097 ulong map_addr;
Alexander Grafc3468482014-04-11 17:09:45 +020098
99 if (!pmap_addr)
100 return 0;
101
102 map_addr = *pmap_addr;
103
104 /* Align map_addr */
105 map_addr += size - 1;
106 map_addr &= ~(size - 1);
107
Tom Rini68ad5752022-06-20 08:07:57 -0400108 if (map_addr + size >= SYS_PCI_MAP_END)
Alexander Grafc3468482014-04-11 17:09:45 +0200109 return -1;
110
111 /* Map virtual memory for range */
Bin Mengd8632422021-02-25 17:22:25 +0800112 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
Alexander Grafc3468482014-04-11 17:09:45 +0200113 *pmap_addr = map_addr + size;
114
Alexander Grafc3468482014-04-11 17:09:45 +0200115 return 0;
116}
117
Bin Meng0f68ea42021-03-14 20:15:04 +0800118static void platform_bus_map_region(ulong map_addr, phys_addr_t paddr,
119 phys_size_t size)
120{
121 /* Align map_addr */
122 map_addr += size - 1;
123 map_addr &= ~(size - 1);
124
125 /* Map virtual memory for range */
126 assert(!tlb_map_range(map_addr, paddr, size, TLB_MAP_IO));
127}
128
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800129int misc_init_r(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200130{
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800131 struct udevice *dev;
132 struct pci_region *io;
133 struct pci_region *mem;
134 struct pci_region *pre;
Alexander Grafc3468482014-04-11 17:09:45 +0200135 ulong map_addr;
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800136 int ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200137
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800138 /* Ensure PCI is probed */
139 uclass_first_device(UCLASS_PCI, &dev);
140
141 pci_get_regions(dev, &io, &mem, &pre);
Alexander Grafc3468482014-04-11 17:09:45 +0200142
143 /* Start MMIO and PIO range maps above RAM */
Tom Rini68ad5752022-06-20 08:07:57 -0400144 map_addr = SYS_PCI_MAP_START;
Alexander Grafc3468482014-04-11 17:09:45 +0200145
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800146 /* Map MMIO range */
147 ret = pci_map_region(mem->phys_start, mem->size, &map_addr);
148 if (ret)
149 return ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200150
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800151 /* Map PIO range */
152 ret = pci_map_region(io->phys_start, io->size, &map_addr);
153 if (ret)
154 return ret;
Alexander Grafc3468482014-04-11 17:09:45 +0200155
Bin Mengc46215c2021-02-25 17:22:46 +0800156 /*
157 * Make sure virtio bus is enumerated so that peripherals
158 * on the virtio bus can be discovered by their drivers.
159 */
160 virtio_init();
161
Bin Meng8a804dc2021-02-25 17:22:55 +0800162 /*
163 * U-Boot is relocated to RAM already, let's delete the temporary FDT
164 * virtual-physical mapping that was used in the pre-relocation phase.
165 */
Tom Rini6a5dccc2022-11-16 13:10:41 -0500166 disable_tlb(find_tlb_idx((void *)CFG_SYS_TMPVIRT, 1));
Bin Meng8a804dc2021-02-25 17:22:55 +0800167
Bin Meng0f68ea42021-03-14 20:15:04 +0800168 /*
169 * Detect the presence of the platform bus node, and
170 * create a virtual memory mapping for it.
171 */
172 for (ret = uclass_find_first_device(UCLASS_SIMPLE_BUS, &dev);
173 dev;
174 ret = uclass_find_next_device(&dev)) {
175 if (device_is_compatible(dev, "qemu,platform")) {
176 struct simple_bus_plat *plat = dev_get_uclass_plat(dev);
177
178 platform_bus_map_region(CONFIG_PLATFORM_BUS_MAP_ADDR,
179 plat->target, plat->size);
180 break;
181 }
182 }
183
Bin Mengf9c9ffc2021-02-25 17:22:43 +0800184 return 0;
Alexander Grafc3468482014-04-11 17:09:45 +0200185}
186
187int last_stage_init(void)
188{
189 void *fdt = get_fdt_virt();
190 int len = 0;
191 const uint64_t *prop;
192 int chosen;
193
194 chosen = fdt_path_offset(fdt, "/chosen");
195 if (chosen < 0) {
196 printf("Couldn't find /chosen node in fdt\n");
197 return -EIO;
198 }
199
200 /* -kernel boot */
201 prop = fdt_getprop(fdt, chosen, "qemu,boot-kernel", &len);
202 if (prop && (len >= 8))
Simon Glass4d949a22017-08-03 12:22:10 -0600203 env_set_hex("qemu_kernel_addr", *prop);
Alexander Grafc3468482014-04-11 17:09:45 +0200204
Alexander Grafc3468482014-04-11 17:09:45 +0200205 return 0;
206}
207
208static uint64_t get_linear_ram_size(void)
209{
210 void *fdt = get_fdt_virt();
211 const void *prop;
212 int memory;
213 int len;
214
215 memory = fdt_path_offset(fdt, "/memory");
216 prop = fdt_getprop(fdt, memory, "reg", &len);
217
218 if (prop && len >= 16)
219 return *(uint64_t *)(prop+8);
220
221 panic("Couldn't determine RAM size");
222}
223
Alexander Grafc3468482014-04-11 17:09:45 +0200224phys_size_t fsl_ddr_sdram_size(void)
225{
226 return get_linear_ram_size();
227}
228
229void init_tlbs(void)
230{
231 phys_size_t ram_size;
232
233 /*
234 * Create a temporary AS=1 map for the fdt
235 *
236 * We use ESEL=0 here to overwrite the previous AS=0 map for ourselves
237 * which was only 4k big. This way we don't have to clear any other maps.
238 */
239 map_fdt_as(0);
240
241 /* Fetch RAM size from the fdt */
242 ram_size = get_linear_ram_size();
243
244 /* And remove our fdt map again */
245 disable_tlb(0);
246
247 /* Create an internal map of manually created TLB maps */
248 init_used_tlb_cams();
249
250 /* Create a dynamic AS=0 CCSRBAR mapping */
Tom Rini6a5dccc2022-11-16 13:10:41 -0500251 assert(!tlb_map_range(CFG_SYS_CCSRBAR, CFG_SYS_CCSRBAR_PHYS,
Alexander Grafc3468482014-04-11 17:09:45 +0200252 1024 * 1024, TLB_MAP_IO));
253
254 /* Create a RAM map that spans all accessible RAM */
255 setup_ddr_tlbs(ram_size >> 20);
256
257 /* Create a map for the TLB */
258 assert(!tlb_map_range((ulong)get_fdt_virt(), get_fdt_phys(),
259 1024 * 1024, TLB_MAP_RAM));
260}
261
Alexander Grafc3468482014-04-11 17:09:45 +0200262static uint32_t get_cpu_freq(void)
263{
264 void *fdt = get_fdt_virt();
265 int cpus_node = fdt_path_offset(fdt, "/cpus");
266 int cpu_node = fdt_first_subnode(fdt, cpus_node);
267 const char *prop = "clock-frequency";
268 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
269}
270
271void get_sys_info(sys_info_t *sys_info)
272{
273 int freq = get_cpu_freq();
274
275 memset(sys_info, 0, sizeof(sys_info_t));
276 sys_info->freq_systembus = freq;
277 sys_info->freq_ddrbus = freq;
278 sys_info->freq_processor[0] = freq;
279}
280
Simon Glass85d65312019-12-28 10:44:58 -0700281int get_clocks(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200282{
283 sys_info_t sys_info;
284
285 get_sys_info(&sys_info);
286
287 gd->cpu_clk = sys_info.freq_processor[0];
288 gd->bus_clk = sys_info.freq_systembus;
289 gd->mem_clk = sys_info.freq_ddrbus;
290 gd->arch.lbc_clk = sys_info.freq_ddrbus;
291
292 return 0;
293}
294
Simon Glassa9dc0682019-12-28 10:44:59 -0700295unsigned long get_tbclk(void)
Alexander Grafc3468482014-04-11 17:09:45 +0200296{
297 void *fdt = get_fdt_virt();
298 int cpus_node = fdt_path_offset(fdt, "/cpus");
299 int cpu_node = fdt_first_subnode(fdt, cpus_node);
300 const char *prop = "timebase-frequency";
301 return fdt_getprop_u32_default_node(fdt, cpu_node, 0, prop, 0);
302}
303
304/********************************************
305 * get_bus_freq
306 * return system bus freq in Hz
307 *********************************************/
Simon Glass85d65312019-12-28 10:44:58 -0700308ulong get_bus_freq(ulong dummy)
Alexander Grafc3468482014-04-11 17:09:45 +0200309{
310 sys_info_t sys_info;
311 get_sys_info(&sys_info);
312 return sys_info.freq_systembus;
313}
Alexander Graf5b9e18c2014-04-30 19:21:10 +0200314
315/*
316 * Return the number of cores on this SOC.
317 */
318int cpu_numcores(void)
319{
320 /*
321 * The QEMU u-boot target only needs to drive the first core,
322 * spinning and device tree nodes get driven by QEMU itself
323 */
324 return 1;
325}
326
327/*
328 * Return a 32-bit mask indicating which cores are present on this SOC.
329 */
330u32 cpu_mask(void)
331{
332 return (1 << cpu_numcores()) - 1;
333}
Bin Meng11f7a3f2021-02-25 17:22:30 +0800334
335/**
336 * Return the virtual address of FDT that was passed by QEMU
337 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100338 * Return: virtual address of FDT received from QEMU in r3 register
Bin Meng11f7a3f2021-02-25 17:22:30 +0800339 */
Ilias Apalodimasab5348a2021-10-26 09:12:33 +0300340void *board_fdt_blob_setup(int *err)
Bin Meng11f7a3f2021-02-25 17:22:30 +0800341{
Ilias Apalodimasab5348a2021-10-26 09:12:33 +0300342 *err = 0;
Bin Meng11f7a3f2021-02-25 17:22:30 +0800343 return get_fdt_virt();
344}
Bin Meng285d1e22021-02-25 17:22:39 +0800345
Tom Rinidf6a2152022-11-16 13:10:28 -0500346/* See CFG_SYS_NS16550_CLK in arch/powerpc/include/asm/config.h */
Bin Meng285d1e22021-02-25 17:22:39 +0800347int get_serial_clock(void)
348{
349 return get_bus_freq(0);
350}