183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
24b0730d2SSimon Glass /*
34b0730d2SSimon Glass * Copyright (c) 2011 The Chromium OS Authors.
44b0730d2SSimon Glass */
5*9190a3ebSHeinrich Schuchardt
64b0730d2SSimon Glass #include <common.h>
79d922450SSimon Glass #include <dm.h>
8f4289cbdSSimon Glass #include <errno.h>
9b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
107a9219c1SSimon Glass #include <os.h>
11b45122fdSSimon Glass #include <asm/io.h>
1230eef21fSSimon Glass #include <asm/setjmp.h>
135c2859cdSSimon Glass #include <asm/state.h>
146e206504SSimon Glass #include <dm/root.h>
154b0730d2SSimon Glass
164b0730d2SSimon Glass DECLARE_GLOBAL_DATA_PTR;
174b0730d2SSimon Glass
189569c406SSimon Glass /* Enable access to PCI memory with map_sysmem() */
199569c406SSimon Glass static bool enable_pci_map;
209569c406SSimon Glass
219569c406SSimon Glass #ifdef CONFIG_PCI
229569c406SSimon Glass /* Last device that was mapped into memory, and length of mapping */
239569c406SSimon Glass static struct udevice *map_dev;
249569c406SSimon Glass unsigned long map_len;
259569c406SSimon Glass #endif
269569c406SSimon Glass
sandbox_exit(void)275010d98fSSimon Glass void sandbox_exit(void)
284b0730d2SSimon Glass {
298939df09SSimon Glass /* Do this here while it still has an effect */
308939df09SSimon Glass os_fd_restore();
315c2859cdSSimon Glass if (state_uninit())
325c2859cdSSimon Glass os_exit(2);
335c2859cdSSimon Glass
3461336833SSimon Glass if (dm_uninit())
3561336833SSimon Glass os_exit(2);
3661336833SSimon Glass
377a9219c1SSimon Glass /* This is considered normal termination for now */
387a9219c1SSimon Glass os_exit(0);
3988bd0e9dSSimon Glass }
4088bd0e9dSSimon Glass
414b0730d2SSimon Glass /* delay x useconds */
__udelay(unsigned long usec)424b0730d2SSimon Glass void __udelay(unsigned long usec)
434b0730d2SSimon Glass {
449723563aSSimon Glass struct sandbox_state *state = state_get_current();
459723563aSSimon Glass
469723563aSSimon Glass if (!state->skip_delays)
47d99a6874SMatthias Weisser os_usleep(usec);
484b0730d2SSimon Glass }
494b0730d2SSimon Glass
cleanup_before_linux(void)504b0730d2SSimon Glass int cleanup_before_linux(void)
514b0730d2SSimon Glass {
524b0730d2SSimon Glass return 0;
534b0730d2SSimon Glass }
544b0730d2SSimon Glass
cleanup_before_linux_select(int flags)5529748515SSimon Glass int cleanup_before_linux_select(int flags)
5629748515SSimon Glass {
5729748515SSimon Glass return 0;
5829748515SSimon Glass }
5929748515SSimon Glass
60428aa0caSSimon Glass /**
61428aa0caSSimon Glass * is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM
62428aa0caSSimon Glass *
63428aa0caSSimon Glass * This provides a way to check if a pointer is owned by sandbox (and is within
64428aa0caSSimon Glass * its RAM) or not. Sometimes pointers come from a test which conceptually runs
65428aa0caSSimon Glass * output sandbox, potentially with direct access to the C-library malloc()
66428aa0caSSimon Glass * function, or the sandbox stack (which is not actually within the emulated
67428aa0caSSimon Glass * DRAM.
68428aa0caSSimon Glass *
69428aa0caSSimon Glass * Such pointers obviously cannot be mapped into sandbox's DRAM, so we must
70428aa0caSSimon Glass * detect them an process them separately, by recording a mapping to a tag,
71428aa0caSSimon Glass * which we can use to map back to the pointer later.
72428aa0caSSimon Glass *
73428aa0caSSimon Glass * @ptr: Pointer to check
74428aa0caSSimon Glass * @return true if this is within sandbox emulated DRAM, false if not
75428aa0caSSimon Glass */
is_in_sandbox_mem(const void * ptr)76428aa0caSSimon Glass static bool is_in_sandbox_mem(const void *ptr)
77f7ae1ca3SPaul Burton {
78428aa0caSSimon Glass return (const uint8_t *)ptr >= gd->arch.ram_buf &&
79428aa0caSSimon Glass (const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size;
80f7ae1ca3SPaul Burton }
81f7ae1ca3SPaul Burton
82428aa0caSSimon Glass /**
83428aa0caSSimon Glass * phys_to_virt() - Converts a sandbox RAM address to a pointer
84428aa0caSSimon Glass *
85428aa0caSSimon Glass * Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into
86428aa0caSSimon Glass * the emulated DRAM buffer used by sandbox. This function converts such an
87428aa0caSSimon Glass * address to a pointer into this buffer, which can be used to access the
88428aa0caSSimon Glass * memory.
89428aa0caSSimon Glass *
90428aa0caSSimon Glass * If the address is outside this range, it is assumed to be a tag
91428aa0caSSimon Glass */
phys_to_virt(phys_addr_t paddr)92428aa0caSSimon Glass void *phys_to_virt(phys_addr_t paddr)
93f7ae1ca3SPaul Burton {
94428aa0caSSimon Glass struct sandbox_mapmem_entry *mentry;
95428aa0caSSimon Glass struct sandbox_state *state;
96428aa0caSSimon Glass
97428aa0caSSimon Glass /* If the address is within emulated DRAM, calculate the value */
98428aa0caSSimon Glass if (paddr < gd->ram_size)
99428aa0caSSimon Glass return (void *)(gd->arch.ram_buf + paddr);
100428aa0caSSimon Glass
101428aa0caSSimon Glass /*
102428aa0caSSimon Glass * Otherwise search out list of tags for the correct pointer previously
103428aa0caSSimon Glass * created by map_to_sysmem()
104428aa0caSSimon Glass */
105428aa0caSSimon Glass state = state_get_current();
106428aa0caSSimon Glass list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
107428aa0caSSimon Glass if (mentry->tag == paddr) {
108*9190a3ebSHeinrich Schuchardt debug("%s: Used map from %lx to %p\n", __func__,
109428aa0caSSimon Glass (ulong)paddr, mentry->ptr);
110428aa0caSSimon Glass return mentry->ptr;
111428aa0caSSimon Glass }
112428aa0caSSimon Glass }
113428aa0caSSimon Glass
114428aa0caSSimon Glass printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n",
115428aa0caSSimon Glass __func__, (ulong)paddr, (ulong)gd->ram_size);
116428aa0caSSimon Glass os_abort();
117428aa0caSSimon Glass
118428aa0caSSimon Glass /* Not reached */
119428aa0caSSimon Glass return NULL;
120428aa0caSSimon Glass }
121428aa0caSSimon Glass
find_tag(const void * ptr)122428aa0caSSimon Glass struct sandbox_mapmem_entry *find_tag(const void *ptr)
123428aa0caSSimon Glass {
124428aa0caSSimon Glass struct sandbox_mapmem_entry *mentry;
125428aa0caSSimon Glass struct sandbox_state *state = state_get_current();
126428aa0caSSimon Glass
127428aa0caSSimon Glass list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
128428aa0caSSimon Glass if (mentry->ptr == ptr) {
129428aa0caSSimon Glass debug("%s: Used map from %p to %lx\n", __func__, ptr,
130428aa0caSSimon Glass mentry->tag);
131428aa0caSSimon Glass return mentry;
132428aa0caSSimon Glass }
133428aa0caSSimon Glass }
134428aa0caSSimon Glass return NULL;
135428aa0caSSimon Glass }
136428aa0caSSimon Glass
virt_to_phys(void * ptr)137428aa0caSSimon Glass phys_addr_t virt_to_phys(void *ptr)
138428aa0caSSimon Glass {
139428aa0caSSimon Glass struct sandbox_mapmem_entry *mentry;
140428aa0caSSimon Glass
141428aa0caSSimon Glass /*
142428aa0caSSimon Glass * If it is in emulated RAM, don't bother looking for a tag. Just
143428aa0caSSimon Glass * calculate the pointer using the provides offset into the RAM buffer.
144428aa0caSSimon Glass */
145428aa0caSSimon Glass if (is_in_sandbox_mem(ptr))
146428aa0caSSimon Glass return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf);
147428aa0caSSimon Glass
148428aa0caSSimon Glass mentry = find_tag(ptr);
149428aa0caSSimon Glass if (!mentry) {
150428aa0caSSimon Glass /* Abort so that gdb can be used here */
151428aa0caSSimon Glass printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n",
152428aa0caSSimon Glass __func__, ptr, (ulong)gd->ram_size);
153428aa0caSSimon Glass os_abort();
154428aa0caSSimon Glass }
155*9190a3ebSHeinrich Schuchardt debug("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag);
156428aa0caSSimon Glass
157428aa0caSSimon Glass return mentry->tag;
158f7ae1ca3SPaul Burton }
159f7ae1ca3SPaul Burton
map_physmem(phys_addr_t paddr,unsigned long len,unsigned long flags)1604b0730d2SSimon Glass void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
1614b0730d2SSimon Glass {
162a7d9caecSSimon Glass #if defined(CONFIG_PCI) && !defined(CONFIG_SPL_BUILD)
1639569c406SSimon Glass unsigned long plen = len;
1649569c406SSimon Glass void *ptr;
1659569c406SSimon Glass
1669569c406SSimon Glass map_dev = NULL;
1679569c406SSimon Glass if (enable_pci_map && !pci_map_physmem(paddr, &len, &map_dev, &ptr)) {
1689569c406SSimon Glass if (plen != len) {
1699569c406SSimon Glass printf("%s: Warning: partial map at %x, wanted %lx, got %lx\n",
170c6b89f31SMario Six __func__, (uint)paddr, len, plen);
1719569c406SSimon Glass }
1729569c406SSimon Glass map_len = len;
1739569c406SSimon Glass return ptr;
1749569c406SSimon Glass }
1759569c406SSimon Glass #endif
1769569c406SSimon Glass
177f7ae1ca3SPaul Burton return phys_to_virt(paddr);
1784b0730d2SSimon Glass }
1794b0730d2SSimon Glass
unmap_physmem(const void * ptr,unsigned long flags)180428aa0caSSimon Glass void unmap_physmem(const void *ptr, unsigned long flags)
1819569c406SSimon Glass {
1829569c406SSimon Glass #ifdef CONFIG_PCI
1839569c406SSimon Glass if (map_dev) {
184428aa0caSSimon Glass pci_unmap_physmem(ptr, map_len, map_dev);
1859569c406SSimon Glass map_dev = NULL;
1869569c406SSimon Glass }
1879569c406SSimon Glass #endif
1889569c406SSimon Glass }
1899569c406SSimon Glass
map_to_sysmem(const void * ptr)190428aa0caSSimon Glass phys_addr_t map_to_sysmem(const void *ptr)
191428aa0caSSimon Glass {
192428aa0caSSimon Glass struct sandbox_mapmem_entry *mentry;
193428aa0caSSimon Glass
194428aa0caSSimon Glass /*
195428aa0caSSimon Glass * If it is in emulated RAM, don't bother creating a tag. Just return
196428aa0caSSimon Glass * the offset into the RAM buffer.
197428aa0caSSimon Glass */
198428aa0caSSimon Glass if (is_in_sandbox_mem(ptr))
199428aa0caSSimon Glass return (u8 *)ptr - gd->arch.ram_buf;
200428aa0caSSimon Glass
201428aa0caSSimon Glass /*
202428aa0caSSimon Glass * See if there is an existing tag with this pointer. If not, set up a
203428aa0caSSimon Glass * new one.
204428aa0caSSimon Glass */
205428aa0caSSimon Glass mentry = find_tag(ptr);
206428aa0caSSimon Glass if (!mentry) {
207428aa0caSSimon Glass struct sandbox_state *state = state_get_current();
208428aa0caSSimon Glass
209428aa0caSSimon Glass mentry = malloc(sizeof(*mentry));
210428aa0caSSimon Glass if (!mentry) {
211428aa0caSSimon Glass printf("%s: Error: Out of memory\n", __func__);
212428aa0caSSimon Glass os_exit(ENOMEM);
213428aa0caSSimon Glass }
214428aa0caSSimon Glass mentry->tag = state->next_tag++;
215428aa0caSSimon Glass mentry->ptr = (void *)ptr;
216428aa0caSSimon Glass list_add_tail(&mentry->sibling_node, &state->mapmem_head);
217428aa0caSSimon Glass debug("%s: Added map from %p to %lx\n", __func__, ptr,
218428aa0caSSimon Glass (ulong)mentry->tag);
219428aa0caSSimon Glass }
220428aa0caSSimon Glass
221428aa0caSSimon Glass /*
222428aa0caSSimon Glass * Return the tag as the address to use. A later call to map_sysmem()
223428aa0caSSimon Glass * will return ptr
224428aa0caSSimon Glass */
225428aa0caSSimon Glass return mentry->tag;
226428aa0caSSimon Glass }
227428aa0caSSimon Glass
sandbox_set_enable_pci_map(int enable)2289569c406SSimon Glass void sandbox_set_enable_pci_map(int enable)
2299569c406SSimon Glass {
2309569c406SSimon Glass enable_pci_map = enable;
2319569c406SSimon Glass }
2329569c406SSimon Glass
flush_dcache_range(unsigned long start,unsigned long stop)2334b0730d2SSimon Glass void flush_dcache_range(unsigned long start, unsigned long stop)
2344b0730d2SSimon Glass {
2354b0730d2SSimon Glass }
236b45122fdSSimon Glass
invalidate_dcache_range(unsigned long start,unsigned long stop)2370d1414bdSBin Meng void invalidate_dcache_range(unsigned long start, unsigned long stop)
2380d1414bdSBin Meng {
2390d1414bdSBin Meng }
2400d1414bdSBin Meng
sandbox_read_fdt_from_file(void)241b45122fdSSimon Glass int sandbox_read_fdt_from_file(void)
242b45122fdSSimon Glass {
243b45122fdSSimon Glass struct sandbox_state *state = state_get_current();
244b45122fdSSimon Glass const char *fname = state->fdt_fname;
245b45122fdSSimon Glass void *blob;
246b45122fdSSimon Glass loff_t size;
247b45122fdSSimon Glass int err;
248b45122fdSSimon Glass int fd;
249b45122fdSSimon Glass
250b45122fdSSimon Glass blob = map_sysmem(CONFIG_SYS_FDT_LOAD_ADDR, 0);
251b45122fdSSimon Glass if (!state->fdt_fname) {
252b45122fdSSimon Glass err = fdt_create_empty_tree(blob, 256);
253b45122fdSSimon Glass if (!err)
254b45122fdSSimon Glass goto done;
255b45122fdSSimon Glass printf("Unable to create empty FDT: %s\n", fdt_strerror(err));
256b45122fdSSimon Glass return -EINVAL;
257b45122fdSSimon Glass }
258b45122fdSSimon Glass
259b45122fdSSimon Glass err = os_get_filesize(fname, &size);
260b45122fdSSimon Glass if (err < 0) {
261b45122fdSSimon Glass printf("Failed to file FDT file '%s'\n", fname);
262b45122fdSSimon Glass return err;
263b45122fdSSimon Glass }
264b45122fdSSimon Glass fd = os_open(fname, OS_O_RDONLY);
265b45122fdSSimon Glass if (fd < 0) {
266b45122fdSSimon Glass printf("Failed to open FDT file '%s'\n", fname);
267b45122fdSSimon Glass return -EACCES;
268b45122fdSSimon Glass }
269b45122fdSSimon Glass if (os_read(fd, blob, size) != size) {
270b45122fdSSimon Glass os_close(fd);
271b45122fdSSimon Glass return -EIO;
272b45122fdSSimon Glass }
273b45122fdSSimon Glass os_close(fd);
274b45122fdSSimon Glass
275b45122fdSSimon Glass done:
276b45122fdSSimon Glass gd->fdt_blob = blob;
277b45122fdSSimon Glass
278b45122fdSSimon Glass return 0;
279b45122fdSSimon Glass }
280c87dc38dSSimon Glass
timer_get_boot_us(void)281c87dc38dSSimon Glass ulong timer_get_boot_us(void)
282c87dc38dSSimon Glass {
283c87dc38dSSimon Glass static uint64_t base_count;
284c87dc38dSSimon Glass uint64_t count = os_get_nsec();
285c87dc38dSSimon Glass
286c87dc38dSSimon Glass if (!base_count)
287c87dc38dSSimon Glass base_count = count;
288c87dc38dSSimon Glass
289c87dc38dSSimon Glass return (count - base_count) / 1000;
290c87dc38dSSimon Glass }
291