diff options
Diffstat (limited to 'arch/riscv/lib')
| -rw-r--r-- | arch/riscv/lib/bootm.c | 97 | ||||
| -rw-r--r-- | arch/riscv/lib/cache.c | 36 | ||||
| -rw-r--r-- | arch/riscv/lib/crt0_riscv_efi.S | 12 | ||||
| -rw-r--r-- | arch/riscv/lib/interrupts.c | 58 | ||||
| -rw-r--r-- | arch/riscv/lib/setjmp.S | 2 | 
5 files changed, 151 insertions, 54 deletions
| diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c index 2b5ccce9338..124aeefff83 100644 --- a/arch/riscv/lib/bootm.c +++ b/arch/riscv/lib/bootm.c @@ -8,6 +8,8 @@  #include <common.h>  #include <command.h> +#include <dm.h> +#include <dm/root.h>  #include <image.h>  #include <asm/byteorder.h>  #include <asm/csr.h> @@ -26,26 +28,41 @@ int arch_fixup_fdt(void *blob)  	return 0;  } -int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +/** + * announce_and_cleanup() - Print message and prepare for kernel boot + * + * @fake: non-zero to do everything except actually boot + */ +static void announce_and_cleanup(int fake)  { -	void	(*kernel)(ulong hart, void *dtb); - -	/* -	 * allow the PREP bootm subcommand, it is required for bootm to work -	 */ -	if (flag & BOOTM_STATE_OS_PREP) -		return 0; +	printf("\nStarting kernel ...%s\n\n", fake ? +		"(fake run for tracing)" : ""); +	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); +#ifdef CONFIG_BOOTSTAGE_FDT +	bootstage_fdt_add_report(); +#endif +#ifdef CONFIG_BOOTSTAGE_REPORT +	bootstage_report(); +#endif -	if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) -		return 1; +#ifdef CONFIG_USB_DEVICE +	udc_disconnect(); +#endif -	kernel = (void (*)(ulong, void *))images->ep; +	board_quiesce_devices(); -	bootstage_mark(BOOTSTAGE_ID_RUN_OS); +	/* +	 * Call remove function of all devices with a removal flag set. +	 * This may be useful for last-stage operations, like cancelling +	 * of DMA operation or releasing device internal buffers. +	 */ +	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); -	debug("## Transferring control to Linux (at address %08lx) ...\n", -	       (ulong)kernel); +	cleanup_before_linux(); +} +static void boot_prep_linux(bootm_headers_t *images) +{  	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {  #ifdef CONFIG_OF_LIBFDT  		debug("using: FDT\n"); @@ -54,24 +71,50 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)  			hang();  		}  #endif +	} else { +		printf("Device tree not found or missing FDT support\n"); +		hang();  	} +} -	/* we assume that the kernel is in place */ -	printf("\nStarting kernel ...\n\n"); +static void boot_jump_linux(bootm_headers_t *images, int flag) +{ +	void (*kernel)(ulong hart, void *dtb); +	int fake = (flag & BOOTM_STATE_OS_FAKE_GO); -	/* -	 * Call remove function of all devices with a removal flag set. -	 * This may be useful for last-stage operations, like cancelling -	 * of DMA operation or releasing device internal buffers. -	 */ -	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); +	kernel = (void (*)(ulong, void *))images->ep; -	cleanup_before_linux(); +	bootstage_mark(BOOTSTAGE_ID_RUN_OS); + +	debug("## Transferring control to Linux (at address %08lx) ...\n", +	      (ulong)kernel); -	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) -		kernel(csr_read(mhartid), images->ft_addr); +	announce_and_cleanup(fake); -	/* does not return */ +	if (!fake) { +		if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) +			kernel(csr_read(mhartid), images->ft_addr); +	} +} + +int do_bootm_linux(int flag, int argc, char * const argv[], +		   bootm_headers_t *images) +{ +	/* No need for those on RISC-V */ +	if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) +		return -1; -	return 1; +	if (flag & BOOTM_STATE_OS_PREP) { +		boot_prep_linux(images); +		return 0; +	} + +	if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { +		boot_jump_linux(images, flag); +		return 0; +	} + +	boot_prep_linux(images); +	boot_jump_linux(images, flag); +	return 0;  } diff --git a/arch/riscv/lib/cache.c b/arch/riscv/lib/cache.c index 1d67c49c2c0..ae5c60716ff 100644 --- a/arch/riscv/lib/cache.c +++ b/arch/riscv/lib/cache.c @@ -6,44 +6,68 @@  #include <common.h> +void invalidate_icache_all(void) +{ +	asm volatile ("fence.i" ::: "memory"); +} + +void flush_dcache_all(void) +{ +	asm volatile ("fence" :::"memory"); +}  void flush_dcache_range(unsigned long start, unsigned long end)  { +	flush_dcache_all();  }  void invalidate_icache_range(unsigned long start, unsigned long end)  { +	/* +	 * RISC-V does not have an instruction for invalidating parts of the +	 * instruction cache. Invalidate all of it instead. +	 */ +	invalidate_icache_all();  }  void invalidate_dcache_range(unsigned long start, unsigned long end)  { +	flush_dcache_all(); +} + +void cache_flush(void) +{ +	invalidate_icache_all(); +	flush_dcache_all();  }  void flush_cache(unsigned long addr, unsigned long size)  { +	invalidate_icache_all(); +	flush_dcache_all();  } -void icache_enable(void) +__weak void icache_enable(void)  {  } -void icache_disable(void) +__weak void icache_disable(void)  {  } -int icache_status(void) +__weak int icache_status(void)  {  	return 0;  } -void dcache_enable(void) +__weak void dcache_enable(void)  {  } -void dcache_disable(void) +__weak void dcache_disable(void)  {  } -int dcache_status(void) +__weak int dcache_status(void)  {  	return 0;  } diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S index 18f61f515ac..b7b5329e1f7 100644 --- a/arch/riscv/lib/crt0_riscv_efi.S +++ b/arch/riscv/lib/crt0_riscv_efi.S @@ -41,13 +41,13 @@ coff_header:  	.short	2				/* nr_sections */  	.long	0				/* TimeDateStamp */  	.long	0				/* PointerToSymbolTable */ -	.long	1				/* NumberOfSymbols */ +	.long	0				/* NumberOfSymbols */  	.short	section_table - optional_header	/* SizeOfOptionalHeader */ -	/* -	 * Characteristics: IMAGE_FILE_DEBUG_STRIPPED | -	 * IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED -	 */ -	.short	0x206 +	/* Characteristics */ +	.short	(IMAGE_FILE_EXECUTABLE_IMAGE | \ +		 IMAGE_FILE_LINE_NUMS_STRIPPED | \ +		 IMAGE_FILE_LOCAL_SYMS_STRIPPED | \ +		 IMAGE_FILE_DEBUG_STRIPPED)  optional_header:  	.short	0x20b				/* PE32+ format */  	.byte	0x02				/* MajorLinkerVersion */ diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c index 0a0995a7af9..3aff0069773 100644 --- a/arch/riscv/lib/interrupts.c +++ b/arch/riscv/lib/interrupts.c @@ -12,7 +12,7 @@  #include <asm/system.h>  #include <asm/encoding.h> -static void _exit_trap(int code, uint epc, struct pt_regs *regs); +static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs);  int interrupt_init(void)  { @@ -34,17 +34,30 @@ int disable_interrupts(void)  	return 0;  } -uint handle_trap(uint mcause, uint epc, struct pt_regs *regs) +ulong handle_trap(ulong cause, ulong epc, struct pt_regs *regs)  { -	uint is_int; +	ulong is_irq, irq; -	is_int = (mcause & MCAUSE_INT); -	if ((is_int) && ((mcause & MCAUSE_CAUSE)  == IRQ_M_EXT)) -		external_interrupt(0);	/* handle_m_ext_interrupt */ -	else if ((is_int) && ((mcause & MCAUSE_CAUSE)  == IRQ_M_TIMER)) -		timer_interrupt(0);	/* handle_m_timer_interrupt */ -	else -		_exit_trap(mcause, epc, regs); +	is_irq = (cause & MCAUSE_INT); +	irq = (cause & ~MCAUSE_INT); + +	if (is_irq) { +		switch (irq) { +		case IRQ_M_EXT: +		case IRQ_S_EXT: +			external_interrupt(0);	/* handle external interrupt */ +			break; +		case IRQ_M_TIMER: +		case IRQ_S_TIMER: +			timer_interrupt(0);	/* handle timer interrupt */ +			break; +		default: +			_exit_trap(cause, epc, regs); +			break; +		}; +	} else { +		_exit_trap(cause, epc, regs); +	}  	return epc;  } @@ -60,16 +73,33 @@ __attribute__((weak)) void timer_interrupt(struct pt_regs *regs)  {  } -static void _exit_trap(int code, uint epc, struct pt_regs *regs) +static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)  {  	static const char * const exception_code[] = {  		"Instruction address misaligned",  		"Instruction access fault",  		"Illegal instruction",  		"Breakpoint", -		"Load address misaligned" +		"Load address misaligned", +		"Load access fault", +		"Store/AMO address misaligned", +		"Store/AMO access fault", +		"Environment call from U-mode", +		"Environment call from S-mode", +		"Reserved", +		"Environment call from M-mode", +		"Instruction page fault", +		"Load page fault", +		"Reserved", +		"Store/AMO page fault",  	}; -	printf("exception code: %d , %s , epc %08x , ra %08lx\n", -		code, exception_code[code], epc, regs->ra); +	if (code < ARRAY_SIZE(exception_code)) { +		printf("exception code: %ld , %s , epc %lx , ra %lx\n", +		       code, exception_code[code], epc, regs->ra); +	} else { +		printf("Reserved\n"); +	} + +	hang();  } diff --git a/arch/riscv/lib/setjmp.S b/arch/riscv/lib/setjmp.S index 8f5a6a23aad..72bc9241f6a 100644 --- a/arch/riscv/lib/setjmp.S +++ b/arch/riscv/lib/setjmp.S @@ -6,7 +6,7 @@  #include <config.h>  #include <linux/linkage.h> -#ifdef CONFIG_CPU_RISCV_64 +#ifdef CONFIG_ARCH_RV64I  #define STORE_IDX(reg, idx)	sd reg, (idx*8)(a0)  #define LOAD_IDX(reg, idx)	ld reg, (idx*8)(a0)  #else | 
