xref: /openbmc/u-boot/arch/sandbox/cpu/cpu.c (revision 5830791d91d1200854ef78fcb32f808c8080f0f0)
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