diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /roms/u-boot/arch/mips/cpu/mips64 | |
| download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip  | |
Diffstat (limited to 'roms/u-boot/arch/mips/cpu/mips64')
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/Makefile | 9 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/cache.S | 213 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/config.mk | 23 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/cpu.c | 95 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/interrupts.c | 22 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/start.S | 261 | ||||
| -rw-r--r-- | roms/u-boot/arch/mips/cpu/mips64/time.c | 70 | 
7 files changed, 693 insertions, 0 deletions
diff --git a/roms/u-boot/arch/mips/cpu/mips64/Makefile b/roms/u-boot/arch/mips/cpu/mips64/Makefile new file mode 100644 index 00000000..899c319c --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2003-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +extra-y	= start.o +obj-y	= cpu.o interrupts.o time.o cache.o diff --git a/roms/u-boot/arch/mips/cpu/mips64/cache.S b/roms/u-boot/arch/mips/cpu/mips64/cache.S new file mode 100644 index 00000000..36d86881 --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/cache.S @@ -0,0 +1,213 @@ +/* + *  Cache-handling routined for MIPS CPUs + * + *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/cacheops.h> + +#define RA		t9 + +/* + * 16kB is the maximum size of instruction and data caches on MIPS 4K, + * 64kB is on 4KE, 24K, 5K, etc. Set bigger size for convenience. + * + * Note that the above size is the maximum size of primary cache. U-Boot + * doesn't have L2 cache support for now. + */ +#define MIPS_MAX_CACHE_SIZE	0x10000 + +#define INDEX_BASE	CKSEG0 + +	.macro	cache_op op addr +	.set	push +	.set	noreorder +	.set	mips3 +	cache	\op, 0(\addr) +	.set	pop +	.endm + +	.macro	f_fill64 dst, offset, val +	LONG_S	\val, (\offset +  0 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  1 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  2 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  3 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  4 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  5 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  6 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  7 * LONGSIZE)(\dst) +#if LONGSIZE == 4 +	LONG_S	\val, (\offset +  8 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset +  9 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 10 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 11 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 12 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 13 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 14 * LONGSIZE)(\dst) +	LONG_S	\val, (\offset + 15 * LONGSIZE)(\dst) +#endif +	.endm + +/* + * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz) + */ +LEAF(mips_init_icache) +	blez		a1, 9f +	mtc0		zero, CP0_TAGLO +	/* clear tag to invalidate */ +	PTR_LI		t0, INDEX_BASE +	PTR_ADDU	t1, t0, a1 +1:	cache_op	INDEX_STORE_TAG_I t0 +	PTR_ADDU	t0, a2 +	bne		t0, t1, 1b +	/* fill once, so data field parity is correct */ +	PTR_LI		t0, INDEX_BASE +2:	cache_op	FILL t0 +	PTR_ADDU	t0, a2 +	bne		t0, t1, 2b +	/* invalidate again - prudent but not strictly neccessary */ +	PTR_LI		t0, INDEX_BASE +1:	cache_op	INDEX_STORE_TAG_I t0 +	PTR_ADDU	t0, a2 +	bne		t0, t1, 1b +9:	jr		ra +	END(mips_init_icache) + +/* + * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz) + */ +LEAF(mips_init_dcache) +	blez		a1, 9f +	mtc0		zero, CP0_TAGLO +	/* clear all tags */ +	PTR_LI		t0, INDEX_BASE +	PTR_ADDU	t1, t0, a1 +1:	cache_op	INDEX_STORE_TAG_D t0 +	PTR_ADDU	t0, a2 +	bne		t0, t1, 1b +	/* load from each line (in cached space) */ +	PTR_LI		t0, INDEX_BASE +2:	LONG_L		zero, 0(t0) +	PTR_ADDU	t0, a2 +	bne		t0, t1, 2b +	/* clear all tags */ +	PTR_LI		t0, INDEX_BASE +1:	cache_op	INDEX_STORE_TAG_D t0 +	PTR_ADDU	t0, a2 +	bne		t0, t1, 1b +9:	jr		ra +	END(mips_init_dcache) + +/* + * mips_cache_reset - low level initialisation of the primary caches + * + * This routine initialises the primary caches to ensure that they have good + * parity.  It must be called by the ROM before any cached locations are used + * to prevent the possibility of data with bad parity being written to memory. + * + * To initialise the instruction cache it is essential that a source of data + * with good parity is available. This routine will initialise an area of + * memory starting at location zero to be used as a source of parity. + * + * RETURNS: N/A + * + */ +NESTED(mips_cache_reset, 0, ra) +	move	RA, ra +	li	t2, CONFIG_SYS_ICACHE_SIZE +	li	t3, CONFIG_SYS_DCACHE_SIZE +	li	t8, CONFIG_SYS_CACHELINE_SIZE + +	li	v0, MIPS_MAX_CACHE_SIZE + +	/* +	 * Now clear that much memory starting from zero. +	 */ +	PTR_LI		a0, CKSEG1 +	PTR_ADDU	a1, a0, v0 +2:	PTR_ADDIU	a0, 64 +	f_fill64	a0, -64, zero +	bne		a0, a1, 2b + +	/* +	 * The caches are probably in an indeterminate state, +	 * so we force good parity into them by doing an +	 * invalidate, load/fill, invalidate for each line. +	 */ + +	/* +	 * Assume bottom of RAM will generate good parity for the cache. +	 */ + +	/* +	 * Initialize the I-cache first, +	 */ +	move	a1, t2 +	move	a2, t8 +	PTR_LA	v1, mips_init_icache +	jalr	v1 + +	/* +	 * then initialize D-cache. +	 */ +	move	a1, t3 +	move	a2, t8 +	PTR_LA	v1, mips_init_dcache +	jalr	v1 + +	jr	RA +	END(mips_cache_reset) + +/* + * dcache_status - get cache status + * + * RETURNS: 0 - cache disabled; 1 - cache enabled + * + */ +LEAF(dcache_status) +	mfc0	t0, CP0_CONFIG +	li	t1, CONF_CM_UNCACHED +	andi	t0, t0, CONF_CM_CMASK +	move	v0, zero +	beq	t0, t1, 2f +	li	v0, 1 +2:	jr	ra +	END(dcache_status) + +/* + * dcache_disable - disable cache + * + * RETURNS: N/A + * + */ +LEAF(dcache_disable) +	mfc0	t0, CP0_CONFIG +	li	t1, -8 +	and	t0, t0, t1 +	ori	t0, t0, CONF_CM_UNCACHED +	mtc0	t0, CP0_CONFIG +	jr	ra +	END(dcache_disable) + +/* + * dcache_enable - enable cache + * + * RETURNS: N/A + * + */ +LEAF(dcache_enable) +	mfc0	t0, CP0_CONFIG +	ori	t0, CONF_CM_CMASK +	xori	t0, CONF_CM_CMASK +	ori	t0, CONF_CM_CACHABLE_NONCOHERENT +	mtc0	t0, CP0_CONFIG +	jr	ra +	END(dcache_enable) diff --git a/roms/u-boot/arch/mips/cpu/mips64/config.mk b/roms/u-boot/arch/mips/cpu/mips64/config.mk new file mode 100644 index 00000000..c55eb7f2 --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/config.mk @@ -0,0 +1,23 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, <wd@denx.de> +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +# +# Default optimization level for MIPS64 +# +# Note: Toolchains with binutils prior to v2.16 +# are no longer supported by U-Boot MIPS tree! +# +PLATFORM_CPPFLAGS += -DCONFIG_MIPS64 -march=mips64 +PLATFORM_CPPFLAGS += -mabi=64 -DCONFIG_64BIT +ifdef CONFIG_SYS_BIG_ENDIAN +PLATFORM_LDFLAGS  += -m elf64btsmip +else +PLATFORM_LDFLAGS  += -m elf64ltsmip +endif + +CONFIG_STANDALONE_LOAD_ADDR ?= 0xffffffff80200000 \ +			       -T $(srctree)/examples/standalone/mips64.lds diff --git a/roms/u-boot/arch/mips/cpu/mips64/cpu.c b/roms/u-boot/arch/mips/cpu/mips64/cpu.c new file mode 100644 index 00000000..9f45cfca --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/cpu.c @@ -0,0 +1,95 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <netdev.h> +#include <asm/mipsregs.h> +#include <asm/cacheops.h> +#include <asm/reboot.h> + +#define cache_op(op, addr)						\ +	__asm__ __volatile__(						\ +	"	.set	push\n"						\ +	"	.set	noreorder\n"					\ +	"	.set	mips64\n"					\ +	"	cache	%0, %1\n"					\ +	"	.set	pop\n"						\ +	:								\ +	: "i" (op), "R" (*(unsigned char *)(addr))) + +void __attribute__((weak)) _machine_restart(void) +{ +	fprintf(stderr, "*** reset failed ***\n"); + +	while (1) +		/* NOP */; +} + +int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	_machine_restart(); + +	return 0; +} + +void flush_cache(ulong start_addr, ulong size) +{ +	unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; +	unsigned long addr = start_addr & ~(lsize - 1); +	unsigned long aend = (start_addr + size - 1) & ~(lsize - 1); + +	/* aend will be miscalculated when size is zero, so we return here */ +	if (size == 0) +		return; + +	while (1) { +		cache_op(HIT_WRITEBACK_INV_D, addr); +		cache_op(HIT_INVALIDATE_I, addr); +		if (addr == aend) +			break; +		addr += lsize; +	} +} + +void flush_dcache_range(ulong start_addr, ulong stop) +{ +	unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; +	unsigned long addr = start_addr & ~(lsize - 1); +	unsigned long aend = (stop - 1) & ~(lsize - 1); + +	while (1) { +		cache_op(HIT_WRITEBACK_INV_D, addr); +		if (addr == aend) +			break; +		addr += lsize; +	} +} + +void invalidate_dcache_range(ulong start_addr, ulong stop) +{ +	unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE; +	unsigned long addr = start_addr & ~(lsize - 1); +	unsigned long aend = (stop - 1) & ~(lsize - 1); + +	while (1) { +		cache_op(HIT_INVALIDATE_D, addr); +		if (addr == aend) +			break; +		addr += lsize; +	} +} + +void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1) +{ +	write_c0_entrylo0(low0); +	write_c0_pagemask(pagemask); +	write_c0_entrylo1(low1); +	write_c0_entryhi(hi); +	write_c0_index(index); +	tlb_write_indexed(); +} diff --git a/roms/u-boot/arch/mips/cpu/mips64/interrupts.c b/roms/u-boot/arch/mips/cpu/mips64/interrupts.c new file mode 100644 index 00000000..275fcf56 --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/interrupts.c @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> + +int interrupt_init(void) +{ +	return 0; +} + +void enable_interrupts(void) +{ +} + +int disable_interrupts(void) +{ +	return 0; +} diff --git a/roms/u-boot/arch/mips/cpu/mips64/start.S b/roms/u-boot/arch/mips/cpu/mips64/start.S new file mode 100644 index 00000000..92954e1c --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/start.S @@ -0,0 +1,261 @@ +/* + *  Startup Code for MIPS64 CPU-core + * + *  Copyright (c) 2003	Wolfgang Denk <wd@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> + +#ifndef CONFIG_SYS_MIPS_CACHE_MODE +#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT +#endif + +#ifdef CONFIG_SYS_LITTLE_ENDIAN +#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ +	(((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym)) +#else +#define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \ +	((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24) +#endif + +	/* +	 * For the moment disable interrupts, mark the kernel mode and +	 * set ST0_KX so that the CPU does not spit fire when using +	 * 64-bit addresses. +	 */ +	.macro	setup_c0_status set clr +	.set	push +	mfc0	t0, CP0_STATUS +	or	t0, ST0_CU0 | \set | 0x1f | \clr +	xor	t0, 0x1f | \clr +	mtc0	t0, CP0_STATUS +	.set	noreorder +	sll	zero, 3				# ehb +	.set	pop +	.endm + +	.set noreorder + +	.globl _start +	.text +_start: +	/* U-boot entry point */ +	b	reset +	 nop + +	.org 0x200 +	/* TLB refill, 32 bit task */ +1:	b	1b +	 nop + +	.org 0x280 +	/* XTLB refill, 64 bit task */ +1:	b	1b +	 nop + +	.org 0x300 +	/* Cache error exception */ +1:	b	1b +	 nop + +	.org 0x380 +	/* General exception */ +1:	b	1b +	 nop + +	.org 0x400 +	/* Catch interrupt exceptions */ +1:	b	1b +	 nop + +	.org 0x480 +	/* EJTAG debug exception */ +1:	b	1b +	 nop + +	.align 4 +reset: + +	/* Clear watch registers */ +	dmtc0	zero, CP0_WATCHLO +	dmtc0	zero, CP0_WATCHHI + +	/* WP(Watch Pending), SW0/1 should be cleared */ +	mtc0	zero, CP0_CAUSE + +	setup_c0_status ST0_KX 0 + +	/* Init Timer */ +	mtc0	zero, CP0_COUNT +	mtc0	zero, CP0_COMPARE + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +	/* CONFIG0 register */ +	dli	t0, CONF_CM_UNCACHED +	mtc0	t0, CP0_CONFIG +#endif + +	/* +	 * Initialize $gp, force 8 byte alignment of bal instruction to forbid +	 * the compiler to put nop's between bal and _gp. This is required to +	 * keep _gp and ra aligned to 8 byte. +	 */ +	.align	3 +	bal	1f +	 nop +	.dword	_gp +1: +	ld	gp, 0(ra) + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +	/* Initialize any external memory */ +	dla	t9, lowlevel_init +	jalr	t9 +	 nop + +	/* Initialize caches... */ +	dla	t9, mips_cache_reset +	jalr	t9 +	 nop + +	/* ... and enable them */ +	dli	t0, CONFIG_SYS_MIPS_CACHE_MODE +	mtc0	t0, CP0_CONFIG +#endif + +	/* Set up temporary stack */ +	dli	sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET + +	dla	t9, board_init_f +	jr	t9 +	 nop + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * a0 = addr_sp + * a1 = gd + * a2 = destination address + */ +	.globl	relocate_code +	.ent	relocate_code +relocate_code: +	move	sp, a0			# set new stack pointer + +	move	s0, a1			# save gd in s0 +	move	s2, a2			# save destination address in s2 + +	dli	t0, CONFIG_SYS_MONITOR_BASE +	dsub	s1, s2, t0		# s1 <-- relocation offset + +	dla	t3, in_ram +	ld	t2, -24(t3)		# t2 <-- __image_copy_end +	move	t1, a2 + +	dadd	gp, s1			# adjust gp + +	/* +	 * t0 = source address +	 * t1 = target address +	 * t2 = source end address +	 */ +1: +	lw	t3, 0(t0) +	sw	t3, 0(t1) +	daddu	t0, 4 +	blt	t0, t2, 1b +	 daddu	t1, 4 + +	/* If caches were enabled, we would have to flush them here. */ +	dsub	a1, t1, s2		# a1 <-- size +	dla	t9, flush_cache +	jalr	t9 +	 move	a0, s2			# a0 <-- destination address + +	/* Jump to where we've relocated ourselves */ +	daddi	t0, s2, in_ram - _start +	jr	t0 +	 nop + +	.dword	__rel_dyn_end +	.dword	__rel_dyn_start +	.dword	__image_copy_end +	.dword	_GLOBAL_OFFSET_TABLE_ +	.dword	num_got_entries + +in_ram: +	/* +	 * Now we want to update GOT. +	 * +	 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object +	 * generated by GNU ld. Skip these reserved entries from relocation. +	 */ +	ld	t3, -8(t0)		# t3 <-- num_got_entries +	ld	t8, -16(t0)		# t8 <-- _GLOBAL_OFFSET_TABLE_ +	dadd	t8, s1			# t8 now holds relocated _G_O_T_ +	daddi	t8, t8, 16		# skipping first two entries +	dli	t2, 2 +1: +	ld	t1, 0(t8) +	beqz	t1, 2f +	 dadd	t1, s1 +	sd	t1, 0(t8) +2: +	daddi	t2, 1 +	blt	t2, t3, 1b +	 daddi	t8, 8 + +	/* Update dynamic relocations */ +	ld	t1, -32(t0)		# t1 <-- __rel_dyn_start +	ld	t2, -40(t0)		# t2 <-- __rel_dyn_end + +	b	2f			# skip first reserved entry +	 daddi	t1, 16 + +1: +	lw	t8, -4(t1)		# t8 <-- relocation info + +	dli	t3, MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03) +	bne	t8, t3, 2f		# skip non R_MIPS_REL32 entries +	 nop + +	ld	t3, -16(t1)		# t3 <-- location to fix up in FLASH + +	ld	t8, 0(t3)		# t8 <-- original pointer +	dadd	t8, s1			# t8 <-- adjusted pointer + +	dadd	t3, s1			# t3 <-- location to fix up in RAM +	sd	t8, 0(t3) + +2: +	blt	t1, t2, 1b +	 daddi	t1, 16			# each rel.dyn entry is 16 bytes + +	/* +	 * Clear BSS +	 * +	 * GOT is now relocated. Thus __bss_start and __bss_end can be +	 * accessed directly via $gp. +	 */ +	dla	t1, __bss_start		# t1 <-- __bss_start +	dla	t2, __bss_end		# t2 <-- __bss_end + +1: +	sd	zero, 0(t1) +	blt	t1, t2, 1b +	 daddi	t1, 8 + +	move	a0, s0			# a0 <-- gd +	dla	t9, board_init_r +	jr	t9 +	 move	a1, s2 + +	.end	relocate_code diff --git a/roms/u-boot/arch/mips/cpu/mips64/time.c b/roms/u-boot/arch/mips/cpu/mips64/time.c new file mode 100644 index 00000000..0497acf4 --- /dev/null +++ b/roms/u-boot/arch/mips/cpu/mips64/time.c @@ -0,0 +1,70 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/mipsregs.h> + +static unsigned long timestamp; + +/* how many counter cycles in a jiffy */ +#define CYCLES_PER_JIFFY	 \ +	(CONFIG_SYS_MIPS_TIMER_FREQ + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ + +/* + * timer without interrupts + */ + +int timer_init(void) +{ +	/* Set up the timer for the first expiration. */ +	write_c0_compare(read_c0_count() + CYCLES_PER_JIFFY); + +	return 0; +} + +ulong get_timer(ulong base) +{ +	unsigned int count; +	unsigned int expirelo = read_c0_compare(); + +	/* Check to see if we have missed any timestamps. */ +	count = read_c0_count(); +	while ((count - expirelo) < 0x7fffffff) { +		expirelo += CYCLES_PER_JIFFY; +		timestamp++; +	} +	write_c0_compare(expirelo); + +	return timestamp - base; +} + +void __udelay(unsigned long usec) +{ +	unsigned int tmo; + +	tmo = read_c0_count() + (usec * (CONFIG_SYS_MIPS_TIMER_FREQ / 1000000)); +	while ((tmo - read_c0_count()) < 0x7fffffff) +		/*NOP*/; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On MIPS it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ +	return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On MIPS it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ +	return CONFIG_SYS_HZ; +}  | 
