From a414281da4ce0761e898309fee4c489d43b4abb6 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 May 2020 11:59:05 +0200 Subject: [PATCH 01/20] mips: time: Only compile the weak get_tbclk() when needed This patch opts-out the compilation of get_tbclk() if CONFIG_SYS_MIPS_TIMER_FREQ is not defined. This is used on the Octeon platform, where the weak get_tbclk() function is overwritten by its platform specific one. Signed-off-by: Stefan Roese --- arch/mips/cpu/time.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/cpu/time.c b/arch/mips/cpu/time.c index e0c1868b8c..5e7a7144d0 100644 --- a/arch/mips/cpu/time.c +++ b/arch/mips/cpu/time.c @@ -13,7 +13,9 @@ unsigned long notrace timer_read_counter(void) return read_c0_count(); } +#if defined(CONFIG_SYS_MIPS_TIMER_FREQ) ulong notrace __weak get_tbclk(void) { return CONFIG_SYS_MIPS_TIMER_FREQ; } +#endif From a02bc1f99275a17e1d29886c8c69398e9313842d Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 May 2020 11:59:06 +0200 Subject: [PATCH 02/20] mips: traps: Set WG bit in EBase register on Octeon WG (bit 11) needs to be set on Octeon to enable writing bits 63:30 of the exception base register. Signed-off-by: Stefan Roese --- arch/mips/include/asm/mipsregs.h | 1 + arch/mips/lib/traps.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 7538e6b2e0..17381301ec 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -366,6 +366,7 @@ * Bits in the coprocessor 0 EBase register. */ #define EBASE_CPUNUM 0x3ff +#define EBASE_WG (_ULCAST_(1) << 11) /* * Bits in the coprocessor 0 config register. diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c index b1ae02fcab..6ff9d20bd6 100644 --- a/arch/mips/lib/traps.c +++ b/arch/mips/lib/traps.c @@ -108,6 +108,10 @@ void trap_init(ulong reloc_addr) saved_ebase = read_c0_ebase() & 0xfffff000; + /* Set WG bit on Octeon to enable writing to bits 63:30 */ + if (IS_ENABLED(CONFIG_ARCH_OCTEON)) + ebase |= EBASE_WG; + write_c0_ebase(ebase); clear_c0_status(ST0_BEV); execution_hazard_barrier(); From c37281310593c01981516bb706242f80295a1308 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 5 Jun 2020 10:29:25 +0200 Subject: [PATCH 03/20] mips: reloc: Change R_MIPS_NONE to catch pre-reloc BSS usage This patch changes the R_MIPS_NONE define from 0 to a magic value. This makes it possible to better detect any forbidden pre-relocation usage of BSS variables, as they are often zero'ed and then relocation is stopped too early. Additionally the error message is improved to also print the faulting address. This helps finding the root-cause for this breakage by comparing this address with the values in System.map. This patch helps a lot when working on pre-relocation code, like the Octeon DDR init code, where such variables have hit me multiple times now. Signed-off-by: Stefan Roese Cc: Daniel Schwierzeck Cc: Aaron Williams Cc: Chandrakala Chavva --- arch/mips/include/asm/relocs.h | 2 +- arch/mips/lib/reloc.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/relocs.h b/arch/mips/include/asm/relocs.h index 0987c4bb13..b9b0261f62 100644 --- a/arch/mips/include/asm/relocs.h +++ b/arch/mips/include/asm/relocs.h @@ -8,7 +8,7 @@ #ifndef __ASM_MIPS_RELOCS_H__ #define __ASM_MIPS_RELOCS_H__ -#define R_MIPS_NONE 0 +#define R_MIPS_NONE 0xbeef7531 #define R_MIPS_32 2 #define R_MIPS_26 4 #define R_MIPS_HI16 5 diff --git a/arch/mips/lib/reloc.c b/arch/mips/lib/reloc.c index ffc8c7a1b7..67c8af2f35 100644 --- a/arch/mips/lib/reloc.c +++ b/arch/mips/lib/reloc.c @@ -67,7 +67,7 @@ static unsigned long read_uint(uint8_t **buf) * intentionally simple, and does the bare minimum needed to fixup the * relocated U-Boot - in particular, it does not check for overflows. */ -static void apply_reloc(unsigned int type, void *addr, long off) +static void apply_reloc(unsigned int type, void *addr, long off, uint8_t *buf) { uint32_t u32; @@ -92,7 +92,8 @@ static void apply_reloc(unsigned int type, void *addr, long off) break; default: - panic("Unhandled reloc type %u\n", type); + panic("Unhandled reloc type %u (@ %p), bss used before relocation?\n", + type, buf); } } @@ -137,7 +138,7 @@ void relocate_code(ulong start_addr_sp, gd_t *new_gd, ulong relocaddr) break; addr += read_uint(&buf) << 2; - apply_reloc(type, (void *)addr, off); + apply_reloc(type, (void *)addr, off, buf); } /* Ensure the icache is coherent */ From 2eed3dca229e97aa03954ee5178457c4f2f8cfdb Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 May 2020 11:59:03 +0200 Subject: [PATCH 04/20] mips: cache: Allow using CONFIG_MIPS_L2_CACHE without CONFIG_MIPS_CM This patch enables the usage of CONFIG_MIPS_L2_CACHE without CONFIG_MIPS_CM, which is what is needed for the newly added Octeon platform. Signed-off-by: Stefan Roese --- arch/mips/include/asm/cm.h | 12 ++++++++++++ arch/mips/lib/cache.c | 2 -- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/cm.h b/arch/mips/include/asm/cm.h index 3878171607..99ddbccd80 100644 --- a/arch/mips/include/asm/cm.h +++ b/arch/mips/include/asm/cm.h @@ -41,6 +41,7 @@ #include #include +#if CONFIG_IS_ENABLED(MIPS_CM) static inline void *mips_cm_base(void) { return (void *)CKSEG1ADDR(CONFIG_MIPS_CM_BASE); @@ -56,6 +57,17 @@ static inline unsigned long mips_cm_l2_line_size(void) line_sz &= GENMASK(GCR_L2_CONFIG_LINESZ_BITS - 1, 0); return line_sz ? (2 << line_sz) : 0; } +#else +static inline void *mips_cm_base(void) +{ + return NULL; +} + +static inline unsigned long mips_cm_l2_line_size(void) +{ + return 0; +} +#endif #endif /* !__ASSEMBLY__ */ diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index 24f115ebc9..b5c42aeed7 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -8,9 +8,7 @@ #include #include #include -#ifdef CONFIG_MIPS_L2_CACHE #include -#endif #include #include #include From 1d4ba15c6fe1265c5964cce3436fd501b14bae3b Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 14 May 2020 11:59:04 +0200 Subject: [PATCH 05/20] mips: cache: Make flush_cache() weak to enable overwrite This patch adds __weak to flush_cache() in lib/cache.c. This makes it possible to overwrite this function by a platforms specific version, like done with the Octeon base port. Signed-off-by: Stefan Roese --- arch/mips/lib/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index b5c42aeed7..ad37f05802 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -107,7 +107,7 @@ static inline unsigned long scache_line_size(void) } \ } while (0) -void flush_cache(ulong start_addr, ulong size) +void __weak flush_cache(ulong start_addr, ulong size) { unsigned long ilsize = icache_line_size(); unsigned long dlsize = dcache_line_size(); From 60a0559b7fe9bdb9433dc39c42e3e12c4363d63e Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:33:19 +0200 Subject: [PATCH 06/20] mips: cache: Make invalidate_dcache_range() weak to enable overwrite This patch adds __weak to invalidate_dcache_range() in lib/cache.c. This makes it possible to overwrite this function by a platforms specific version, which will be done for Octeon. Signed-off-by: Stefan Roese --- arch/mips/lib/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index ad37f05802..cf29994a7a 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -159,7 +159,7 @@ void __weak flush_dcache_range(ulong start_addr, ulong stop) sync(); } -void invalidate_dcache_range(ulong start_addr, ulong stop) +void __weak invalidate_dcache_range(ulong start_addr, ulong stop) { unsigned long lsize = dcache_line_size(); unsigned long slsize = scache_line_size(); From 54e7fbd5adef2ca68d3e3723516651fc9f096d0b Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 00:45:54 +0200 Subject: [PATCH 07/20] mips: start.S: remove dead code Since commit 703ec9ddf965 ("MIPS: Stop building position independent code") the relocation code was completely reworked and removed from start.S. Remove some left-overs of the old code. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/cpu/start.S | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 6de9a2f362..c3d1e64c1c 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -17,19 +17,10 @@ #endif #ifdef CONFIG_32BIT -# define MIPS_RELOC 3 # define STATUS_SET 0 #endif #ifdef CONFIG_64BIT -# 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 -# define MIPS_RELOC MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03) # define STATUS_SET ST0_KX #endif From b55e07e5656c6838a14453705e90189908ad7d92 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 00:45:55 +0200 Subject: [PATCH 08/20] mips: add KSEG1 wrapper for change_k0_cca change_k0_cca() is called multiple times. Move the code for changing to KSEG1 to a macro to avoid code duplication. Also fix missing change to KSEG1 when changing to CONF_CM_CACHABLE_COW. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/lib/cache_init.S | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S index cfad1d9c8a..2233d27137 100644 --- a/arch/mips/lib/cache_init.S +++ b/arch/mips/lib/cache_init.S @@ -79,6 +79,21 @@ .set pop .endm + /* + * The changing of Kernel mode cacheability must be done from KSEG1. + * If the code is executing from KSEG0, jump to KSEG1 during the execution + * of change_k0_cca. change_k0_cca itself clears all hazards when returning. + */ + .macro change_k0_cca_kseg1 mode + PTR_LA t0, change_k0_cca + li t1, CPHYSADDR(~0) + and t0, t0, t1 + PTR_LI t1, CKSEG1 + or t0, t0, t1 + li a0, \mode + jalr t0 + .endm + /* * mips_cache_reset - low level initialisation of the primary caches * @@ -317,18 +332,9 @@ l1_init: sync /* - * Enable use of the I-cache by setting Config.K0. The code for this - * must be executed from KSEG1. Jump from KSEG0 to KSEG1 to do this. - * Jump back to KSEG0 after caches are enabled and insert an - * instruction hazard barrier. + * Enable use of the I-cache by setting Config.K0. */ - PTR_LA t0, change_k0_cca - li t1, CPHYSADDR(~0) - and t0, t0, t1 - PTR_LI t1, CKSEG1 - or t0, t0, t1 - li a0, CONF_CM_CACHABLE_NONCOHERENT - jalr.hb t0 + change_k0_cca_kseg1 CONF_CM_CACHABLE_NONCOHERENT /* * then initialize D-cache. @@ -388,9 +394,7 @@ l2_unbypass: beqz t0, 2f /* Change Config.K0 to a coherent CCA */ - PTR_LA t0, change_k0_cca - li a0, CONF_CM_CACHABLE_COW - jalr t0 + change_k0_cca_kseg1 CONF_CM_CACHABLE_COW /* * Join the coherent domain such that the caches of this core are kept From 60772433dd42987f3b965188d9577150084b8956 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 00:45:56 +0200 Subject: [PATCH 09/20] mips: refactor disabling of caches Logically this code belongs to cache_init.S. If a complex SoC needs to replace the generic cache init, mips_cache_disable() can now be called from custom start.S files. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/cpu/start.S | 9 ++++----- arch/mips/lib/cache_init.S | 6 ++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index c3d1e64c1c..a9f8743717 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -196,11 +196,10 @@ wr_done: mtc0 zero, CP0_COMPARE #ifndef CONFIG_SKIP_LOWLEVEL_INIT - mfc0 t0, CP0_CONFIG - and t0, t0, MIPS_CONF_IMPL - or t0, t0, CONF_CM_UNCACHED - mtc0 t0, CP0_CONFIG - ehb + /* Disable caches */ + PTR_LA t9, mips_cache_disable + jalr t9 + nop #endif #ifdef CONFIG_MIPS_CM diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S index 2233d27137..602741c65d 100644 --- a/arch/mips/lib/cache_init.S +++ b/arch/mips/lib/cache_init.S @@ -418,6 +418,12 @@ return: jr R_RETURN END(mips_cache_reset) +LEAF(mips_cache_disable) + move R_RETURN, ra + change_k0_cca_kseg1 CONF_CM_UNCACHED + jr R_RETURN + END(mips_cache_disable) + LEAF(change_k0_cca) mfc0 t0, CP0_CONFIG #if __mips_isa_rev >= 2 From 57bfb1aed6a87b19ca7e2a76df83ea387621e2e9 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 00:45:57 +0200 Subject: [PATCH 10/20] mips: add config options for generic cache setup code Add an own Kconfig symbol for the initial disabling of caches invoked from generic start code. Also add an own Kconfig symbols for the initialization of caches invoked from generic start code. Until now both code paths could only be disabled with CONFIG_SKIP_LOWLEVEL_INIT. But this is not flexible enough for RAM boot scenarios like EJTAG or SPL payload or for machines which don't require cache initialization or which want to provide their own cache implementation. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/Kconfig | 24 ++++++++++++++++++++++++ arch/mips/cpu/start.S | 6 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 48e754cc46..eb00ee71bc 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -270,6 +270,30 @@ config MIPS_CACHE_INDEX_BASE Normally this is CKSEG0. If the MIPS system needs to move this block to some SRAM or ScratchPad RAM, adapt this option accordingly. +config MIPS_CACHE_SETUP + bool "Allow generic start code to initialize and setup caches" + default n if SKIP_LOWLEVEL_INIT + default y + help + This allows the generic start code to invoke the generic initialization + of the CPU caches. Disabling this can be useful for RAM boot scenarios + (EJTAG, SPL payload) or for machines which don't need cache initialization + or which want to provide their own cache implementation. + + If unsure, say yes. + +config MIPS_CACHE_DISABLE + bool "Allow generic start code to initially disable caches" + default n if SKIP_LOWLEVEL_INIT + default y + help + This allows the generic start code to initially disable the CPU caches + and run uncached until the caches are initialized and enabled. Disabling + this can be useful on machines which don't need cache initialization or + which want to provide their own cache implementation. + + If unsure, say yes. + config MIPS_RELOCATION_TABLE_SIZE hex "Relocation table size" range 0x100 0x10000 diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index a9f8743717..0c303031ad 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -195,7 +195,7 @@ wr_done: /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */ mtc0 zero, CP0_COMPARE -#ifndef CONFIG_SKIP_LOWLEVEL_INIT +#ifdef CONFIG_MIPS_CACHE_DISABLE /* Disable caches */ PTR_LA t9, mips_cache_disable jalr t9 @@ -234,12 +234,16 @@ wr_done: jalr t9 nop # endif +#endif +#ifdef CONFIG_MIPS_CACHE_SETUP /* Initialize caches... */ PTR_LA t9, mips_cache_reset jalr t9 nop +#endif +#ifndef CONFIG_SKIP_LOWLEVEL_INIT # ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* Initialize any external memory */ PTR_LA t9, lowlevel_init From dd1bb42305033b77032099ce03cbed6bdbb74612 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 01:46:15 +0200 Subject: [PATCH 11/20] mips: remove deprecated UNCACHED_SDRAM() macro This macro only served as a wrapper for CKSEG1ADDR() with an exception for CONFIG_TB0229. CONFIG_TB0229 doesn't exist, thus use CKSEG1ADDR() directly. This also prepares for an upcoming asm header sync with Linux. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/include/asm/addrspace.h | 13 ------------- arch/mips/lib/bootm.c | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index b6d387677e..ae6f586f00 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -126,19 +126,6 @@ #define PHYS_TO_XKPHYS(cm, a) (_CONST64_(0x8000000000000000) | \ (_CONST64_(cm) << 59) | (a)) -/* - * Returns the uncached address of a sdram address - */ -#ifndef __ASSEMBLY__ -#if defined(CONFIG_TB0229) -/* We use a 36 bit physical address map here and - cannot access physical memory directly from core */ -#define UNCACHED_SDRAM(a) (((unsigned long)(a)) | 0x20000000) -#else /* !CONFIG_TB0229 */ -#define UNCACHED_SDRAM(a) CKSEG1ADDR(a) -#endif /* CONFIG_TB0229 */ -#endif /* __ASSEMBLY__ */ - /* * The ultimate limited of the 64-bit MIPS architecture: 2 bits for selecting * the region, 3 bits for the CCA mode. This leaves 59 bits of which the diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c index 82f986cb81..0a13f6edb7 100644 --- a/arch/mips/lib/bootm.c +++ b/arch/mips/lib/bootm.c @@ -51,7 +51,7 @@ void arch_lmb_reserve(struct lmb *lmb) static void linux_cmdline_init(void) { linux_argc = 1; - linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params); + linux_argv = (char **)CKSEG1ADDR(gd->bd->bi_boot_params); linux_argv[0] = 0; linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS); } @@ -186,7 +186,7 @@ static void linux_env_legacy(bootm_headers_t *images) (ulong)(gd->ram_size >> 20)); } - rd_start = UNCACHED_SDRAM(images->initrd_start); + rd_start = CKSEG1ADDR(images->initrd_start); rd_size = images->initrd_end - images->initrd_start; linux_env_init(); From eac800043fade8d7c64e925125e258e60f83d95b Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 01:46:16 +0200 Subject: [PATCH 12/20] mips: sync asm/asm.h with Linux 5.7 Sync asm/asm.h with Linux 5.7. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/include/asm/asm.h | 130 +++--------------------------------- 1 file changed, 10 insertions(+), 120 deletions(-) diff --git a/arch/mips/include/asm/asm.h b/arch/mips/include/asm/asm.h index 7abcf6df07..a6876e1b07 100644 --- a/arch/mips/include/asm/asm.h +++ b/arch/mips/include/asm/asm.h @@ -16,37 +16,12 @@ #include -#ifndef CAT -#ifdef __STDC__ -#define __CAT(str1, str2) str1##str2 -#else -#define __CAT(str1, str2) str1/**/str2 -#endif -#define CAT(str1, str2) __CAT(str1, str2) -#endif - -/* - * PIC specific declarations - * Not used for the kernel but here seems to be the right place. - */ -#ifdef __PIC__ -#define CPRESTORE(register) \ - .cprestore register -#define CPADD(register) \ - .cpadd register -#define CPLOAD(register) \ - .cpload register -#else -#define CPRESTORE(register) -#define CPADD(register) -#define CPLOAD(register) -#endif - #define ENTRY(symbol) \ .globl symbol; \ .type symbol, @function; \ .ent symbol, 0; \ -symbol: +symbol: .cfi_startproc; \ + .insn /* * LEAF - declare leaf routine @@ -57,7 +32,9 @@ symbol: .type symbol, @function; \ .ent symbol, 0; \ .section .text.symbol, "x"; \ -symbol: .frame sp, 0, ra +symbol: .frame sp, 0, ra; \ + .cfi_startproc; \ + .insn /* * NESTED - declare nested routine entry point @@ -68,12 +45,15 @@ symbol: .frame sp, 0, ra .type symbol, @function; \ .ent symbol, 0; \ .section .text.symbol, "x"; \ -symbol: .frame sp, framesize, rpc +symbol: .frame sp, framesize, rpc; \ + .cfi_startproc; \ + .insn /* * END - mark end of function */ #define END(function) \ + .cfi_endproc; \ .end function; \ .size function, .-function @@ -90,7 +70,7 @@ symbol: #define FEXPORT(symbol) \ .globl symbol; \ .type symbol, @function; \ -symbol: +symbol: .insn /* * ABS - export absolute symbol @@ -128,96 +108,6 @@ symbol = value 8: .asciiz msg; \ .popsection; -/* - * Build text tables - */ -#define TTABLE(string) \ - .pushsection .text; \ - .word 1f; \ - .popsection \ - .pushsection .data; \ -1: .asciiz string; \ - .popsection - -/* - * MIPS IV pref instruction. - * Use with .set noreorder only! - * - * MIPS IV implementations are free to treat this as a nop. The R5000 - * is one of them. So we should have an option not to use this instruction. - */ -#ifdef CONFIG_CPU_HAS_PREFETCH - -#define PREF(hint, addr) \ - .set push; \ - .set arch=r5000; \ - pref hint, addr; \ - .set pop - -#define PREFE(hint, addr) \ - .set push; \ - .set mips0; \ - .set eva; \ - prefe hint, addr; \ - .set pop - -#define PREFX(hint, addr) \ - .set push; \ - .set arch=r5000; \ - prefx hint, addr; \ - .set pop - -#else /* !CONFIG_CPU_HAS_PREFETCH */ - -#define PREF(hint, addr) -#define PREFE(hint, addr) -#define PREFX(hint, addr) - -#endif /* !CONFIG_CPU_HAS_PREFETCH */ - -/* - * MIPS ISA IV/V movn/movz instructions and equivalents for older CPUs. - */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS1) -#define MOVN(rd, rs, rt) \ - .set push; \ - .set reorder; \ - beqz rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#define MOVZ(rd, rs, rt) \ - .set push; \ - .set reorder; \ - bnez rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#endif /* _MIPS_ISA == _MIPS_ISA_MIPS1 */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) -#define MOVN(rd, rs, rt) \ - .set push; \ - .set noreorder; \ - bnezl rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#define MOVZ(rd, rs, rt) \ - .set push; \ - .set noreorder; \ - beqzl rt, 9f; \ - move rd, rs; \ - .set pop; \ -9: -#endif /* (_MIPS_ISA == _MIPS_ISA_MIPS2) || (_MIPS_ISA == _MIPS_ISA_MIPS3) */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS4 ) || (_MIPS_ISA == _MIPS_ISA_MIPS5) || \ - (_MIPS_ISA == _MIPS_ISA_MIPS32) || (_MIPS_ISA == _MIPS_ISA_MIPS64) -#define MOVN(rd, rs, rt) \ - movn rd, rs, rt -#define MOVZ(rd, rs, rt) \ - movz rd, rs, rt -#endif /* MIPS IV, MIPS V, MIPS32 or MIPS64 */ - /* * Stack alignment */ From c0f99579faeb9d6a14609d4855a1d6888a10e6f4 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 01:46:17 +0200 Subject: [PATCH 13/20] mips: sync asm/addrspace.h with Linux 5.7 Sync asm/addrspace.h with Linux 5.7 Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/include/asm/addrspace.h | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h index ae6f586f00..8112ab833e 100644 --- a/arch/mips/include/asm/addrspace.h +++ b/arch/mips/include/asm/addrspace.h @@ -42,7 +42,7 @@ /* * Returns the kernel segment base of a given address */ -#define KSEGX(a) ((_ACAST32_ (a)) & 0xe0000000) +#define KSEGX(a) ((_ACAST32_(a)) & _ACAST32_(0xe0000000)) /* * Returns the physical address of a CKSEGx / XKPHYS address @@ -123,8 +123,7 @@ #define PHYS_TO_XKSEG_UNCACHED(p) PHYS_TO_XKPHYS(K_CALG_UNCACHED, (p)) #define PHYS_TO_XKSEG_CACHED(p) PHYS_TO_XKPHYS(K_CALG_COH_SHAREABLE, (p)) #define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK) -#define PHYS_TO_XKPHYS(cm, a) (_CONST64_(0x8000000000000000) | \ - (_CONST64_(cm) << 59) | (a)) +#define PHYS_TO_XKPHYS(cm, a) (XKPHYS | (_ACAST64_(cm) << 59) | (a)) /* * The ultimate limited of the 64-bit MIPS architecture: 2 bits for selecting @@ -133,18 +132,9 @@ */ #define TO_PHYS_MASK _CONST64_(0x07ffffffffffffff) /* 2^^59 - 1 */ -#ifndef CONFIG_CPU_R8000 - -/* - * The R8000 doesn't have the 32-bit compat spaces so we don't define them - * in order to catch bugs in the source code. - */ - #define COMPAT_K1BASE32 _CONST64_(0xffffffffa0000000) #define PHYS_TO_COMPATK1(x) ((x) | COMPAT_K1BASE32) /* 32-bit compat k1 */ -#endif - #define KDM_TO_PHYS(x) (_ACAST64_ (x) & TO_PHYS_MASK) #define PHYS_TO_K0(x) (_ACAST64_ (x) | CAC_BASE) From 81d4b14f7e7e4492d99af96c42be7fd8b26eb4d7 Mon Sep 17 00:00:00 2001 From: Daniel Schwierzeck Date: Sun, 12 Jul 2020 01:46:18 +0200 Subject: [PATCH 14/20] mips: sync asm/mipsregs.h with Linux 5.7 Sync asm/mipsregs.h with Linux 5.7. Also replace the custom symbols EBASE_CPUNUM and EBASE_WG with the according symbols from Linux. Signed-off-by: Daniel Schwierzeck Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- arch/mips/cpu/start.S | 2 +- arch/mips/include/asm/compiler.h | 69 ++ arch/mips/include/asm/isa-rev.h | 24 + arch/mips/include/asm/mipsregs.h | 1208 +++++++++++++++++++++++++----- arch/mips/lib/traps.c | 2 +- 5 files changed, 1106 insertions(+), 199 deletions(-) create mode 100644 arch/mips/include/asm/compiler.h create mode 100644 arch/mips/include/asm/isa-rev.h diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index 0c303031ad..e22771715c 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -138,7 +138,7 @@ reset: and t0, t0, (1 << 31) #else 1: mfc0 t0, CP0_EBASE - and t0, t0, EBASE_CPUNUM + and t0, t0, MIPS_EBASE_CPUNUM #endif /* Hang if this isn't the first CPU in the system */ diff --git a/arch/mips/include/asm/compiler.h b/arch/mips/include/asm/compiler.h new file mode 100644 index 0000000000..c498b42f1c --- /dev/null +++ b/arch/mips/include/asm/compiler.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2004, 2007 Maciej W. Rozycki + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_COMPILER_H +#define _ASM_COMPILER_H + +/* + * With GCC 4.5 onwards we can use __builtin_unreachable to indicate to the + * compiler that a particular code path will never be hit. This allows it to be + * optimised out of the generated binary. + * + * Unfortunately at least GCC 4.6.3 through 7.3.0 inclusive suffer from a bug + * that can lead to instructions from beyond an unreachable statement being + * incorrectly reordered into earlier delay slots if the unreachable statement + * is the only content of a case in a switch statement. This can lead to + * seemingly random behaviour, such as invalid memory accesses from incorrectly + * reordered loads or stores. See this potential GCC fix for details: + * + * https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00360.html + * + * It is unclear whether GCC 8 onwards suffer from the same issue - nothing + * relevant is mentioned in GCC 8 release notes and nothing obviously relevant + * stands out in GCC commit logs, but these newer GCC versions generate very + * different code for the testcase which doesn't exhibit the bug. + * + * GCC also handles stack allocation suboptimally when calling noreturn + * functions or calling __builtin_unreachable(): + * + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365 + * + * We work around both of these issues by placing a volatile asm statement, + * which GCC is prevented from reordering past, prior to __builtin_unreachable + * calls. + * + * The .insn statement is required to ensure that any branches to the + * statement, which sadly must be kept due to the asm statement, are known to + * be branches to code and satisfy linker requirements for microMIPS kernels. + */ +#undef barrier_before_unreachable +#define barrier_before_unreachable() asm volatile(".insn") + +#if !defined(CONFIG_CC_IS_GCC) || \ + (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) +# define GCC_OFF_SMALL_ASM() "ZC" +#elif defined(CONFIG_CPU_MICROMIPS) +# error "microMIPS compilation unsupported with GCC older than 4.9" +#else +# define GCC_OFF_SMALL_ASM() "R" +#endif + +#ifdef CONFIG_CPU_MIPSR6 +#define MIPS_ISA_LEVEL "mips64r6" +#define MIPS_ISA_ARCH_LEVEL MIPS_ISA_LEVEL +#define MIPS_ISA_LEVEL_RAW mips64r6 +#define MIPS_ISA_ARCH_LEVEL_RAW MIPS_ISA_LEVEL_RAW +#else +/* MIPS64 is a superset of MIPS32 */ +#define MIPS_ISA_LEVEL "mips64r2" +#define MIPS_ISA_ARCH_LEVEL "arch=r4000" +#define MIPS_ISA_LEVEL_RAW mips64r2 +#define MIPS_ISA_ARCH_LEVEL_RAW MIPS_ISA_LEVEL_RAW +#endif /* CONFIG_CPU_MIPSR6 */ + +#endif /* _ASM_COMPILER_H */ diff --git a/arch/mips/include/asm/isa-rev.h b/arch/mips/include/asm/isa-rev.h new file mode 100644 index 0000000000..683ea3454d --- /dev/null +++ b/arch/mips/include/asm/isa-rev.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MIPS Tech, LLC + * Author: Matt Redfearn + */ + +#ifndef __MIPS_ASM_ISA_REV_H__ +#define __MIPS_ASM_ISA_REV_H__ + +/* + * The ISA revision level. This is 0 for MIPS I to V and N for + * MIPS{32,64}rN. + */ + +/* If the compiler has defined __mips_isa_rev, believe it. */ +#ifdef __mips_isa_rev +#define MIPS_ISA_REV __mips_isa_rev +#else +/* The compiler hasn't defined the isa rev so assume it's MIPS I - V (0) */ +#define MIPS_ISA_REV 0 +#endif + + +#endif /* __MIPS_ASM_ISA_REV_H__ */ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 17381301ec..e65485b4ff 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -10,6 +10,8 @@ #ifndef _ASM_MIPSREGS_H #define _ASM_MIPSREGS_H +#include +#include /* * The following macros are especially useful for __asm__ * inline assembler. @@ -26,9 +28,10 @@ */ #ifdef __ASSEMBLY__ #define _ULCAST_ +#define _U64CAST_ #else -#include #define _ULCAST_ (unsigned long) +#define _U64CAST_ (u64) #endif /* @@ -42,15 +45,25 @@ #define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 +#define CP0_PAGEGRAIN $5, 1 +#define CP0_SEGCTL0 $5, 2 +#define CP0_SEGCTL1 $5, 3 +#define CP0_SEGCTL2 $5, 4 #define CP0_WIRED $6 #define CP0_INFO $7 -#define CP0_HWRENA $7, 0 +#define CP0_HWRENA $7 #define CP0_BADVADDR $8 #define CP0_BADINSTR $8, 1 #define CP0_COUNT $9 #define CP0_ENTRYHI $10 +#define CP0_GUESTCTL1 $10, 4 +#define CP0_GUESTCTL2 $10, 5 +#define CP0_GUESTCTL3 $10, 6 #define CP0_COMPARE $11 +#define CP0_GUESTCTL0EXT $11, 4 #define CP0_STATUS $12 +#define CP0_GUESTCTL0 $12, 6 +#define CP0_GTOFFSET $12, 7 #define CP0_CAUSE $13 #define CP0_EPC $14 #define CP0_PRID $15 @@ -59,6 +72,7 @@ #define CP0_CONFIG $16 #define CP0_CONFIG3 $16, 3 #define CP0_CONFIG5 $16, 5 +#define CP0_CONFIG6 $16, 6 #define CP0_LLADDR $17 #define CP0_WATCHLO $18 #define CP0_WATCHHI $19 @@ -130,6 +144,16 @@ #define MIPS_ENTRYLO_XI (_ULCAST_(1) << (BITS_PER_LONG - 2)) #define MIPS_ENTRYLO_RI (_ULCAST_(1) << (BITS_PER_LONG - 1)) +/* + * MIPSr6+ GlobalNumber register definitions + */ +#define MIPS_GLOBALNUMBER_VP_SHF 0 +#define MIPS_GLOBALNUMBER_VP (_ULCAST_(0xff) << MIPS_GLOBALNUMBER_VP_SHF) +#define MIPS_GLOBALNUMBER_CORE_SHF 8 +#define MIPS_GLOBALNUMBER_CORE (_ULCAST_(0xff) << MIPS_GLOBALNUMBER_CORE_SHF) +#define MIPS_GLOBALNUMBER_CLUSTER_SHF 16 +#define MIPS_GLOBALNUMBER_CLUSTER (_ULCAST_(0xf) << MIPS_GLOBALNUMBER_CLUSTER_SHF) + /* * Values for PageMask register */ @@ -189,6 +213,8 @@ /* MIPS32/64 EntryHI bit definitions */ #define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) +#define MIPS_ENTRYHI_ASIDX (_ULCAST_(0x3) << 8) +#define MIPS_ENTRYHI_ASID (_ULCAST_(0xff) << 0) /* * R4x00 interrupt enable / cause bits @@ -351,10 +377,14 @@ #define CAUSEF_IP7 (_ULCAST_(1) << 15) #define CAUSEB_FDCI 21 #define CAUSEF_FDCI (_ULCAST_(1) << 21) +#define CAUSEB_WP 22 +#define CAUSEF_WP (_ULCAST_(1) << 22) #define CAUSEB_IV 23 #define CAUSEF_IV (_ULCAST_(1) << 23) #define CAUSEB_PCI 26 #define CAUSEF_PCI (_ULCAST_(1) << 26) +#define CAUSEB_DC 27 +#define CAUSEF_DC (_ULCAST_(1) << 27) #define CAUSEB_CE 28 #define CAUSEF_CE (_ULCAST_(3) << 28) #define CAUSEB_TI 30 @@ -363,10 +393,36 @@ #define CAUSEF_BD (_ULCAST_(1) << 31) /* - * Bits in the coprocessor 0 EBase register. + * Cause.ExcCode trap codes. */ -#define EBASE_CPUNUM 0x3ff -#define EBASE_WG (_ULCAST_(1) << 11) +#define EXCCODE_INT 0 /* Interrupt pending */ +#define EXCCODE_MOD 1 /* TLB modified fault */ +#define EXCCODE_TLBL 2 /* TLB miss on load or ifetch */ +#define EXCCODE_TLBS 3 /* TLB miss on a store */ +#define EXCCODE_ADEL 4 /* Address error on a load or ifetch */ +#define EXCCODE_ADES 5 /* Address error on a store */ +#define EXCCODE_IBE 6 /* Bus error on an ifetch */ +#define EXCCODE_DBE 7 /* Bus error on a load or store */ +#define EXCCODE_SYS 8 /* System call */ +#define EXCCODE_BP 9 /* Breakpoint */ +#define EXCCODE_RI 10 /* Reserved instruction exception */ +#define EXCCODE_CPU 11 /* Coprocessor unusable */ +#define EXCCODE_OV 12 /* Arithmetic overflow */ +#define EXCCODE_TR 13 /* Trap instruction */ +#define EXCCODE_MSAFPE 14 /* MSA floating point exception */ +#define EXCCODE_FPE 15 /* Floating point exception */ +#define EXCCODE_TLBRI 19 /* TLB Read-Inhibit exception */ +#define EXCCODE_TLBXI 20 /* TLB Execution-Inhibit exception */ +#define EXCCODE_MSADIS 21 /* MSA disabled exception */ +#define EXCCODE_MDMX 22 /* MDMX unusable exception */ +#define EXCCODE_WATCH 23 /* Watch address reference */ +#define EXCCODE_MCHECK 24 /* Machine check */ +#define EXCCODE_THREAD 25 /* Thread exceptions (MT) */ +#define EXCCODE_DSPDIS 26 /* DSP disabled exception */ +#define EXCCODE_GE 27 /* Virtualized guest exception (VZ) */ + +/* Implementation specific trap codes used by MIPS cores */ +#define MIPS_EXCCODE_TLBPAR 16 /* TLB parity error exception */ /* * Bits in the coprocessor 0 config register. @@ -394,7 +450,7 @@ #define CONF_SM (_ULCAST_(1) << 16) #define CONF_SC (_ULCAST_(1) << 17) #define CONF_EW (_ULCAST_(3) << 18) -#define CONF_EP (_ULCAST_(15) << 24) +#define CONF_EP (_ULCAST_(15)<< 24) #define CONF_EC (_ULCAST_(7) << 28) #define CONF_CM (_ULCAST_(1) << 31) @@ -420,7 +476,7 @@ #define R10K_CONF_CT (_ULCAST_(1) << 5) #define R10K_CONF_PE (_ULCAST_(1) << 6) #define R10K_CONF_PM (_ULCAST_(3) << 7) -#define R10K_CONF_EC (_ULCAST_(15) << 9) +#define R10K_CONF_EC (_ULCAST_(15)<< 9) #define R10K_CONF_SB (_ULCAST_(1) << 13) #define R10K_CONF_SK (_ULCAST_(1) << 14) #define R10K_CONF_SS (_ULCAST_(7) << 16) @@ -453,6 +509,7 @@ #define TX49_CONF_CWFON (_ULCAST_(1) << 27) /* Bits specific to the MIPS32/64 PRA. */ +#define MIPS_CONF_VI (_ULCAST_(1) << 3) #define MIPS_CONF_MT (_ULCAST_(7) << 7) #define MIPS_CONF_MT_TLB (_ULCAST_(1) << 7) #define MIPS_CONF_MT_FTLB (_ULCAST_(4) << 7) @@ -549,7 +606,8 @@ #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14) #define MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT (_ULCAST_(2) << 14) #define MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT (_ULCAST_(3) << 14) -#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << 16) +#define MIPS_CONF4_KSCREXIST_SHIFT (16) +#define MIPS_CONF4_KSCREXIST (_ULCAST_(255) << MIPS_CONF4_KSCREXIST_SHIFT) #define MIPS_CONF4_VTLBSIZEEXT_SHIFT (24) #define MIPS_CONF4_VTLBSIZEEXT (_ULCAST_(15) << MIPS_CONF4_VTLBSIZEEXT_SHIFT) #define MIPS_CONF4_AE (_ULCAST_(1) << 28) @@ -562,9 +620,13 @@ #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) #define MIPS_CONF5_VP (_ULCAST_(1) << 7) +#define MIPS_CONF5_SBRI (_ULCAST_(1) << 6) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) #define MIPS_CONF5_L2C (_ULCAST_(1) << 10) +#define MIPS_CONF5_CA2 (_ULCAST_(1) << 14) +#define MIPS_CONF5_MI (_ULCAST_(1) << 17) +#define MIPS_CONF5_CRCP (_ULCAST_(1) << 18) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) #define MIPS_CONF5_EVA (_ULCAST_(1) << 28) #define MIPS_CONF5_CV (_ULCAST_(1) << 29) @@ -573,6 +635,8 @@ #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) /* proAptiv FTLB on/off bit */ #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) +/* Loongson-3 FTLB on/off bit */ +#define MIPS_CONF6_FTLBDIS (_ULCAST_(1) << 22) /* FTLB probability bits */ #define MIPS_CONF6_FTLBP_SHIFT (16) @@ -582,19 +646,95 @@ #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) -/* FTLB probability bits for R6 */ -#define MIPS_CONF7_FTLBP_SHIFT (18) + +/* Ingenic HPTLB off bits */ +#define XBURST_PAGECTRL_HPTLB_DIS 0xa9000000 + +/* Ingenic Config7 bits */ +#define MIPS_CONF7_BTB_LOOP_EN (_ULCAST_(1) << 4) + +/* Config7 Bits specific to MIPS Technologies. */ + +/* Performance counters implemented Per TC */ +#define MTI_CONF7_PTC (_ULCAST_(1) << 19) + +/* WatchLo* register definitions */ +#define MIPS_WATCHLO_IRW (_ULCAST_(0x7) << 0) + +/* WatchHi* register definitions */ +#define MIPS_WATCHHI_M (_ULCAST_(1) << 31) +#define MIPS_WATCHHI_G (_ULCAST_(1) << 30) +#define MIPS_WATCHHI_WM (_ULCAST_(0x3) << 28) +#define MIPS_WATCHHI_WM_R_RVA (_ULCAST_(0) << 28) +#define MIPS_WATCHHI_WM_R_GPA (_ULCAST_(1) << 28) +#define MIPS_WATCHHI_WM_G_GVA (_ULCAST_(2) << 28) +#define MIPS_WATCHHI_EAS (_ULCAST_(0x3) << 24) +#define MIPS_WATCHHI_ASID (_ULCAST_(0xff) << 16) +#define MIPS_WATCHHI_MASK (_ULCAST_(0x1ff) << 3) +#define MIPS_WATCHHI_I (_ULCAST_(1) << 2) +#define MIPS_WATCHHI_R (_ULCAST_(1) << 1) +#define MIPS_WATCHHI_W (_ULCAST_(1) << 0) +#define MIPS_WATCHHI_IRW (_ULCAST_(0x7) << 0) + +/* PerfCnt control register definitions */ +#define MIPS_PERFCTRL_EXL (_ULCAST_(1) << 0) +#define MIPS_PERFCTRL_K (_ULCAST_(1) << 1) +#define MIPS_PERFCTRL_S (_ULCAST_(1) << 2) +#define MIPS_PERFCTRL_U (_ULCAST_(1) << 3) +#define MIPS_PERFCTRL_IE (_ULCAST_(1) << 4) +#define MIPS_PERFCTRL_EVENT_S 5 +#define MIPS_PERFCTRL_EVENT (_ULCAST_(0x3ff) << MIPS_PERFCTRL_EVENT_S) +#define MIPS_PERFCTRL_PCTD (_ULCAST_(1) << 15) +#define MIPS_PERFCTRL_EC (_ULCAST_(0x3) << 23) +#define MIPS_PERFCTRL_EC_R (_ULCAST_(0) << 23) +#define MIPS_PERFCTRL_EC_RI (_ULCAST_(1) << 23) +#define MIPS_PERFCTRL_EC_G (_ULCAST_(2) << 23) +#define MIPS_PERFCTRL_EC_GRI (_ULCAST_(3) << 23) +#define MIPS_PERFCTRL_W (_ULCAST_(1) << 30) +#define MIPS_PERFCTRL_M (_ULCAST_(1) << 31) + +/* PerfCnt control register MT extensions used by MIPS cores */ +#define MIPS_PERFCTRL_VPEID_S 16 +#define MIPS_PERFCTRL_VPEID (_ULCAST_(0xf) << MIPS_PERFCTRL_VPEID_S) +#define MIPS_PERFCTRL_TCID_S 22 +#define MIPS_PERFCTRL_TCID (_ULCAST_(0xff) << MIPS_PERFCTRL_TCID_S) +#define MIPS_PERFCTRL_MT_EN (_ULCAST_(0x3) << 20) +#define MIPS_PERFCTRL_MT_EN_ALL (_ULCAST_(0) << 20) +#define MIPS_PERFCTRL_MT_EN_VPE (_ULCAST_(1) << 20) +#define MIPS_PERFCTRL_MT_EN_TC (_ULCAST_(2) << 20) + +/* PerfCnt control register MT extensions used by BMIPS5000 */ +#define BRCM_PERFCTRL_TC (_ULCAST_(1) << 30) + +/* PerfCnt control register MT extensions used by Netlogic XLR */ +#define XLR_PERFCTRL_ALLTHREADS (_ULCAST_(1) << 13) /* MAAR bit definitions */ +#define MIPS_MAAR_VH (_U64CAST_(1) << 63) #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) #define MIPS_MAAR_ADDR_SHIFT 12 #define MIPS_MAAR_S (_ULCAST_(1) << 1) -#define MIPS_MAAR_V (_ULCAST_(1) << 0) +#define MIPS_MAAR_VL (_ULCAST_(1) << 0) + +/* MAARI bit definitions */ +#define MIPS_MAARI_INDEX (_ULCAST_(0x3f) << 0) + +/* EBase bit definitions */ +#define MIPS_EBASE_CPUNUM_SHIFT 0 +#define MIPS_EBASE_CPUNUM (_ULCAST_(0x3ff) << 0) +#define MIPS_EBASE_WG_SHIFT 11 +#define MIPS_EBASE_WG (_ULCAST_(1) << 11) +#define MIPS_EBASE_BASE_SHIFT 12 +#define MIPS_EBASE_BASE (~_ULCAST_((1 << MIPS_EBASE_BASE_SHIFT) - 1)) /* CMGCRBase bit definitions */ #define MIPS_CMGCRB_BASE 11 #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) +/* LLAddr bit definitions */ +#define MIPS_LLADDR_LLB_SHIFT 0 +#define MIPS_LLADDR_LLB (_ULCAST_(1) << MIPS_LLADDR_LLB_SHIFT) + /* * Bits in the MIPS32 Memory Segmentation registers. */ @@ -626,6 +766,8 @@ #define MIPS_PWFIELD_PTEI_SHIFT 0 #define MIPS_PWFIELD_PTEI_MASK 0x0000003f +#define MIPS_PWSIZE_PS_SHIFT 30 +#define MIPS_PWSIZE_PS_MASK 0x40000000 #define MIPS_PWSIZE_GDW_SHIFT 24 #define MIPS_PWSIZE_GDW_MASK 0x3f000000 #define MIPS_PWSIZE_UDW_SHIFT 18 @@ -639,6 +781,12 @@ #define MIPS_PWCTL_PWEN_SHIFT 31 #define MIPS_PWCTL_PWEN_MASK 0x80000000 +#define MIPS_PWCTL_XK_SHIFT 28 +#define MIPS_PWCTL_XK_MASK 0x10000000 +#define MIPS_PWCTL_XS_SHIFT 27 +#define MIPS_PWCTL_XS_MASK 0x08000000 +#define MIPS_PWCTL_XU_SHIFT 26 +#define MIPS_PWCTL_XU_MASK 0x04000000 #define MIPS_PWCTL_DPH_SHIFT 7 #define MIPS_PWCTL_DPH_MASK 0x00000080 #define MIPS_PWCTL_HUGEPG_SHIFT 6 @@ -646,6 +794,94 @@ #define MIPS_PWCTL_PSN_SHIFT 0 #define MIPS_PWCTL_PSN_MASK 0x0000003f +/* GuestCtl0 fields */ +#define MIPS_GCTL0_GM_SHIFT 31 +#define MIPS_GCTL0_GM (_ULCAST_(1) << MIPS_GCTL0_GM_SHIFT) +#define MIPS_GCTL0_RI_SHIFT 30 +#define MIPS_GCTL0_RI (_ULCAST_(1) << MIPS_GCTL0_RI_SHIFT) +#define MIPS_GCTL0_MC_SHIFT 29 +#define MIPS_GCTL0_MC (_ULCAST_(1) << MIPS_GCTL0_MC_SHIFT) +#define MIPS_GCTL0_CP0_SHIFT 28 +#define MIPS_GCTL0_CP0 (_ULCAST_(1) << MIPS_GCTL0_CP0_SHIFT) +#define MIPS_GCTL0_AT_SHIFT 26 +#define MIPS_GCTL0_AT (_ULCAST_(0x3) << MIPS_GCTL0_AT_SHIFT) +#define MIPS_GCTL0_GT_SHIFT 25 +#define MIPS_GCTL0_GT (_ULCAST_(1) << MIPS_GCTL0_GT_SHIFT) +#define MIPS_GCTL0_CG_SHIFT 24 +#define MIPS_GCTL0_CG (_ULCAST_(1) << MIPS_GCTL0_CG_SHIFT) +#define MIPS_GCTL0_CF_SHIFT 23 +#define MIPS_GCTL0_CF (_ULCAST_(1) << MIPS_GCTL0_CF_SHIFT) +#define MIPS_GCTL0_G1_SHIFT 22 +#define MIPS_GCTL0_G1 (_ULCAST_(1) << MIPS_GCTL0_G1_SHIFT) +#define MIPS_GCTL0_G0E_SHIFT 19 +#define MIPS_GCTL0_G0E (_ULCAST_(1) << MIPS_GCTL0_G0E_SHIFT) +#define MIPS_GCTL0_PT_SHIFT 18 +#define MIPS_GCTL0_PT (_ULCAST_(1) << MIPS_GCTL0_PT_SHIFT) +#define MIPS_GCTL0_RAD_SHIFT 9 +#define MIPS_GCTL0_RAD (_ULCAST_(1) << MIPS_GCTL0_RAD_SHIFT) +#define MIPS_GCTL0_DRG_SHIFT 8 +#define MIPS_GCTL0_DRG (_ULCAST_(1) << MIPS_GCTL0_DRG_SHIFT) +#define MIPS_GCTL0_G2_SHIFT 7 +#define MIPS_GCTL0_G2 (_ULCAST_(1) << MIPS_GCTL0_G2_SHIFT) +#define MIPS_GCTL0_GEXC_SHIFT 2 +#define MIPS_GCTL0_GEXC (_ULCAST_(0x1f) << MIPS_GCTL0_GEXC_SHIFT) +#define MIPS_GCTL0_SFC2_SHIFT 1 +#define MIPS_GCTL0_SFC2 (_ULCAST_(1) << MIPS_GCTL0_SFC2_SHIFT) +#define MIPS_GCTL0_SFC1_SHIFT 0 +#define MIPS_GCTL0_SFC1 (_ULCAST_(1) << MIPS_GCTL0_SFC1_SHIFT) + +/* GuestCtl0.AT Guest address translation control */ +#define MIPS_GCTL0_AT_ROOT 1 /* Guest MMU under Root control */ +#define MIPS_GCTL0_AT_GUEST 3 /* Guest MMU under Guest control */ + +/* GuestCtl0.GExcCode Hypervisor exception cause codes */ +#define MIPS_GCTL0_GEXC_GPSI 0 /* Guest Privileged Sensitive Instruction */ +#define MIPS_GCTL0_GEXC_GSFC 1 /* Guest Software Field Change */ +#define MIPS_GCTL0_GEXC_HC 2 /* Hypercall */ +#define MIPS_GCTL0_GEXC_GRR 3 /* Guest Reserved Instruction Redirect */ +#define MIPS_GCTL0_GEXC_GVA 8 /* Guest Virtual Address available */ +#define MIPS_GCTL0_GEXC_GHFC 9 /* Guest Hardware Field Change */ +#define MIPS_GCTL0_GEXC_GPA 10 /* Guest Physical Address available */ + +/* GuestCtl0Ext fields */ +#define MIPS_GCTL0EXT_RPW_SHIFT 8 +#define MIPS_GCTL0EXT_RPW (_ULCAST_(0x3) << MIPS_GCTL0EXT_RPW_SHIFT) +#define MIPS_GCTL0EXT_NCC_SHIFT 6 +#define MIPS_GCTL0EXT_NCC (_ULCAST_(0x3) << MIPS_GCTL0EXT_NCC_SHIFT) +#define MIPS_GCTL0EXT_CGI_SHIFT 4 +#define MIPS_GCTL0EXT_CGI (_ULCAST_(1) << MIPS_GCTL0EXT_CGI_SHIFT) +#define MIPS_GCTL0EXT_FCD_SHIFT 3 +#define MIPS_GCTL0EXT_FCD (_ULCAST_(1) << MIPS_GCTL0EXT_FCD_SHIFT) +#define MIPS_GCTL0EXT_OG_SHIFT 2 +#define MIPS_GCTL0EXT_OG (_ULCAST_(1) << MIPS_GCTL0EXT_OG_SHIFT) +#define MIPS_GCTL0EXT_BG_SHIFT 1 +#define MIPS_GCTL0EXT_BG (_ULCAST_(1) << MIPS_GCTL0EXT_BG_SHIFT) +#define MIPS_GCTL0EXT_MG_SHIFT 0 +#define MIPS_GCTL0EXT_MG (_ULCAST_(1) << MIPS_GCTL0EXT_MG_SHIFT) + +/* GuestCtl0Ext.RPW Root page walk configuration */ +#define MIPS_GCTL0EXT_RPW_BOTH 0 /* Root PW for GPA->RPA and RVA->RPA */ +#define MIPS_GCTL0EXT_RPW_GPA 2 /* Root PW for GPA->RPA */ +#define MIPS_GCTL0EXT_RPW_RVA 3 /* Root PW for RVA->RPA */ + +/* GuestCtl0Ext.NCC Nested cache coherency attributes */ +#define MIPS_GCTL0EXT_NCC_IND 0 /* Guest CCA independent of Root CCA */ +#define MIPS_GCTL0EXT_NCC_MOD 1 /* Guest CCA modified by Root CCA */ + +/* GuestCtl1 fields */ +#define MIPS_GCTL1_ID_SHIFT 0 +#define MIPS_GCTL1_ID_WIDTH 8 +#define MIPS_GCTL1_ID (_ULCAST_(0xff) << MIPS_GCTL1_ID_SHIFT) +#define MIPS_GCTL1_RID_SHIFT 16 +#define MIPS_GCTL1_RID_WIDTH 8 +#define MIPS_GCTL1_RID (_ULCAST_(0xff) << MIPS_GCTL1_RID_SHIFT) +#define MIPS_GCTL1_EID_SHIFT 24 +#define MIPS_GCTL1_EID_WIDTH 8 +#define MIPS_GCTL1_EID (_ULCAST_(0xff) << MIPS_GCTL1_EID_SHIFT) + +/* GuestID reserved for root context */ +#define MIPS_GCTL1_ROOT_GUESTID 0 + /* CDMMBase register bit definitions */ #define MIPS_CDMMBASE_SIZE_SHIFT 0 #define MIPS_CDMMBASE_SIZE (_ULCAST_(511) << MIPS_CDMMBASE_SIZE_SHIFT) @@ -654,6 +890,24 @@ #define MIPS_CDMMBASE_ADDR_SHIFT 11 #define MIPS_CDMMBASE_ADDR_START 15 +/* RDHWR register numbers */ +#define MIPS_HWR_CPUNUM 0 /* CPU number */ +#define MIPS_HWR_SYNCISTEP 1 /* SYNCI step size */ +#define MIPS_HWR_CC 2 /* Cycle counter */ +#define MIPS_HWR_CCRES 3 /* Cycle counter resolution */ +#define MIPS_HWR_ULR 29 /* UserLocal */ +#define MIPS_HWR_IMPL1 30 /* Implementation dependent */ +#define MIPS_HWR_IMPL2 31 /* Implementation dependent */ + +/* Bits in HWREna register */ +#define MIPS_HWRENA_CPUNUM (_ULCAST_(1) << MIPS_HWR_CPUNUM) +#define MIPS_HWRENA_SYNCISTEP (_ULCAST_(1) << MIPS_HWR_SYNCISTEP) +#define MIPS_HWRENA_CC (_ULCAST_(1) << MIPS_HWR_CC) +#define MIPS_HWRENA_CCRES (_ULCAST_(1) << MIPS_HWR_CCRES) +#define MIPS_HWRENA_ULR (_ULCAST_(1) << MIPS_HWR_ULR) +#define MIPS_HWRENA_IMPL1 (_ULCAST_(1) << MIPS_HWR_IMPL1) +#define MIPS_HWRENA_IMPL2 (_ULCAST_(1) << MIPS_HWR_IMPL2) + /* * Bitfields in the TX39 family CP0 Configuration Register 3 */ @@ -697,6 +951,31 @@ /* Disable Branch Return Cache */ #define R10K_DIAG_D_BRC (_ULCAST_(1) << 22) +/* Flush ITLB */ +#define LOONGSON_DIAG_ITLB (_ULCAST_(1) << 2) +/* Flush DTLB */ +#define LOONGSON_DIAG_DTLB (_ULCAST_(1) << 3) +/* Flush VTLB */ +#define LOONGSON_DIAG_VTLB (_ULCAST_(1) << 12) +/* Flush FTLB */ +#define LOONGSON_DIAG_FTLB (_ULCAST_(1) << 13) + +/* CvmCtl register field definitions */ +#define CVMCTL_IPPCI_SHIFT 7 +#define CVMCTL_IPPCI (_U64CAST_(0x7) << CVMCTL_IPPCI_SHIFT) +#define CVMCTL_IPTI_SHIFT 4 +#define CVMCTL_IPTI (_U64CAST_(0x7) << CVMCTL_IPTI_SHIFT) + +/* CvmMemCtl2 register field definitions */ +#define CVMMEMCTL2_INHIBITTS (_U64CAST_(1) << 17) + +/* CvmVMConfig register field definitions */ +#define CVMVMCONF_DGHT (_U64CAST_(1) << 60) +#define CVMVMCONF_MMUSIZEM1_S 12 +#define CVMVMCONF_MMUSIZEM1 (_U64CAST_(0xff) << CVMVMCONF_MMUSIZEM1_S) +#define CVMVMCONF_RMMUSIZEM1_S 0 +#define CVMVMCONF_RMMUSIZEM1 (_U64CAST_(0xff) << CVMVMCONF_RMMUSIZEM1_S) + /* * Coprocessor 1 (FPU) register names */ @@ -780,9 +1059,12 @@ /* * Bits 22:20 of the FPU Status Register will be read as 0, * and should be written as zero. + * MAC2008 was removed in Release 5 so we still treat it as + * reserved. */ #define FPU_CSR_RSVD (_ULCAST_(7) << 20) +#define FPU_CSR_MAC2008 (_ULCAST_(1) << 20) #define FPU_CSR_ABS2008 (_ULCAST_(1) << 19) #define FPU_CSR_NAN2008 (_ULCAST_(1) << 18) @@ -827,14 +1109,14 @@ * Macros for handling the ISA mode bit for MIPS16 and microMIPS. */ #if defined(CONFIG_SYS_SUPPORTS_MIPS16) || \ - defined(CONFIG_SYS_SUPPORTS_MICROMIPS) + defined(CONFIG_SYS_SUPPORTS_MICROMIPS) #define get_isa16_mode(x) ((x) & 0x1) #define msk_isa16_mode(x) ((x) & ~0x1) -#define set_isa16_mode(x) do { (x) |= 0x1; } while (0) +#define set_isa16_mode(x) do { (x) |= 0x1; } while(0) #else #define get_isa16_mode(x) 0 #define msk_isa16_mode(x) (x) -#define set_isa16_mode(x) do { } while (0) +#define set_isa16_mode(x) do { } while(0) #endif /* @@ -848,6 +1130,123 @@ static inline int mm_insn_16bit(u16 insn) return (opcode >= 1 && opcode <= 3) ? 1 : 0; } +/* + * Helper macros for generating raw instruction encodings in inline asm. + */ +#ifdef CONFIG_CPU_MICROMIPS +#define _ASM_INSN16_IF_MM(_enc) \ + ".insn\n\t" \ + ".hword (" #_enc ")\n\t" +#define _ASM_INSN32_IF_MM(_enc) \ + ".insn\n\t" \ + ".hword ((" #_enc ") >> 16)\n\t" \ + ".hword ((" #_enc ") & 0xffff)\n\t" +#else +#define _ASM_INSN_IF_MIPS(_enc) \ + ".insn\n\t" \ + ".word (" #_enc ")\n\t" +#endif + +#ifndef _ASM_INSN16_IF_MM +#define _ASM_INSN16_IF_MM(_enc) +#endif +#ifndef _ASM_INSN32_IF_MM +#define _ASM_INSN32_IF_MM(_enc) +#endif +#ifndef _ASM_INSN_IF_MIPS +#define _ASM_INSN_IF_MIPS(_enc) +#endif + +/* + * parse_r var, r - Helper assembler macro for parsing register names. + * + * This converts the register name in $n form provided in \r to the + * corresponding register number, which is assigned to the variable \var. It is + * needed to allow explicit encoding of instructions in inline assembly where + * registers are chosen by the compiler in $n form, allowing us to avoid using + * fixed register numbers. + * + * It also allows newer instructions (not implemented by the assembler) to be + * transparently implemented using assembler macros, instead of needing separate + * cases depending on toolchain support. + * + * Simple usage example: + * __asm__ __volatile__("parse_r __rt, %0\n\t" + * ".insn\n\t" + * "# di %0\n\t" + * ".word (0x41606000 | (__rt << 16))" + * : "=r" (status); + */ + +/* Match an individual register number and assign to \var */ +#define _IFC_REG(n) \ + ".ifc \\r, $" #n "\n\t" \ + "\\var = " #n "\n\t" \ + ".endif\n\t" + +__asm__(".macro parse_r var r\n\t" + "\\var = -1\n\t" + _IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3) + _IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7) + _IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11) + _IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15) + _IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19) + _IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23) + _IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27) + _IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31) + ".iflt \\var\n\t" + ".error \"Unable to parse register name \\r\"\n\t" + ".endif\n\t" + ".endm"); + +#undef _IFC_REG + +/* + * C macros for generating assembler macros for common instruction formats. + * + * The names of the operands can be chosen by the caller, and the encoding of + * register operand \ is assigned to __ where it can be accessed from + * the ENC encodings. + */ + +/* Instructions with no operands */ +#define _ASM_MACRO_0(OP, ENC) \ + __asm__(".macro " #OP "\n\t" \ + ENC \ + ".endm") + +/* Instructions with 1 register operand & 1 immediate operand */ +#define _ASM_MACRO_1R1I(OP, R1, I2, ENC) \ + __asm__(".macro " #OP " " #R1 ", " #I2 "\n\t" \ + "parse_r __" #R1 ", \\" #R1 "\n\t" \ + ENC \ + ".endm") + +/* Instructions with 2 register operands */ +#define _ASM_MACRO_2R(OP, R1, R2, ENC) \ + __asm__(".macro " #OP " " #R1 ", " #R2 "\n\t" \ + "parse_r __" #R1 ", \\" #R1 "\n\t" \ + "parse_r __" #R2 ", \\" #R2 "\n\t" \ + ENC \ + ".endm") + +/* Instructions with 3 register operands */ +#define _ASM_MACRO_3R(OP, R1, R2, R3, ENC) \ + __asm__(".macro " #OP " " #R1 ", " #R2 ", " #R3 "\n\t" \ + "parse_r __" #R1 ", \\" #R1 "\n\t" \ + "parse_r __" #R2 ", \\" #R2 "\n\t" \ + "parse_r __" #R3 ", \\" #R3 "\n\t" \ + ENC \ + ".endm") + +/* Instructions with 2 register operands and 1 optional select operand */ +#define _ASM_MACRO_2R_1S(OP, R1, R2, SEL3, ENC) \ + __asm__(".macro " #OP " " #R1 ", " #R2 ", " #SEL3 " = 0\n\t" \ + "parse_r __" #R1 ", \\" #R1 "\n\t" \ + "parse_r __" #R2 ", \\" #R2 "\n\t" \ + ENC \ + ".endm") + /* * TLB Invalidate Flush */ @@ -856,7 +1255,9 @@ static inline void tlbinvf(void) __asm__ __volatile__( ".set push\n\t" ".set noreorder\n\t" - ".word 0x42000004\n\t" /* tlbinvf */ + "# tlbinvf\n\t" + _ASM_INSN_IF_MIPS(0x42000004) + _ASM_INSN32_IF_MM(0x0000537c) ".set pop"); } @@ -911,40 +1312,55 @@ do { \ * Macros to access the system control coprocessor */ -#define __read_32bit_c0_register(source, sel) \ +#define ___read_32bit_c0_register(source, sel, vol) \ ({ unsigned int __res; \ if (sel == 0) \ - __asm__ __volatile__( \ + __asm__ vol( \ "mfc0\t%0, " #source "\n\t" \ : "=r" (__res)); \ else \ - __asm__ __volatile__( \ + __asm__ vol( \ + ".set\tpush\n\t" \ ".set\tmips32\n\t" \ "mfc0\t%0, " #source ", " #sel "\n\t" \ - ".set\tmips0\n\t" \ + ".set\tpop\n\t" \ : "=r" (__res)); \ __res; \ }) -#define __read_64bit_c0_register(source, sel) \ +#define ___read_64bit_c0_register(source, sel, vol) \ ({ unsigned long long __res; \ if (sizeof(unsigned long) == 4) \ - __res = __read_64bit_c0_split(source, sel); \ + __res = __read_64bit_c0_split(source, sel, vol); \ else if (sel == 0) \ - __asm__ __volatile__( \ + __asm__ vol( \ + ".set\tpush\n\t" \ ".set\tmips3\n\t" \ "dmfc0\t%0, " #source "\n\t" \ - ".set\tmips0" \ + ".set\tpop" \ : "=r" (__res)); \ else \ - __asm__ __volatile__( \ + __asm__ vol( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ "dmfc0\t%0, " #source ", " #sel "\n\t" \ - ".set\tmips0" \ + ".set\tpop" \ : "=r" (__res)); \ __res; \ }) +#define __read_32bit_c0_register(source, sel) \ + ___read_32bit_c0_register(source, sel, __volatile__) + +#define __read_const_32bit_c0_register(source, sel) \ + ___read_32bit_c0_register(source, sel,) + +#define __read_64bit_c0_register(source, sel) \ + ___read_64bit_c0_register(source, sel, __volatile__) + +#define __read_const_64bit_c0_register(source, sel) \ + ___read_64bit_c0_register(source, sel,) + #define __write_32bit_c0_register(register, sel, value) \ do { \ if (sel == 0) \ @@ -953,9 +1369,10 @@ do { \ : : "Jr" ((unsigned int)(value))); \ else \ __asm__ __volatile__( \ + ".set\tpush\n\t" \ ".set\tmips32\n\t" \ "mtc0\t%z0, " #register ", " #sel "\n\t" \ - ".set\tmips0" \ + ".set\tpop" \ : : "Jr" ((unsigned int)(value))); \ } while (0) @@ -965,15 +1382,17 @@ do { \ __write_64bit_c0_split(register, sel, value); \ else if (sel == 0) \ __asm__ __volatile__( \ + ".set\tpush\n\t" \ ".set\tmips3\n\t" \ "dmtc0\t%z0, " #register "\n\t" \ - ".set\tmips0" \ + ".set\tpop" \ : : "Jr" (value)); \ else \ __asm__ __volatile__( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ "dmtc0\t%z0, " #register ", " #sel "\n\t" \ - ".set\tmips0" \ + ".set\tpop" \ : : "Jr" (value)); \ } while (0) @@ -982,6 +1401,11 @@ do { \ (unsigned long) __read_32bit_c0_register(reg, sel) : \ (unsigned long) __read_64bit_c0_register(reg, sel)) +#define __read_const_ulong_c0_register(reg, sel) \ + ((sizeof(unsigned long) == 4) ? \ + (unsigned long) __read_const_32bit_c0_register(reg, sel) : \ + (unsigned long) __read_const_64bit_c0_register(reg, sel)) + #define __write_ulong_c0_register(reg, sel, val) \ do { \ if (sizeof(unsigned long) == 4) \ @@ -1012,27 +1436,27 @@ do { \ * These versions are only needed for systems with more than 38 bits of * physical address space running the 32-bit kernel. That's none atm :-) */ -#define __read_64bit_c0_split(source, sel) \ +#define __read_64bit_c0_split(source, sel, vol) \ ({ \ unsigned long long __val; \ \ if (sel == 0) \ - __asm__ __volatile__( \ + __asm__ vol( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ - "dmfc0\t%M0, " #source "\n\t" \ - "dsll\t%L0, %M0, 32\n\t" \ - "dsra\t%M0, %M0, 32\n\t" \ - "dsra\t%L0, %L0, 32\n\t" \ - ".set\tmips0" \ + "dmfc0\t%L0, " #source "\n\t" \ + "dsra\t%M0, %L0, 32\n\t" \ + "sll\t%L0, %L0, 0\n\t" \ + ".set\tpop" \ : "=r" (__val)); \ else \ - __asm__ __volatile__( \ + __asm__ vol( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ - "dmfc0\t%M0, " #source ", " #sel "\n\t" \ - "dsll\t%L0, %M0, 32\n\t" \ - "dsra\t%M0, %M0, 32\n\t" \ - "dsra\t%L0, %L0, 32\n\t" \ - ".set\tmips0" \ + "dmfc0\t%L0, " #source ", " #sel "\n\t" \ + "dsra\t%M0, %L0, 32\n\t" \ + "sll\t%L0, %L0, 0\n\t" \ + ".set\tpop" \ : "=r" (__val)); \ \ __val; \ @@ -1040,60 +1464,77 @@ do { \ #define __write_64bit_c0_split(source, sel, val) \ do { \ - if (sel == 0) \ + unsigned long long __tmp = (val); \ + if (MIPS_ISA_REV >= 2) \ __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\t" MIPS_ISA_LEVEL "\n\t" \ + "dins\t%L0, %M0, 32, 32\n\t" \ + "dmtc0\t%L0, " #source ", " #sel "\n\t" \ + ".set\tpop" \ + : "+r" (__tmp)); \ + else if (sel == 0) \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ "dsll\t%L0, %L0, 32\n\t" \ "dsrl\t%L0, %L0, 32\n\t" \ "dsll\t%M0, %M0, 32\n\t" \ "or\t%L0, %L0, %M0\n\t" \ "dmtc0\t%L0, " #source "\n\t" \ - ".set\tmips0" \ - : : "r" (val)); \ + ".set\tpop" \ + : "+r" (__tmp)); \ else \ __asm__ __volatile__( \ + ".set\tpush\n\t" \ ".set\tmips64\n\t" \ "dsll\t%L0, %L0, 32\n\t" \ "dsrl\t%L0, %L0, 32\n\t" \ "dsll\t%M0, %M0, 32\n\t" \ "or\t%L0, %L0, %M0\n\t" \ "dmtc0\t%L0, " #source ", " #sel "\n\t" \ - ".set\tmips0" \ - : : "r" (val)); \ + ".set\tpop" \ + : "+r" (__tmp)); \ } while (0) -#define __readx_32bit_c0_register(source) \ +#ifndef TOOLCHAIN_SUPPORTS_XPA +_ASM_MACRO_2R_1S(mfhc0, rt, rs, sel, + _ASM_INSN_IF_MIPS(0x40400000 | __rt << 16 | __rs << 11 | \\sel) + _ASM_INSN32_IF_MM(0x000000f4 | __rt << 21 | __rs << 16 | \\sel << 11)); +_ASM_MACRO_2R_1S(mthc0, rt, rd, sel, + _ASM_INSN_IF_MIPS(0x40c00000 | __rt << 16 | __rd << 11 | \\sel) + _ASM_INSN32_IF_MM(0x000002f4 | __rt << 21 | __rd << 16 | \\sel << 11)); +#define _ASM_SET_XPA "" +#else /* !TOOLCHAIN_SUPPORTS_XPA */ +#define _ASM_SET_XPA ".set\txpa\n\t" +#endif + +#define __readx_32bit_c0_register(source, sel) \ ({ \ unsigned int __res; \ \ __asm__ __volatile__( \ " .set push \n" \ - " .set noat \n" \ " .set mips32r2 \n" \ - " .insn \n" \ - " # mfhc0 $1, %1 \n" \ - " .word (0x40410000 | ((%1 & 0x1f) << 11)) \n" \ - " move %0, $1 \n" \ + _ASM_SET_XPA \ + " mfhc0 %0, " #source ", %1 \n" \ " .set pop \n" \ : "=r" (__res) \ - : "i" (source)); \ + : "i" (sel)); \ __res; \ }) -#define __writex_32bit_c0_register(register, value) \ -({ \ +#define __writex_32bit_c0_register(register, sel, value) \ +do { \ __asm__ __volatile__( \ " .set push \n" \ - " .set noat \n" \ " .set mips32r2 \n" \ - " move $1, %0 \n" \ - " # mthc0 $1, %1 \n" \ - " .insn \n" \ - " .word (0x40c10000 | ((%1 & 0x1f) << 11)) \n" \ + _ASM_SET_XPA \ + " mthc0 %z0, " #register ", %1 \n" \ " .set pop \n" \ : \ - : "r" (value), "i" (register)); \ -}) + : "Jr" (value), "i" (sel)); \ +} while (0) #define read_c0_index() __read_32bit_c0_register($0, 0) #define write_c0_index(val) __write_32bit_c0_register($0, 0, val) @@ -1104,24 +1545,35 @@ do { \ #define read_c0_entrylo0() __read_ulong_c0_register($2, 0) #define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val) -#define readx_c0_entrylo0() __readx_32bit_c0_register(2) -#define writex_c0_entrylo0(val) __writex_32bit_c0_register(2, val) +#define readx_c0_entrylo0() __readx_32bit_c0_register($2, 0) +#define writex_c0_entrylo0(val) __writex_32bit_c0_register($2, 0, val) #define read_c0_entrylo1() __read_ulong_c0_register($3, 0) #define write_c0_entrylo1(val) __write_ulong_c0_register($3, 0, val) -#define readx_c0_entrylo1() __readx_32bit_c0_register(3) -#define writex_c0_entrylo1(val) __writex_32bit_c0_register(3, val) +#define readx_c0_entrylo1() __readx_32bit_c0_register($3, 0) +#define writex_c0_entrylo1(val) __writex_32bit_c0_register($3, 0, val) #define read_c0_conf() __read_32bit_c0_register($3, 0) #define write_c0_conf(val) __write_32bit_c0_register($3, 0, val) +#define read_c0_globalnumber() __read_32bit_c0_register($3, 1) + #define read_c0_context() __read_ulong_c0_register($4, 0) #define write_c0_context(val) __write_ulong_c0_register($4, 0, val) +#define read_c0_contextconfig() __read_32bit_c0_register($4, 1) +#define write_c0_contextconfig(val) __write_32bit_c0_register($4, 1, val) + #define read_c0_userlocal() __read_ulong_c0_register($4, 2) #define write_c0_userlocal(val) __write_ulong_c0_register($4, 2, val) +#define read_c0_xcontextconfig() __read_ulong_c0_register($4, 3) +#define write_c0_xcontextconfig(val) __write_ulong_c0_register($4, 3, val) + +#define read_c0_memorymapid() __read_32bit_c0_register($4, 5) +#define write_c0_memorymapid(val) __write_32bit_c0_register($4, 5, val) + #define read_c0_pagemask() __read_32bit_c0_register($5, 0) #define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val) @@ -1139,6 +1591,9 @@ do { \ #define read_c0_badvaddr() __read_ulong_c0_register($8, 0) #define write_c0_badvaddr(val) __write_ulong_c0_register($8, 0, val) +#define read_c0_badinstr() __read_32bit_c0_register($8, 1) +#define read_c0_badinstrp() __read_32bit_c0_register($8, 2) + #define read_c0_count() __read_32bit_c0_register($9, 0) #define write_c0_count(val) __write_32bit_c0_register($9, 0, val) @@ -1151,9 +1606,21 @@ do { \ #define read_c0_entryhi() __read_ulong_c0_register($10, 0) #define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val) +#define read_c0_guestctl1() __read_32bit_c0_register($10, 4) +#define write_c0_guestctl1(val) __write_32bit_c0_register($10, 4, val) + +#define read_c0_guestctl2() __read_32bit_c0_register($10, 5) +#define write_c0_guestctl2(val) __write_32bit_c0_register($10, 5, val) + +#define read_c0_guestctl3() __read_32bit_c0_register($10, 6) +#define write_c0_guestctl3(val) __write_32bit_c0_register($10, 6, val) + #define read_c0_compare() __read_32bit_c0_register($11, 0) #define write_c0_compare(val) __write_32bit_c0_register($11, 0, val) +#define read_c0_guestctl0ext() __read_32bit_c0_register($11, 4) +#define write_c0_guestctl0ext(val) __write_32bit_c0_register($11, 4, val) + #define read_c0_compare2() __read_32bit_c0_register($11, 6) /* pnx8550 */ #define write_c0_compare2(val) __write_32bit_c0_register($11, 6, val) @@ -1164,13 +1631,19 @@ do { \ #define write_c0_status(val) __write_32bit_c0_register($12, 0, val) +#define read_c0_guestctl0() __read_32bit_c0_register($12, 6) +#define write_c0_guestctl0(val) __write_32bit_c0_register($12, 6, val) + +#define read_c0_gtoffset() __read_32bit_c0_register($12, 7) +#define write_c0_gtoffset(val) __write_32bit_c0_register($12, 7, val) + #define read_c0_cause() __read_32bit_c0_register($13, 0) #define write_c0_cause(val) __write_32bit_c0_register($13, 0, val) #define read_c0_epc() __read_ulong_c0_register($14, 0) #define write_c0_epc(val) __write_ulong_c0_register($14, 0, val) -#define read_c0_prid() __read_32bit_c0_register($15, 0) +#define read_c0_prid() __read_const_32bit_c0_register($15, 0) #define read_c0_cmgcrbase() __read_ulong_c0_register($15, 3) @@ -1349,6 +1822,9 @@ do { \ #define read_c0_ebase() __read_32bit_c0_register($15, 1) #define write_c0_ebase(val) __write_32bit_c0_register($15, 1, val) +#define read_c0_ebase_64() __read_64bit_c0_register($15, 1) +#define write_c0_ebase_64(val) __write_64bit_c0_register($15, 1, val) + #define read_c0_cdmmbase() __read_ulong_c0_register($15, 2) #define write_c0_cdmmbase(val) __write_ulong_c0_register($15, 2, val) @@ -1375,6 +1851,12 @@ do { \ #define read_c0_pwctl() __read_32bit_c0_register($6, 6) #define write_c0_pwctl(val) __write_32bit_c0_register($6, 6, val) +#define read_c0_pgd() __read_64bit_c0_register($9, 7) +#define write_c0_pgd(val) __write_64bit_c0_register($9, 7, val) + +#define read_c0_kpgd() __read_64bit_c0_register($31, 7) +#define write_c0_kpgd(val) __write_64bit_c0_register($31, 7, val) + /* Cavium OCTEON (cnMIPS) */ #define read_c0_cvmcount() __read_ulong_c0_register($9, 6) #define write_c0_cvmcount(val) __write_ulong_c0_register($9, 6, val) @@ -1384,6 +1866,13 @@ do { \ #define read_c0_cvmmemctl() __read_64bit_c0_register($11, 7) #define write_c0_cvmmemctl(val) __write_64bit_c0_register($11, 7, val) + +#define read_c0_cvmmemctl2() __read_64bit_c0_register($16, 6) +#define write_c0_cvmmemctl2(val) __write_64bit_c0_register($16, 6, val) + +#define read_c0_cvmvmconfig() __read_64bit_c0_register($16, 7) +#define write_c0_cvmvmconfig(val) __write_64bit_c0_register($16, 7, val) + /* * The cacheerr registers are not standardized. On OCTEON, they are * 64 bits wide. @@ -1439,6 +1928,306 @@ do { \ #define read_c0_brcm_sleepcount() __read_32bit_c0_register($22, 7) #define write_c0_brcm_sleepcount(val) __write_32bit_c0_register($22, 7, val) +/* Ingenic page ctrl register */ +#define write_c0_page_ctrl(val) __write_32bit_c0_register($5, 4, val) + +/* + * Macros to access the guest system control coprocessor + */ + +#ifndef TOOLCHAIN_SUPPORTS_VIRT +_ASM_MACRO_2R_1S(mfgc0, rt, rs, sel, + _ASM_INSN_IF_MIPS(0x40600000 | __rt << 16 | __rs << 11 | \\sel) + _ASM_INSN32_IF_MM(0x000004fc | __rt << 21 | __rs << 16 | \\sel << 11)); +_ASM_MACRO_2R_1S(dmfgc0, rt, rs, sel, + _ASM_INSN_IF_MIPS(0x40600100 | __rt << 16 | __rs << 11 | \\sel) + _ASM_INSN32_IF_MM(0x580004fc | __rt << 21 | __rs << 16 | \\sel << 11)); +_ASM_MACRO_2R_1S(mtgc0, rt, rd, sel, + _ASM_INSN_IF_MIPS(0x40600200 | __rt << 16 | __rd << 11 | \\sel) + _ASM_INSN32_IF_MM(0x000006fc | __rt << 21 | __rd << 16 | \\sel << 11)); +_ASM_MACRO_2R_1S(dmtgc0, rt, rd, sel, + _ASM_INSN_IF_MIPS(0x40600300 | __rt << 16 | __rd << 11 | \\sel) + _ASM_INSN32_IF_MM(0x580006fc | __rt << 21 | __rd << 16 | \\sel << 11)); +_ASM_MACRO_0(tlbgp, _ASM_INSN_IF_MIPS(0x42000010) + _ASM_INSN32_IF_MM(0x0000017c)); +_ASM_MACRO_0(tlbgr, _ASM_INSN_IF_MIPS(0x42000009) + _ASM_INSN32_IF_MM(0x0000117c)); +_ASM_MACRO_0(tlbgwi, _ASM_INSN_IF_MIPS(0x4200000a) + _ASM_INSN32_IF_MM(0x0000217c)); +_ASM_MACRO_0(tlbgwr, _ASM_INSN_IF_MIPS(0x4200000e) + _ASM_INSN32_IF_MM(0x0000317c)); +_ASM_MACRO_0(tlbginvf, _ASM_INSN_IF_MIPS(0x4200000c) + _ASM_INSN32_IF_MM(0x0000517c)); +#define _ASM_SET_VIRT "" +#else /* !TOOLCHAIN_SUPPORTS_VIRT */ +#define _ASM_SET_VIRT ".set\tvirt\n\t" +#endif + +#define __read_32bit_gc0_register(source, sel) \ +({ int __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + _ASM_SET_VIRT \ + "mfgc0\t%0, " #source ", %1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (sel)); \ + __res; \ +}) + +#define __read_64bit_gc0_register(source, sel) \ +({ unsigned long long __res; \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + _ASM_SET_VIRT \ + "dmfgc0\t%0, " #source ", %1\n\t" \ + ".set\tpop" \ + : "=r" (__res) \ + : "i" (sel)); \ + __res; \ +}) + +#define __write_32bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips32r2\n\t" \ + _ASM_SET_VIRT \ + "mtgc0\t%z0, " #register ", %1\n\t" \ + ".set\tpop" \ + : : "Jr" ((unsigned int)(value)), \ + "i" (sel)); \ +} while (0) + +#define __write_64bit_gc0_register(register, sel, value) \ +do { \ + __asm__ __volatile__( \ + ".set\tpush\n\t" \ + ".set\tmips64r2\n\t" \ + _ASM_SET_VIRT \ + "dmtgc0\t%z0, " #register ", %1\n\t" \ + ".set\tpop" \ + : : "Jr" (value), \ + "i" (sel)); \ +} while (0) + +#define __read_ulong_gc0_register(reg, sel) \ + ((sizeof(unsigned long) == 4) ? \ + (unsigned long) __read_32bit_gc0_register(reg, sel) : \ + (unsigned long) __read_64bit_gc0_register(reg, sel)) + +#define __write_ulong_gc0_register(reg, sel, val) \ +do { \ + if (sizeof(unsigned long) == 4) \ + __write_32bit_gc0_register(reg, sel, val); \ + else \ + __write_64bit_gc0_register(reg, sel, val); \ +} while (0) + +#define read_gc0_index() __read_32bit_gc0_register($0, 0) +#define write_gc0_index(val) __write_32bit_gc0_register($0, 0, val) + +#define read_gc0_entrylo0() __read_ulong_gc0_register($2, 0) +#define write_gc0_entrylo0(val) __write_ulong_gc0_register($2, 0, val) + +#define read_gc0_entrylo1() __read_ulong_gc0_register($3, 0) +#define write_gc0_entrylo1(val) __write_ulong_gc0_register($3, 0, val) + +#define read_gc0_context() __read_ulong_gc0_register($4, 0) +#define write_gc0_context(val) __write_ulong_gc0_register($4, 0, val) + +#define read_gc0_contextconfig() __read_32bit_gc0_register($4, 1) +#define write_gc0_contextconfig(val) __write_32bit_gc0_register($4, 1, val) + +#define read_gc0_userlocal() __read_ulong_gc0_register($4, 2) +#define write_gc0_userlocal(val) __write_ulong_gc0_register($4, 2, val) + +#define read_gc0_xcontextconfig() __read_ulong_gc0_register($4, 3) +#define write_gc0_xcontextconfig(val) __write_ulong_gc0_register($4, 3, val) + +#define read_gc0_pagemask() __read_32bit_gc0_register($5, 0) +#define write_gc0_pagemask(val) __write_32bit_gc0_register($5, 0, val) + +#define read_gc0_pagegrain() __read_32bit_gc0_register($5, 1) +#define write_gc0_pagegrain(val) __write_32bit_gc0_register($5, 1, val) + +#define read_gc0_segctl0() __read_ulong_gc0_register($5, 2) +#define write_gc0_segctl0(val) __write_ulong_gc0_register($5, 2, val) + +#define read_gc0_segctl1() __read_ulong_gc0_register($5, 3) +#define write_gc0_segctl1(val) __write_ulong_gc0_register($5, 3, val) + +#define read_gc0_segctl2() __read_ulong_gc0_register($5, 4) +#define write_gc0_segctl2(val) __write_ulong_gc0_register($5, 4, val) + +#define read_gc0_pwbase() __read_ulong_gc0_register($5, 5) +#define write_gc0_pwbase(val) __write_ulong_gc0_register($5, 5, val) + +#define read_gc0_pwfield() __read_ulong_gc0_register($5, 6) +#define write_gc0_pwfield(val) __write_ulong_gc0_register($5, 6, val) + +#define read_gc0_pwsize() __read_ulong_gc0_register($5, 7) +#define write_gc0_pwsize(val) __write_ulong_gc0_register($5, 7, val) + +#define read_gc0_wired() __read_32bit_gc0_register($6, 0) +#define write_gc0_wired(val) __write_32bit_gc0_register($6, 0, val) + +#define read_gc0_pwctl() __read_32bit_gc0_register($6, 6) +#define write_gc0_pwctl(val) __write_32bit_gc0_register($6, 6, val) + +#define read_gc0_hwrena() __read_32bit_gc0_register($7, 0) +#define write_gc0_hwrena(val) __write_32bit_gc0_register($7, 0, val) + +#define read_gc0_badvaddr() __read_ulong_gc0_register($8, 0) +#define write_gc0_badvaddr(val) __write_ulong_gc0_register($8, 0, val) + +#define read_gc0_badinstr() __read_32bit_gc0_register($8, 1) +#define write_gc0_badinstr(val) __write_32bit_gc0_register($8, 1, val) + +#define read_gc0_badinstrp() __read_32bit_gc0_register($8, 2) +#define write_gc0_badinstrp(val) __write_32bit_gc0_register($8, 2, val) + +#define read_gc0_count() __read_32bit_gc0_register($9, 0) + +#define read_gc0_entryhi() __read_ulong_gc0_register($10, 0) +#define write_gc0_entryhi(val) __write_ulong_gc0_register($10, 0, val) + +#define read_gc0_compare() __read_32bit_gc0_register($11, 0) +#define write_gc0_compare(val) __write_32bit_gc0_register($11, 0, val) + +#define read_gc0_status() __read_32bit_gc0_register($12, 0) +#define write_gc0_status(val) __write_32bit_gc0_register($12, 0, val) + +#define read_gc0_intctl() __read_32bit_gc0_register($12, 1) +#define write_gc0_intctl(val) __write_32bit_gc0_register($12, 1, val) + +#define read_gc0_cause() __read_32bit_gc0_register($13, 0) +#define write_gc0_cause(val) __write_32bit_gc0_register($13, 0, val) + +#define read_gc0_epc() __read_ulong_gc0_register($14, 0) +#define write_gc0_epc(val) __write_ulong_gc0_register($14, 0, val) + +#define read_gc0_prid() __read_32bit_gc0_register($15, 0) + +#define read_gc0_ebase() __read_32bit_gc0_register($15, 1) +#define write_gc0_ebase(val) __write_32bit_gc0_register($15, 1, val) + +#define read_gc0_ebase_64() __read_64bit_gc0_register($15, 1) +#define write_gc0_ebase_64(val) __write_64bit_gc0_register($15, 1, val) + +#define read_gc0_config() __read_32bit_gc0_register($16, 0) +#define read_gc0_config1() __read_32bit_gc0_register($16, 1) +#define read_gc0_config2() __read_32bit_gc0_register($16, 2) +#define read_gc0_config3() __read_32bit_gc0_register($16, 3) +#define read_gc0_config4() __read_32bit_gc0_register($16, 4) +#define read_gc0_config5() __read_32bit_gc0_register($16, 5) +#define read_gc0_config6() __read_32bit_gc0_register($16, 6) +#define read_gc0_config7() __read_32bit_gc0_register($16, 7) +#define write_gc0_config(val) __write_32bit_gc0_register($16, 0, val) +#define write_gc0_config1(val) __write_32bit_gc0_register($16, 1, val) +#define write_gc0_config2(val) __write_32bit_gc0_register($16, 2, val) +#define write_gc0_config3(val) __write_32bit_gc0_register($16, 3, val) +#define write_gc0_config4(val) __write_32bit_gc0_register($16, 4, val) +#define write_gc0_config5(val) __write_32bit_gc0_register($16, 5, val) +#define write_gc0_config6(val) __write_32bit_gc0_register($16, 6, val) +#define write_gc0_config7(val) __write_32bit_gc0_register($16, 7, val) + +#define read_gc0_lladdr() __read_ulong_gc0_register($17, 0) +#define write_gc0_lladdr(val) __write_ulong_gc0_register($17, 0, val) + +#define read_gc0_watchlo0() __read_ulong_gc0_register($18, 0) +#define read_gc0_watchlo1() __read_ulong_gc0_register($18, 1) +#define read_gc0_watchlo2() __read_ulong_gc0_register($18, 2) +#define read_gc0_watchlo3() __read_ulong_gc0_register($18, 3) +#define read_gc0_watchlo4() __read_ulong_gc0_register($18, 4) +#define read_gc0_watchlo5() __read_ulong_gc0_register($18, 5) +#define read_gc0_watchlo6() __read_ulong_gc0_register($18, 6) +#define read_gc0_watchlo7() __read_ulong_gc0_register($18, 7) +#define write_gc0_watchlo0(val) __write_ulong_gc0_register($18, 0, val) +#define write_gc0_watchlo1(val) __write_ulong_gc0_register($18, 1, val) +#define write_gc0_watchlo2(val) __write_ulong_gc0_register($18, 2, val) +#define write_gc0_watchlo3(val) __write_ulong_gc0_register($18, 3, val) +#define write_gc0_watchlo4(val) __write_ulong_gc0_register($18, 4, val) +#define write_gc0_watchlo5(val) __write_ulong_gc0_register($18, 5, val) +#define write_gc0_watchlo6(val) __write_ulong_gc0_register($18, 6, val) +#define write_gc0_watchlo7(val) __write_ulong_gc0_register($18, 7, val) + +#define read_gc0_watchhi0() __read_32bit_gc0_register($19, 0) +#define read_gc0_watchhi1() __read_32bit_gc0_register($19, 1) +#define read_gc0_watchhi2() __read_32bit_gc0_register($19, 2) +#define read_gc0_watchhi3() __read_32bit_gc0_register($19, 3) +#define read_gc0_watchhi4() __read_32bit_gc0_register($19, 4) +#define read_gc0_watchhi5() __read_32bit_gc0_register($19, 5) +#define read_gc0_watchhi6() __read_32bit_gc0_register($19, 6) +#define read_gc0_watchhi7() __read_32bit_gc0_register($19, 7) +#define write_gc0_watchhi0(val) __write_32bit_gc0_register($19, 0, val) +#define write_gc0_watchhi1(val) __write_32bit_gc0_register($19, 1, val) +#define write_gc0_watchhi2(val) __write_32bit_gc0_register($19, 2, val) +#define write_gc0_watchhi3(val) __write_32bit_gc0_register($19, 3, val) +#define write_gc0_watchhi4(val) __write_32bit_gc0_register($19, 4, val) +#define write_gc0_watchhi5(val) __write_32bit_gc0_register($19, 5, val) +#define write_gc0_watchhi6(val) __write_32bit_gc0_register($19, 6, val) +#define write_gc0_watchhi7(val) __write_32bit_gc0_register($19, 7, val) + +#define read_gc0_xcontext() __read_ulong_gc0_register($20, 0) +#define write_gc0_xcontext(val) __write_ulong_gc0_register($20, 0, val) + +#define read_gc0_perfctrl0() __read_32bit_gc0_register($25, 0) +#define write_gc0_perfctrl0(val) __write_32bit_gc0_register($25, 0, val) +#define read_gc0_perfcntr0() __read_32bit_gc0_register($25, 1) +#define write_gc0_perfcntr0(val) __write_32bit_gc0_register($25, 1, val) +#define read_gc0_perfcntr0_64() __read_64bit_gc0_register($25, 1) +#define write_gc0_perfcntr0_64(val) __write_64bit_gc0_register($25, 1, val) +#define read_gc0_perfctrl1() __read_32bit_gc0_register($25, 2) +#define write_gc0_perfctrl1(val) __write_32bit_gc0_register($25, 2, val) +#define read_gc0_perfcntr1() __read_32bit_gc0_register($25, 3) +#define write_gc0_perfcntr1(val) __write_32bit_gc0_register($25, 3, val) +#define read_gc0_perfcntr1_64() __read_64bit_gc0_register($25, 3) +#define write_gc0_perfcntr1_64(val) __write_64bit_gc0_register($25, 3, val) +#define read_gc0_perfctrl2() __read_32bit_gc0_register($25, 4) +#define write_gc0_perfctrl2(val) __write_32bit_gc0_register($25, 4, val) +#define read_gc0_perfcntr2() __read_32bit_gc0_register($25, 5) +#define write_gc0_perfcntr2(val) __write_32bit_gc0_register($25, 5, val) +#define read_gc0_perfcntr2_64() __read_64bit_gc0_register($25, 5) +#define write_gc0_perfcntr2_64(val) __write_64bit_gc0_register($25, 5, val) +#define read_gc0_perfctrl3() __read_32bit_gc0_register($25, 6) +#define write_gc0_perfctrl3(val) __write_32bit_gc0_register($25, 6, val) +#define read_gc0_perfcntr3() __read_32bit_gc0_register($25, 7) +#define write_gc0_perfcntr3(val) __write_32bit_gc0_register($25, 7, val) +#define read_gc0_perfcntr3_64() __read_64bit_gc0_register($25, 7) +#define write_gc0_perfcntr3_64(val) __write_64bit_gc0_register($25, 7, val) + +#define read_gc0_errorepc() __read_ulong_gc0_register($30, 0) +#define write_gc0_errorepc(val) __write_ulong_gc0_register($30, 0, val) + +#define read_gc0_kscratch1() __read_ulong_gc0_register($31, 2) +#define read_gc0_kscratch2() __read_ulong_gc0_register($31, 3) +#define read_gc0_kscratch3() __read_ulong_gc0_register($31, 4) +#define read_gc0_kscratch4() __read_ulong_gc0_register($31, 5) +#define read_gc0_kscratch5() __read_ulong_gc0_register($31, 6) +#define read_gc0_kscratch6() __read_ulong_gc0_register($31, 7) +#define write_gc0_kscratch1(val) __write_ulong_gc0_register($31, 2, val) +#define write_gc0_kscratch2(val) __write_ulong_gc0_register($31, 3, val) +#define write_gc0_kscratch3(val) __write_ulong_gc0_register($31, 4, val) +#define write_gc0_kscratch4(val) __write_ulong_gc0_register($31, 5, val) +#define write_gc0_kscratch5(val) __write_ulong_gc0_register($31, 6, val) +#define write_gc0_kscratch6(val) __write_ulong_gc0_register($31, 7, val) + +/* Cavium OCTEON (cnMIPS) */ +#define read_gc0_cvmcount() __read_ulong_gc0_register($9, 6) +#define write_gc0_cvmcount(val) __write_ulong_gc0_register($9, 6, val) + +#define read_gc0_cvmctl() __read_64bit_gc0_register($9, 7) +#define write_gc0_cvmctl(val) __write_64bit_gc0_register($9, 7, val) + +#define read_gc0_cvmmemctl() __read_64bit_gc0_register($11, 7) +#define write_gc0_cvmmemctl(val) __write_64bit_gc0_register($11, 7, val) + +#define read_gc0_cvmmemctl2() __read_64bit_gc0_register($16, 6) +#define write_gc0_cvmmemctl2(val) __write_64bit_gc0_register($16, 6, val) + /* * Macros to access the floating point coprocessor control registers */ @@ -1460,7 +2249,7 @@ do { \ }) #define _write_32bit_cp1_register(dest, val, gas_hardfloat) \ -({ \ +do { \ __asm__ __volatile__( \ " .set push \n" \ " .set reorder \n" \ @@ -1468,7 +2257,7 @@ do { \ " ctc1 %0,"STR(dest)" \n" \ " .set pop \n" \ : : "r" (val)); \ -}) +} while (0) #ifdef GAS_HAS_SET_HARDFLOAT #define read_32bit_cp1_register(source) \ @@ -1482,13 +2271,14 @@ do { \ _write_32bit_cp1_register(dest, val, ) #endif -#ifdef HAVE_AS_DSP +#ifdef TOOLCHAIN_SUPPORTS_DSP #define rddsp(mask) \ ({ \ unsigned int __dspctl; \ \ __asm__ __volatile__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " rddsp %0, %x1 \n" \ " .set pop \n" \ @@ -1498,25 +2288,27 @@ do { \ }) #define wrdsp(val, mask) \ -({ \ +do { \ __asm__ __volatile__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " wrdsp %0, %x1 \n" \ " .set pop \n" \ : \ : "r" (val), "i" (mask)); \ -}) +} while (0) #define mflo0() \ ({ \ long mflo0; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac0 \n" \ - " .set pop \n" \ - : "=r" (mflo0)); \ + " .set pop \n" \ + : "=r" (mflo0)); \ mflo0; \ }) @@ -1525,10 +2317,11 @@ do { \ long mflo1; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac1 \n" \ - " .set pop \n" \ - : "=r" (mflo1)); \ + " .set pop \n" \ + : "=r" (mflo1)); \ mflo1; \ }) @@ -1537,10 +2330,11 @@ do { \ long mflo2; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac2 \n" \ - " .set pop \n" \ - : "=r" (mflo2)); \ + " .set pop \n" \ + : "=r" (mflo2)); \ mflo2; \ }) @@ -1549,10 +2343,11 @@ do { \ long mflo3; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mflo %0, $ac3 \n" \ - " .set pop \n" \ - : "=r" (mflo3)); \ + " .set pop \n" \ + : "=r" (mflo3)); \ mflo3; \ }) @@ -1561,10 +2356,11 @@ do { \ long mfhi0; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac0 \n" \ - " .set pop \n" \ - : "=r" (mfhi0)); \ + " .set pop \n" \ + : "=r" (mfhi0)); \ mfhi0; \ }) @@ -1573,10 +2369,11 @@ do { \ long mfhi1; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac1 \n" \ - " .set pop \n" \ - : "=r" (mfhi1)); \ + " .set pop \n" \ + : "=r" (mfhi1)); \ mfhi1; \ }) @@ -1585,10 +2382,11 @@ do { \ long mfhi2; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac2 \n" \ - " .set pop \n" \ - : "=r" (mfhi2)); \ + " .set pop \n" \ + : "=r" (mfhi2)); \ mfhi2; \ }) @@ -1597,10 +2395,11 @@ do { \ long mfhi3; \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mfhi %0, $ac3 \n" \ - " .set pop \n" \ - : "=r" (mfhi3)); \ + " .set pop \n" \ + : "=r" (mfhi3)); \ mfhi3; \ }) @@ -1609,6 +2408,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac0 \n" \ " .set pop \n" \ @@ -1620,6 +2420,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac1 \n" \ " .set pop \n" \ @@ -1631,6 +2432,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac2 \n" \ " .set pop \n" \ @@ -1642,6 +2444,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mtlo %0, $ac3 \n" \ " .set pop \n" \ @@ -1653,6 +2456,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac0 \n" \ " .set pop \n" \ @@ -1664,6 +2468,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac1 \n" \ " .set pop \n" \ @@ -1675,6 +2480,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac2 \n" \ " .set pop \n" \ @@ -1686,6 +2492,7 @@ do { \ ({ \ __asm__( \ " .set push \n" \ + " .set " MIPS_ISA_LEVEL " \n" \ " .set dsp \n" \ " mthi %0, $ac3 \n" \ " .set pop \n" \ @@ -1695,7 +2502,6 @@ do { \ #else -#ifdef CONFIG_CPU_MICROMIPS #define rddsp(mask) \ ({ \ unsigned int __res; \ @@ -1704,8 +2510,8 @@ do { \ " .set push \n" \ " .set noat \n" \ " # rddsp $1, %x1 \n" \ - " .hword ((0x0020067c | (%x1 << 14)) >> 16) \n" \ - " .hword ((0x0020067c | (%x1 << 14)) & 0xffff) \n" \ + _ASM_INSN_IF_MIPS(0x7c000cb8 | (%x1 << 16)) \ + _ASM_INSN32_IF_MM(0x0020067c | (%x1 << 14)) \ " move %0, $1 \n" \ " .set pop \n" \ : "=r" (__res) \ @@ -1714,103 +2520,18 @@ do { \ }) #define wrdsp(val, mask) \ -({ \ +do { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ " move $1, %0 \n" \ " # wrdsp $1, %x1 \n" \ - " .hword ((0x0020167c | (%x1 << 14)) >> 16) \n" \ - " .hword ((0x0020167c | (%x1 << 14)) & 0xffff) \n" \ + _ASM_INSN_IF_MIPS(0x7c2004f8 | (%x1 << 11)) \ + _ASM_INSN32_IF_MM(0x0020167c | (%x1 << 14)) \ " .set pop \n" \ : \ : "r" (val), "i" (mask)); \ -}) - -#define _umips_dsp_mfxxx(ins) \ -({ \ - unsigned long __treg; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " .hword 0x0001 \n" \ - " .hword %x1 \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__treg) \ - : "i" (ins)); \ - __treg; \ -}) - -#define _umips_dsp_mtxxx(val, ins) \ -({ \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " .hword 0x0001 \n" \ - " .hword %x1 \n" \ - " .set pop \n" \ - : \ - : "r" (val), "i" (ins)); \ -}) - -#define _umips_dsp_mflo(reg) _umips_dsp_mfxxx((reg << 14) | 0x107c) -#define _umips_dsp_mfhi(reg) _umips_dsp_mfxxx((reg << 14) | 0x007c) - -#define _umips_dsp_mtlo(val, reg) _umips_dsp_mtxxx(val, ((reg << 14) | 0x307c)) -#define _umips_dsp_mthi(val, reg) _umips_dsp_mtxxx(val, ((reg << 14) | 0x207c)) - -#define mflo0() _umips_dsp_mflo(0) -#define mflo1() _umips_dsp_mflo(1) -#define mflo2() _umips_dsp_mflo(2) -#define mflo3() _umips_dsp_mflo(3) - -#define mfhi0() _umips_dsp_mfhi(0) -#define mfhi1() _umips_dsp_mfhi(1) -#define mfhi2() _umips_dsp_mfhi(2) -#define mfhi3() _umips_dsp_mfhi(3) - -#define mtlo0(x) _umips_dsp_mtlo(x, 0) -#define mtlo1(x) _umips_dsp_mtlo(x, 1) -#define mtlo2(x) _umips_dsp_mtlo(x, 2) -#define mtlo3(x) _umips_dsp_mtlo(x, 3) - -#define mthi0(x) _umips_dsp_mthi(x, 0) -#define mthi1(x) _umips_dsp_mthi(x, 1) -#define mthi2(x) _umips_dsp_mthi(x, 2) -#define mthi3(x) _umips_dsp_mthi(x, 3) - -#else /* !CONFIG_CPU_MICROMIPS */ -#define rddsp(mask) \ -({ \ - unsigned int __res; \ - \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " # rddsp $1, %x1 \n" \ - " .word 0x7c000cb8 | (%x1 << 16) \n" \ - " move %0, $1 \n" \ - " .set pop \n" \ - : "=r" (__res) \ - : "i" (mask)); \ - __res; \ -}) - -#define wrdsp(val, mask) \ -({ \ - __asm__ __volatile__( \ - " .set push \n" \ - " .set noat \n" \ - " move $1, %0 \n" \ - " # wrdsp $1, %x1 \n" \ - " .word 0x7c2004f8 | (%x1 << 11) \n" \ - " .set pop \n" \ - : \ - : "r" (val), "i" (mask)); \ -}) +} while (0) #define _dsp_mfxxx(ins) \ ({ \ @@ -1819,7 +2540,8 @@ do { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ - " .word (0x00000810 | %1) \n" \ + _ASM_INSN_IF_MIPS(0x00000810 | %X1) \ + _ASM_INSN32_IF_MM(0x0001007c | %x1) \ " move %0, $1 \n" \ " .set pop \n" \ : "=r" (__treg) \ @@ -1828,16 +2550,27 @@ do { \ }) #define _dsp_mtxxx(val, ins) \ -({ \ +do { \ __asm__ __volatile__( \ " .set push \n" \ " .set noat \n" \ " move $1, %0 \n" \ - " .word (0x00200011 | %1) \n" \ + _ASM_INSN_IF_MIPS(0x00200011 | %X1) \ + _ASM_INSN32_IF_MM(0x0001207c | %x1) \ " .set pop \n" \ : \ : "r" (val), "i" (ins)); \ -}) +} while (0) + +#ifdef CONFIG_CPU_MICROMIPS + +#define _dsp_mflo(reg) _dsp_mfxxx((reg << 14) | 0x1000) +#define _dsp_mfhi(reg) _dsp_mfxxx((reg << 14) | 0x0000) + +#define _dsp_mtlo(val, reg) _dsp_mtxxx(val, ((reg << 14) | 0x1000)) +#define _dsp_mthi(val, reg) _dsp_mtxxx(val, ((reg << 14) | 0x0000)) + +#else /* !CONFIG_CPU_MICROMIPS */ #define _dsp_mflo(reg) _dsp_mfxxx((reg << 21) | 0x0002) #define _dsp_mfhi(reg) _dsp_mfxxx((reg << 21) | 0x0000) @@ -1845,6 +2578,8 @@ do { \ #define _dsp_mtlo(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0002)) #define _dsp_mthi(val, reg) _dsp_mtxxx(val, ((reg << 11) | 0x0000)) +#endif /* CONFIG_CPU_MICROMIPS */ + #define mflo0() _dsp_mflo(0) #define mflo1() _dsp_mflo(1) #define mflo2() _dsp_mflo(2) @@ -1865,7 +2600,6 @@ do { \ #define mthi2(x) _dsp_mthi(x, 2) #define mthi3(x) _dsp_mthi(x, 3) -#endif /* CONFIG_CPU_MICROMIPS */ #endif /* @@ -1935,54 +2669,123 @@ static inline void tlb_write_random(void) } /* - * Manipulate bits in a c0 register. + * Guest TLB operations. + * + * It is responsibility of the caller to take care of any TLB hazards. */ -#define __BUILD_SET_C0(name) \ +static inline void guest_tlb_probe(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + _ASM_SET_VIRT + "tlbgp\n\t" + ".set pop"); +} + +static inline void guest_tlb_read(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + _ASM_SET_VIRT + "tlbgr\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_indexed(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + _ASM_SET_VIRT + "tlbgwi\n\t" + ".set pop"); +} + +static inline void guest_tlb_write_random(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + _ASM_SET_VIRT + "tlbgwr\n\t" + ".set pop"); +} + +/* + * Guest TLB Invalidate Flush + */ +static inline void guest_tlbinvf(void) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + _ASM_SET_VIRT + "tlbginvf\n\t" + ".set pop"); +} + +/* + * Manipulate bits in a register. + */ +#define __BUILD_SET_COMMON(name) \ static inline unsigned int \ -set_c0_##name(unsigned int set) \ +set_##name(unsigned int set) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res | set; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -clear_c0_##name(unsigned int clear) \ +clear_##name(unsigned int clear) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~clear; \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } \ \ static inline unsigned int \ -change_c0_##name(unsigned int change, unsigned int val) \ +change_##name(unsigned int change, unsigned int val) \ { \ unsigned int res, new; \ \ - res = read_c0_##name(); \ + res = read_##name(); \ new = res & ~change; \ new |= (val & change); \ - write_c0_##name(new); \ + write_##name(new); \ \ return res; \ } +/* + * Manipulate bits in a c0 register. + */ +#define __BUILD_SET_C0(name) __BUILD_SET_COMMON(c0_##name) + __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) +__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) __BUILD_SET_C0(pagegrain) +__BUILD_SET_C0(guestctl0) +__BUILD_SET_C0(guestctl0ext) +__BUILD_SET_C0(guestctl1) +__BUILD_SET_C0(guestctl2) +__BUILD_SET_C0(guestctl3) __BUILD_SET_C0(brcm_config_0) __BUILD_SET_C0(brcm_bus_pll) __BUILD_SET_C0(brcm_reset) @@ -1991,13 +2794,24 @@ __BUILD_SET_C0(brcm_cmt_ctrl) __BUILD_SET_C0(brcm_config) __BUILD_SET_C0(brcm_mode) +/* + * Manipulate bits in a guest c0 register. + */ +#define __BUILD_SET_GC0(name) __BUILD_SET_COMMON(gc0_##name) + +__BUILD_SET_GC0(wired) +__BUILD_SET_GC0(status) +__BUILD_SET_GC0(cause) +__BUILD_SET_GC0(ebase) +__BUILD_SET_GC0(config1) + /* * Return low 10 bits of ebase. * Note that under KVM (MIPSVZ) this returns vcpu id. */ static inline unsigned int get_ebase_cpunum(void) { - return read_c0_ebase() & 0x3ff; + return read_c0_ebase() & MIPS_EBASE_CPUNUM; } static inline void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c index 6ff9d20bd6..df8b63f383 100644 --- a/arch/mips/lib/traps.c +++ b/arch/mips/lib/traps.c @@ -110,7 +110,7 @@ void trap_init(ulong reloc_addr) /* Set WG bit on Octeon to enable writing to bits 63:30 */ if (IS_ENABLED(CONFIG_ARCH_OCTEON)) - ebase |= EBASE_WG; + ebase |= MIPS_EBASE_WG; write_c0_ebase(ebase); clear_c0_status(ST0_BEV); From de34a61642eda0b64b34dd4d9eeda57eb01f76bc Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:33:16 +0200 Subject: [PATCH 15/20] mips: Add CONFIG_MIPS_MACH_EARLY_INIT for very early mach init code This patch adds the optional call to mips_mach_early_init() to start.S at a very early stage. Its disabled per default. It can be used for very early machine / platform specific init code. Its called very early and at this stage the PC is allowed to differ from the linking address (CONFIG_TEXT_BASE) as no absolute jump has been performed until this call. It will be used by thje Octeon platform. Signed-off-by: Stefan Roese Reviewed-by: Daniel Schwierzeck --- arch/mips/Kconfig | 9 +++++++++ arch/mips/cpu/start.S | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index eb00ee71bc..652e6a993e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -270,6 +270,15 @@ config MIPS_CACHE_INDEX_BASE Normally this is CKSEG0. If the MIPS system needs to move this block to some SRAM or ScratchPad RAM, adapt this option accordingly. +config MIPS_MACH_EARLY_INIT + bool "Enable mach specific very early init code" + help + Use this to enable the call to mips_mach_early_init() very early + from start.S. This function can be used e.g. to do some very early + CPU / SoC intitialization or image copying. Its called very early + and at this stage the PC might not match the linking address + (CONFIG_TEXT_BASE) - no absolute jump done until this call. + config MIPS_CACHE_SETUP bool "Allow generic start code to initialize and setup caches" default n if SKIP_LOWLEVEL_INIT diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index e22771715c..d0c412236d 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -236,6 +236,11 @@ wr_done: # endif #endif +#ifdef CONFIG_MIPS_MACH_EARLY_INIT + bal mips_mach_early_init + nop +#endif + #ifdef CONFIG_MIPS_CACHE_SETUP /* Initialize caches... */ PTR_LA t9, mips_cache_reset From 59aea37abf6bf6d5119a9e2f0237b26bf820b285 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:08:55 +0200 Subject: [PATCH 16/20] sysreset: Add Octeon sysreset driver This patch adds a UCLASS_SYSRESET sysreset driver for the Octeon SoC family. Signed-off-by: Stefan Roese Reviewed-by: Daniel Schwierzeck --- drivers/sysreset/Kconfig | 7 ++++ drivers/sysreset/Makefile | 1 + drivers/sysreset/sysreset_octeon.c | 52 ++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 drivers/sysreset/sysreset_octeon.c diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index 4be7433404..6ebc90e1d3 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -57,6 +57,13 @@ config SYSRESET_MICROBLAZE help This is soft reset on Microblaze which does jump to 0x0 address. +config SYSRESET_OCTEON + bool "Enable support for Marvell Octeon SoC family" + depends on ARCH_OCTEON + help + This enables the system reset driver support for Marvell Octeon + SoCs. + config SYSRESET_PSCI bool "Enable support for PSCI System Reset" depends on ARM_PSCI_FW diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 3ed4bab9e3..df2293b848 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o +obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o obj-$(CONFIG_SYSRESET_SOCFPGA_S10) += sysreset_socfpga_s10.o diff --git a/drivers/sysreset/sysreset_octeon.c b/drivers/sysreset/sysreset_octeon.c new file mode 100644 index 0000000000..a05dac3226 --- /dev/null +++ b/drivers/sysreset/sysreset_octeon.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Stefan Roese + */ + +#include +#include +#include +#include +#include + +#define RST_SOFT_RST 0x0080 + +struct octeon_sysreset_data { + void __iomem *base; +}; + +static int octeon_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct octeon_sysreset_data *data = dev_get_priv(dev); + + writeq(1, data->base + RST_SOFT_RST); + + return -EINPROGRESS; +} + +static int octeon_sysreset_probe(struct udevice *dev) +{ + struct octeon_sysreset_data *data = dev_get_priv(dev); + + data->base = dev_remap_addr(dev); + + return 0; +} + +static struct sysreset_ops octeon_sysreset = { + .request = octeon_sysreset_request, +}; + +static const struct udevice_id octeon_sysreset_ids[] = { + { .compatible = "mrvl,cn7xxx-rst" }, + { } +}; + +U_BOOT_DRIVER(sysreset_octeon) = { + .id = UCLASS_SYSRESET, + .name = "octeon_sysreset", + .priv_auto_alloc_size = sizeof(struct octeon_sysreset_data), + .ops = &octeon_sysreset, + .probe = octeon_sysreset_probe, + .of_match = octeon_sysreset_ids, +}; From 0dc4ab9c43ff6a235b4c0c5295a1a9747ea684c9 Mon Sep 17 00:00:00 2001 From: Aaron Williams Date: Tue, 30 Jun 2020 12:08:56 +0200 Subject: [PATCH 17/20] mips: octeon: Initial minimal support for the Marvell Octeon SoC This patch adds very basic support for the Octeon III SoCs. Only CFI parallel NOR flash and UART is supported for now. Please note that the basic Octeon port does not include the DDR3/4 initialization yet. This will be added in some follow-up patches later. To still use U-Boot on with this port, the L2 cache (4MiB on Octeon III CN73xx) is used as RAM. This way, U-Boot can boot to the prompt on such boards. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- MAINTAINERS | 6 ++ arch/mips/Kconfig | 43 ++++++++++++ arch/mips/Makefile | 3 + arch/mips/mach-octeon/Kconfig | 46 +++++++++++++ arch/mips/mach-octeon/Makefile | 10 +++ arch/mips/mach-octeon/cache.c | 24 +++++++ arch/mips/mach-octeon/clock.c | 14 ++++ arch/mips/mach-octeon/cpu.c | 66 +++++++++++++++++++ arch/mips/mach-octeon/dram.c | 28 ++++++++ arch/mips/mach-octeon/include/ioremap.h | 30 +++++++++ arch/mips/mach-octeon/include/mach/cavm-reg.h | 17 +++++ arch/mips/mach-octeon/include/mach/clock.h | 12 ++++ arch/mips/mach-octeon/lowlevel_init.S | 19 ++++++ scripts/config_whitelist.txt | 1 - 14 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 arch/mips/mach-octeon/Kconfig create mode 100644 arch/mips/mach-octeon/Makefile create mode 100644 arch/mips/mach-octeon/cache.c create mode 100644 arch/mips/mach-octeon/clock.c create mode 100644 arch/mips/mach-octeon/cpu.c create mode 100644 arch/mips/mach-octeon/dram.c create mode 100644 arch/mips/mach-octeon/include/ioremap.h create mode 100644 arch/mips/mach-octeon/include/mach/cavm-reg.h create mode 100644 arch/mips/mach-octeon/include/mach/clock.h create mode 100644 arch/mips/mach-octeon/lowlevel_init.S diff --git a/MAINTAINERS b/MAINTAINERS index 2a281a9a0f..bde85302ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -770,6 +770,12 @@ M: Ezequiel Garcia S: Maintained F: arch/mips/mach-jz47xx/ +MIPS Octeon +M: Aaron Williams +S: Maintained +F: arch/mips/mach-octeon/ +F: arch/mips/include/asm/arch-octeon/ + MMC M: Peng Fan S: Maintained diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 652e6a993e..d2a0a35bb9 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -106,6 +106,25 @@ config ARCH_JZ47XX select OF_CONTROL select DM +config ARCH_OCTEON + bool "Support Marvell Octeon CN7xxx platforms" + select CPU_CAVIUM_OCTEON + select DISPLAY_CPUINFO + select DMA_ADDR_T_64BIT + select DM + select DM_SERIAL + select DM_GPIO + select DM_ETH + select MIPS_L2_CACHE + select MIPS_TUNE_OCTEON3 + select ROM_EXCEPTION_VECTORS + select SUPPORTS_BIG_ENDIAN + select SUPPORTS_CPU_MIPS64_OCTEON + select PHYS_64BIT + select OF_CONTROL + select OF_LIVE + imply CMD_DM + config MACH_PIC32 bool "Support Microchip PIC32" select DM @@ -160,6 +179,7 @@ source "arch/mips/mach-bmips/Kconfig" source "arch/mips/mach-jz47xx/Kconfig" source "arch/mips/mach-pic32/Kconfig" source "arch/mips/mach-mtmips/Kconfig" +source "arch/mips/mach-octeon/Kconfig" if MIPS @@ -233,6 +253,14 @@ config CPU_MIPS64_R6 Choose this option to build a kernel for release 6 or later of the MIPS64 architecture. +config CPU_MIPS64_OCTEON + bool "Marvell Octeon series of CPUs" + depends on SUPPORTS_CPU_MIPS64_OCTEON + select 64BIT + help + Choose this option for Marvell Octeon CPUs. These CPUs are between + MIPS64 R5 and R6 with other extensions. + endchoice menu "General setup" @@ -431,6 +459,12 @@ config SUPPORTS_CPU_MIPS64_R2 config SUPPORTS_CPU_MIPS64_R6 bool +config SUPPORTS_CPU_MIPS64_OCTEON + bool + +config CPU_CAVIUM_OCTEON + bool + config CPU_MIPS32 bool default y if CPU_MIPS32_R1 || CPU_MIPS32_R2 || CPU_MIPS32_R6 @@ -438,6 +472,7 @@ config CPU_MIPS32 config CPU_MIPS64 bool default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6 + default y if CPU_MIPS64_OCTEON config MIPS_TUNE_4KC bool @@ -454,6 +489,9 @@ config MIPS_TUNE_34KC config MIPS_TUNE_74KC bool +config MIPS_TUNE_OCTEON3 + bool + config 32BIT bool @@ -486,6 +524,11 @@ config MIPS_SRAM_INIT before it can be used. If enabled, a function mips_sram_init() will be called just before setup_stack_gd. +config DMA_ADDR_T_64BIT + bool + help + Select this to enable 64-bit DMA addressing + config SYS_DCACHE_SIZE int default 0 diff --git a/arch/mips/Makefile b/arch/mips/Makefile index af3f227436..6502aebd29 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -17,6 +17,7 @@ machine-$(CONFIG_ARCH_JZ47XX) += jz47xx machine-$(CONFIG_MACH_PIC32) += pic32 machine-$(CONFIG_ARCH_MTMIPS) += mtmips machine-$(CONFIG_ARCH_MSCC) += mscc +machine-${CONFIG_ARCH_OCTEON} += octeon machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y)) libs-y += $(machdirs) @@ -30,6 +31,7 @@ arch-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,-mips32r6 arch-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,-mips64 arch-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,-mips64r2 arch-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,-mips64r6 +arch-${CONFIG_CPU_MIPS64_OCTEON} += -march=octeon2 # Allow extra optimization for specific CPUs/SoCs tune-$(CONFIG_MIPS_TUNE_4KC) += -mtune=4kc @@ -37,6 +39,7 @@ tune-$(CONFIG_MIPS_TUNE_14KC) += -mtune=14kc tune-$(CONFIG_MIPS_TUNE_24KC) += -mtune=24kc tune-$(CONFIG_MIPS_TUNE_34KC) += -mtune=34kc tune-$(CONFIG_MIPS_TUNE_74KC) += -mtune=74kc +tune-${CONFIG_MIPS_TUNE_OCTEON3} += -mtune=octeon2 # Include default header files cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic diff --git a/arch/mips/mach-octeon/Kconfig b/arch/mips/mach-octeon/Kconfig new file mode 100644 index 0000000000..3c8ca8dd36 --- /dev/null +++ b/arch/mips/mach-octeon/Kconfig @@ -0,0 +1,46 @@ +menu "Octeon platforms" + depends on ARCH_OCTEON + +config SYS_SOC + string + default "octeon" + +config OCTEON_CN7XXX + bool "Octeon CN7XXX SoC" + +config OCTEON_CN70XX + bool "Octeon CN70XX SoC" + select OCTEON_CN7XXX + +config OCTEON_CN73XX + bool "Octeon CN73XX SoC" + select OCTEON_CN7XXX + +config OCTEON_CN78XX + bool "Octeon CN78XX SoC" + select OCTEON_CN7XXX + +choice + prompt "Octeon MIPS family select" + +config SOC_OCTEON3 + bool "Octeon III family" + help + This selects the Octeon III SoC family CN70xx, CN73XX, CN78xx + and CNF75XX. + +endchoice + +config SYS_DCACHE_SIZE + default 32768 + +config SYS_DCACHE_LINE_SIZE + default 128 + +config SYS_ICACHE_SIZE + default 79872 + +config SYS_ICACHE_LINE_SIZE + default 128 + +endmenu diff --git a/arch/mips/mach-octeon/Makefile b/arch/mips/mach-octeon/Makefile new file mode 100644 index 0000000000..2e37ca572c --- /dev/null +++ b/arch/mips/mach-octeon/Makefile @@ -0,0 +1,10 @@ +# (C) Copyright 2019 Marvell, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += lowlevel_init.o +obj-y += cache.o +obj-y += clock.o +obj-y += cpu.o +obj-y += dram.o diff --git a/arch/mips/mach-octeon/cache.c b/arch/mips/mach-octeon/cache.c new file mode 100644 index 0000000000..9a88bb97c7 --- /dev/null +++ b/arch/mips/mach-octeon/cache.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#include + +/* + * The Octeon platform is cache coherent and cache flushes and invalidates + * are not needed. Define some platform specific empty flush_foo() + * functions here to overwrite the _weak common function as a no-op. + * This effectively disables all cache operations. + */ +void flush_dcache_range(ulong start_addr, ulong stop) +{ +} + +void flush_cache(ulong start_addr, ulong size) +{ +} + +void invalidate_dcache_range(ulong start_addr, ulong stop) +{ +} diff --git a/arch/mips/mach-octeon/clock.c b/arch/mips/mach-octeon/clock.c new file mode 100644 index 0000000000..119b3ac50b --- /dev/null +++ b/arch/mips/mach-octeon/clock.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018, 2019 Marvell International Ltd. + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +ulong notrace get_tbclk(void) +{ + return gd->cpu_clk; +} diff --git a/arch/mips/mach-octeon/cpu.c b/arch/mips/mach-octeon/cpu.c new file mode 100644 index 0000000000..2680a2e6ed --- /dev/null +++ b/arch/mips/mach-octeon/cpu.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int get_clocks(void) +{ + const u64 ref_clock = PLL_REF_CLK; + void __iomem *rst_boot; + u64 val; + + rst_boot = ioremap(CAVM_RST_BOOT, 0); + val = ioread64(rst_boot); + gd->cpu_clk = ref_clock * FIELD_GET(RST_BOOT_C_MUL, val); + gd->bus_clk = ref_clock * FIELD_GET(RST_BOOT_PNR_MUL, val); + + debug("%s: cpu: %lu, bus: %lu\n", __func__, gd->cpu_clk, gd->bus_clk); + + return 0; +} + +/* Early mach init code run from flash */ +int mach_cpu_init(void) +{ + void __iomem *mio_boot_reg_cfg0; + + /* Remap boot-bus 0x1fc0.0000 -> 0x1f40.0000 */ + /* ToDo: Move this to an early running bus (bootbus) DM driver */ + mio_boot_reg_cfg0 = ioremap(CAVM_MIO_BOOT_REG_CFG0, 0); + clrsetbits_be64(mio_boot_reg_cfg0, 0xffff, 0x1f40); + + /* Get clocks and store them in GD */ + get_clocks(); + + return 0; +} + +/** + * Returns number of cores + * + * @return number of CPU cores for the specified node + */ +static int cavm_octeon_num_cores(void) +{ + void __iomem *ciu_fuse; + + ciu_fuse = ioremap(CAVM_CIU_FUSE, 0); + return fls64(ioread64(ciu_fuse) & 0xffffffffffff); +} + +int print_cpuinfo(void) +{ + printf("SoC: Octeon CN73xx (%d cores)\n", cavm_octeon_num_cores()); + + return 0; +} diff --git a/arch/mips/mach-octeon/dram.c b/arch/mips/mach-octeon/dram.c new file mode 100644 index 0000000000..ff7a59f2ab --- /dev/null +++ b/arch/mips/mach-octeon/dram.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) Stefan Roese + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + /* + * No DDR init yet -> run in L2 cache + */ + gd->ram_size = (4 << 20); + gd->bd->bi_dram[0].size = gd->ram_size; + gd->bd->bi_dram[1].size = 0; + + return 0; +} + +ulong board_get_usable_ram_top(ulong total_size) +{ + return gd->ram_top; +} diff --git a/arch/mips/mach-octeon/include/ioremap.h b/arch/mips/mach-octeon/include/ioremap.h new file mode 100644 index 0000000000..59b75008a2 --- /dev/null +++ b/arch/mips/mach-octeon/include/ioremap.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_MACH_OCTEON_IOREMAP_H +#define __ASM_MACH_OCTEON_IOREMAP_H + +#include + +/* + * Allow physical addresses to be fixed up to help peripherals located + * outside the low 32-bit range -- generic pass-through version. + */ +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, + phys_addr_t size) +{ + return phys_addr; +} + +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, + unsigned long flags) +{ + return (void __iomem *)(XKPHYS | offset); +} + +static inline int plat_iounmap(const volatile void __iomem *addr) +{ + return 0; +} + +#define _page_cachable_default _CACHE_CACHABLE_NONCOHERENT + +#endif /* __ASM_MACH_OCTEON_IOREMAP_H */ diff --git a/arch/mips/mach-octeon/include/mach/cavm-reg.h b/arch/mips/mach-octeon/include/mach/cavm-reg.h new file mode 100644 index 0000000000..45850ea355 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cavm-reg.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#ifndef __CAVM_REG_H__ + +/* Register offsets */ +#define CAVM_CIU_FUSE 0x00010100000001a0 +#define CAVM_MIO_BOOT_REG_CFG0 0x0001180000000000 +#define CAVM_RST_BOOT 0x0001180006001600 + +/* Register bits */ +#define RST_BOOT_C_MUL GENMASK_ULL(36, 30) +#define RST_BOOT_PNR_MUL GENMASK_ULL(29, 24) + +#endif /* __CAVM_REG_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/clock.h b/arch/mips/mach-octeon/include/mach/clock.h new file mode 100644 index 0000000000..85c8d3dc4f --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/clock.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018, 2019 Marvell International Ltd. + */ + +#ifndef __CLOCK_H__ + +/** System PLL reference clock */ +#define PLL_REF_CLK 50000000 /* 50 MHz */ +#define NS_PER_REF_CLK_TICK (1000000000 / PLL_REF_CLK) + +#endif /* __CLOCK_H__ */ diff --git a/arch/mips/mach-octeon/lowlevel_init.S b/arch/mips/mach-octeon/lowlevel_init.S new file mode 100644 index 0000000000..d9aab38cde --- /dev/null +++ b/arch/mips/mach-octeon/lowlevel_init.S @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Stefan Roese + */ + +#include +#include +#include +#include +#include +#include +#include + + .set noreorder + +LEAF(lowlevel_init) + jr ra + nop + END(lowlevel_init) diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 1602b05f07..2ec7642583 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -228,7 +228,6 @@ CONFIG_CPLD_BR_PRELIM CONFIG_CPLD_OR_PRELIM CONFIG_CPM2 CONFIG_CPU_ARMV8 -CONFIG_CPU_CAVIUM_OCTEON CONFIG_CPU_FREQ_HZ CONFIG_CPU_HAS_LLSC CONFIG_CPU_HAS_PREFETCH From ff7e4f030bf3b128288ea4482941cfae1dd8abfb Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:08:57 +0200 Subject: [PATCH 18/20] mips: octeon: dts: Add Octeon 3 cn73xx base dtsi file This patch adds the base dtsi file for the Octeon 3 cn73xx SoC. Signed-off-by: Stefan Roese --- MAINTAINERS | 1 + arch/mips/dts/mrvl,cn73xx.dtsi | 64 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 arch/mips/dts/mrvl,cn73xx.dtsi diff --git a/MAINTAINERS b/MAINTAINERS index bde85302ec..6316c6ca00 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -775,6 +775,7 @@ M: Aaron Williams S: Maintained F: arch/mips/mach-octeon/ F: arch/mips/include/asm/arch-octeon/ +F: arch/mips/dts/mrvl,cn73xx.dtsi MMC M: Peng Fan diff --git a/arch/mips/dts/mrvl,cn73xx.dtsi b/arch/mips/dts/mrvl,cn73xx.dtsi new file mode 100644 index 0000000000..a7bd55f8ad --- /dev/null +++ b/arch/mips/dts/mrvl,cn73xx.dtsi @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Marvell / Cavium Inc. CN73xx + */ + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <2>; + + soc0: soc@0 { + interrupt-parent = <&ciu3>; + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; /* Direct mapping */ + + ciu3: interrupt-controller@1010000000000 { + compatible = "cavium,octeon-7890-ciu3"; + interrupt-controller; + /* + * Interrupts are specified by two parts: + * 1) Source number (20 significant bits) + * 2) Trigger type: (4 == level, 1 == edge) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10100 0x00000000 0x0 0xb0000000>; + }; + + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus","simple-bus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + }; + + reset: reset@1180006001600 { + compatible = "mrvl,cn7xxx-rst"; + reg = <0x11800 0x06001600 0x0 0x200>; + }; + + uart0: serial@1180000000800 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000800 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0x08000 4>; + }; + + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + clock-frequency = <0>; + current-speed = <115200>; + reg-shift = <3>; + interrupts = <0x08040 4>; + }; + }; +}; From e9609dc38ba225ddb58fcef41a0beb8a3b09a888 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:33:17 +0200 Subject: [PATCH 19/20] mips: octeon: use mips_mach_early_init() to copy to L2 cache This patch adds the code to copy itself from bootrom location to a different location (TEXT_BASE) to the Octeon platform. Its used in this case to copy the complete U-Boot image into L2 cache, which greatly improves the bootup time - especially in regard to the very long and complex DDR4 init code. The Kconfig symbol CONFIG_MIPS_MACH_EARLY_INIT is enabled with this patch for Octeon. Signed-off-by: Stefan Roese --- arch/mips/Kconfig | 1 + arch/mips/mach-octeon/lowlevel_init.S | 50 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index d2a0a35bb9..997e145450 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -116,6 +116,7 @@ config ARCH_OCTEON select DM_GPIO select DM_ETH select MIPS_L2_CACHE + select MIPS_MACH_EARLY_INIT select MIPS_TUNE_OCTEON3 select ROM_EXCEPTION_VECTORS select SUPPORTS_BIG_ENDIAN diff --git a/arch/mips/mach-octeon/lowlevel_init.S b/arch/mips/mach-octeon/lowlevel_init.S index d9aab38cde..fa87cb4e34 100644 --- a/arch/mips/mach-octeon/lowlevel_init.S +++ b/arch/mips/mach-octeon/lowlevel_init.S @@ -17,3 +17,53 @@ LEAF(lowlevel_init) jr ra nop END(lowlevel_init) + +LEAF(mips_mach_early_init) + + move s0, ra + + bal __dummy + nop + +__dummy: + /* Get the actual address that we are running at */ + PTR_LA a7, __dummy + dsubu t3, ra, a7 /* t3 now has reloc offset */ + + PTR_LA t1, _start + daddu t0, t1, t3 /* t0 now has actual address of _start */ + + /* Calculate end address of copy loop */ + PTR_LA t2, _end + daddiu t2, t2, 0x4000 /* Increase size to include appended DTB */ + daddiu t2, t2, 127 + ins t2, zero, 0, 7 /* Round up to cache line for memcpy */ + + /* Copy ourself to the L2 cache from flash, 32 bytes at a time */ +1: + ld a0, 0(t0) + ld a1, 8(t0) + ld a2, 16(t0) + ld a3, 24(t0) + sd a0, 0(t1) + sd a1, 8(t1) + sd a2, 16(t1) + sd a3, 24(t1) + addiu t0, 32 + addiu t1, 32 + bne t1, t2, 1b + nop + + sync + + /* + * Return to start.S now running from TEXT_BASE, which points + * to DRAM address space, which effectively is L2 cache now. + * This speeds up the init process extremely, especially the + * DDR init code. + */ + dsubu s0, s0, t3 /* Fixup return address with reloc offset */ + jr.hb s0 /* Jump back with hazard barrier */ + nop + + END(mips_mach_early_init) From 5fef24c912a44a08ab644aa16ceb5a435491f9d9 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Tue, 30 Jun 2020 12:08:58 +0200 Subject: [PATCH 20/20] mips: octeon: Add minimal Octeon 3 EBB7304 EVK support This patch adds very basic minimal support for the Marvell Octeon 3 CN73xx based EBB7304 EVK. Please note that the basic Octeon port does not support DDR3/4 initialization yet. To still use U-Boot on with this port, the L2 cache (4MiB) is used as RAM. This way, U-Boot can boot to the prompt on this board. Supported devices: - UART - reset - CFI parallel NOR flash Signed-off-by: Stefan Roese --- arch/mips/dts/Makefile | 1 + arch/mips/dts/mrvl,octeon-ebb7304.dts | 96 ++++++++++++++++++++++++ arch/mips/mach-octeon/Kconfig | 14 ++++ board/Marvell/octeon_ebb7304/Kconfig | 19 +++++ board/Marvell/octeon_ebb7304/MAINTAINERS | 7 ++ board/Marvell/octeon_ebb7304/Makefile | 8 ++ board/Marvell/octeon_ebb7304/board.c | 9 +++ configs/octeon_ebb7304_defconfig | 38 ++++++++++ include/configs/octeon_common.h | 19 +++++ include/configs/octeon_ebb7304.h | 20 +++++ 10 files changed, 231 insertions(+) create mode 100644 arch/mips/dts/mrvl,octeon-ebb7304.dts create mode 100644 board/Marvell/octeon_ebb7304/Kconfig create mode 100644 board/Marvell/octeon_ebb7304/MAINTAINERS create mode 100644 board/Marvell/octeon_ebb7304/Makefile create mode 100644 board/Marvell/octeon_ebb7304/board.c create mode 100644 configs/octeon_ebb7304_defconfig create mode 100644 include/configs/octeon_common.h create mode 100644 include/configs/octeon_ebb7304.h diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index f711e9fb59..dc85901dca 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -18,6 +18,7 @@ dtb-$(CONFIG_BOARD_COMTREND_VR3032U) += comtrend,vr-3032u.dtb dtb-$(CONFIG_BOARD_COMTREND_WAP5813N) += comtrend,wap-5813n.dtb dtb-$(CONFIG_BOARD_HUAWEI_HG556A) += huawei,hg556a.dtb dtb-$(CONFIG_BOARD_MT7628_RFB) += mediatek,mt7628-rfb.dtb +dtb-$(CONFIG_TARGET_OCTEON_EBB7304) += mrvl,octeon-ebb7304.dtb dtb-$(CONFIG_BOARD_NETGEAR_CG3100D) += netgear,cg3100d.dtb dtb-$(CONFIG_BOARD_NETGEAR_DGND3700V2) += netgear,dgnd3700v2.dtb dtb-$(CONFIG_BOARD_SAGEM_FAST1704) += sagem,f@st1704.dtb diff --git a/arch/mips/dts/mrvl,octeon-ebb7304.dts b/arch/mips/dts/mrvl,octeon-ebb7304.dts new file mode 100644 index 0000000000..4e9c2de7d4 --- /dev/null +++ b/arch/mips/dts/mrvl,octeon-ebb7304.dts @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Marvell / Cavium Inc. EVB CN7300 + */ + +/dts-v1/; + +/include/ "mrvl,cn73xx.dtsi" + +/ { + model = "cavium,ebb7304"; + compatible = "cavium,ebb7304"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = &uart0; + }; +}; + +&bootbus { + /* + * bootbus CS0 for CFI flash is remapped (0x1fc0.0000 -> 1f40.0000) + * as the initial size is too small for the 8MiB flash device + */ + ranges = <0 0 0 0x1f400000 0xc00000>, + <1 0 0x10000 0x10000000 0>, + <2 0 0x10000 0x20000000 0>, + <3 0 0x10000 0x30000000 0>, + <4 0 0 0x1d020000 0x10000>, + <5 0 0x10000 0x50000000 0>, + <6 0 0x10000 0x60000000 0>, + <7 0 0x10000 0x70000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <10>; + cavium,t-ce = <50>; + cavium,t-oe = <50>; + cavium,t-we = <35>; + cavium,t-rd-hld = <25>; + cavium,t-wr-hld = <35>; + cavium,t-pause = <0>; + cavium,t-wait = <50>; + cavium,t-page = <30>; + cavium,t-rd-dly = <0>; + cavium,page-mode = <1>; + cavium,pages = <8>; + cavium,bus-width = <8>; + }; + + cavium,cs-config@4 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <4>; + cavium,t-adr = <10>; + cavium,t-ce = <10>; + cavium,t-oe = <160>; + cavium,t-we = <100>; + cavium,t-rd-hld = <10>; + cavium,t-wr-hld = <0>; + cavium,t-pause = <50>; + cavium,t-wait = <50>; + cavium,t-page = <10>; + cavium,t-rd-dly = <10>; + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + + flash0: nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "bootloader"; + reg = <0 0x340000>; + read-only; + }; + partition@300000 { + label = "storage"; + reg = <0x340000 0x4be000>; + }; + partition@7fe000 { + label = "environment"; + reg = <0x7fe000 0x2000>; + read-only; + }; + }; +}; + +&uart0 { + clock-frequency = <1200000000>; +}; diff --git a/arch/mips/mach-octeon/Kconfig b/arch/mips/mach-octeon/Kconfig index 3c8ca8dd36..e8596ed99a 100644 --- a/arch/mips/mach-octeon/Kconfig +++ b/arch/mips/mach-octeon/Kconfig @@ -31,6 +31,18 @@ config SOC_OCTEON3 endchoice +choice + prompt "Octeon 3 board select" + default TARGET_OCTEON_EBB7304 + +config TARGET_OCTEON_EBB7304 + bool "Marvell Octeon EBB7304" + select OCTEON_CN73XX + help + Choose this for the Octeon EBB7304 board + +endchoice + config SYS_DCACHE_SIZE default 32768 @@ -43,4 +55,6 @@ config SYS_ICACHE_SIZE config SYS_ICACHE_LINE_SIZE default 128 +source "board/Marvell/octeon_ebb7304/Kconfig" + endmenu diff --git a/board/Marvell/octeon_ebb7304/Kconfig b/board/Marvell/octeon_ebb7304/Kconfig new file mode 100644 index 0000000000..ab54e6dbbc --- /dev/null +++ b/board/Marvell/octeon_ebb7304/Kconfig @@ -0,0 +1,19 @@ +if TARGET_OCTEON_EBB7304 + +config SYS_BOARD + string + default "octeon_ebb7304" + +config SYS_VENDOR + string + default "Marvell" + +config SYS_CONFIG_NAME + string + default "octeon_ebb7304" + +config DEFAULT_DEVICE_TREE + string + default "mrvl,octeon-ebb7304" + +endif diff --git a/board/Marvell/octeon_ebb7304/MAINTAINERS b/board/Marvell/octeon_ebb7304/MAINTAINERS new file mode 100644 index 0000000000..7256f83567 --- /dev/null +++ b/board/Marvell/octeon_ebb7304/MAINTAINERS @@ -0,0 +1,7 @@ +OCTEON_EBB7304 BOARD +M: Aaron Williams +S: Maintained +F: board/Marvell/octeon_ebb7304/* +F: configs/octeon_ebb7304_defconfig +F: include/configs/octeon_ebb7304.h +F: arch/mips/dts/mrvl,octeon-ebb7304.dts diff --git a/board/Marvell/octeon_ebb7304/Makefile b/board/Marvell/octeon_ebb7304/Makefile new file mode 100644 index 0000000000..a3ed0c8873 --- /dev/null +++ b/board/Marvell/octeon_ebb7304/Makefile @@ -0,0 +1,8 @@ +# +# Copyright (C) 2020 Stefan Roese +# Copyright (C) 2019-2020 Marvell International Ltd. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := board.o diff --git a/board/Marvell/octeon_ebb7304/board.c b/board/Marvell/octeon_ebb7304/board.c new file mode 100644 index 0000000000..56e50a9063 --- /dev/null +++ b/board/Marvell/octeon_ebb7304/board.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Stefan Roese + */ + +/* + * Nothing included right now. Code will be added in follow-up + * patches. + */ diff --git a/configs/octeon_ebb7304_defconfig b/configs/octeon_ebb7304_defconfig new file mode 100644 index 0000000000..d810b1e45f --- /dev/null +++ b/configs/octeon_ebb7304_defconfig @@ -0,0 +1,38 @@ +CONFIG_MIPS=y +CONFIG_SYS_TEXT_BASE=0xffffffff80000000 +CONFIG_SYS_MALLOC_F_LEN=0x4000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_ENV_SECT_SIZE=0x10000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_DEBUG_UART_BASE=0x8001180000000800 +CONFIG_DEBUG_UART_CLOCK=1200000000 +CONFIG_ARCH_OCTEON=y +# CONFIG_MIPS_CACHE_SETUP is not set +# CONFIG_MIPS_CACHE_DISABLE is not set +CONFIG_DEBUG_UART=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_MTD=y +CONFIG_CMD_PCI=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_TIME=y +CONFIG_ENV_IS_IN_FLASH=y +CONFIG_ENV_ADDR=0x1FBFE000 +CONFIG_CLK=y +# CONFIG_INPUT is not set +CONFIG_MTD=y +CONFIG_DM_MTD=y +CONFIG_MTD_NOR_FLASH=y +CONFIG_FLASH_CFI_DRIVER=y +CONFIG_CFI_FLASH=y +CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y +CONFIG_FLASH_CFI_MTD=y +CONFIG_SYS_FLASH_CFI=y +# CONFIG_NETDEVICES is not set +CONFIG_DEBUG_UART_SHIFT=3 +CONFIG_DEBUG_UART_ANNOUNCE=y +CONFIG_SYS_NS16550=y +CONFIG_SYSRESET=y +CONFIG_SYSRESET_OCTEON=y +CONFIG_HEXDUMP=y diff --git a/include/configs/octeon_common.h b/include/configs/octeon_common.h new file mode 100644 index 0000000000..530f02ad3c --- /dev/null +++ b/include/configs/octeon_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019-2020 + * Marvell + */ + +#ifndef __OCTEON_COMMON_H__ +#define __OCTEON_COMMON_H__ + +/* No DDR init yet -> run in L2 cache with limited resources */ +#define CONFIG_SYS_MALLOC_LEN (256 << 10) +#define CONFIG_SYS_SDRAM_BASE 0xffffffff80000000 +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + (1 << 20)) + +#define CONFIG_SYS_INIT_SP_OFFSET 0x180000 + +#endif /* __OCTEON_COMMON_H__ */ diff --git a/include/configs/octeon_ebb7304.h b/include/configs/octeon_ebb7304.h new file mode 100644 index 0000000000..04fe4dfe22 --- /dev/null +++ b/include/configs/octeon_ebb7304.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2019-2020 + * Marvell + */ + +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#include "octeon_common.h" + +/* + * CFI flash + */ +#define CONFIG_SYS_MAX_FLASH_BANKS 1 +#define CONFIG_SYS_MAX_FLASH_SECT 256 +#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_8BIT +#define CONFIG_SYS_FLASH_EMPTY_INFO /* flinfo indicates empty blocks */ + +#endif /* __CONFIG_H__ */