From patchwork Wed Jun 10 10:09:34 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Eisele X-Patchwork-Id: 28396 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@bilbo.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from ozlabs.org (ozlabs.org [203.10.76.45]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "mx.ozlabs.org", Issuer "CA Cert Signing Authority" (verified OK)) by bilbo.ozlabs.org (Postfix) with ESMTPS id 8EB79B70C5 for ; Wed, 10 Jun 2009 20:07:05 +1000 (EST) Received: by ozlabs.org (Postfix) id 7EF25DDD0C; Wed, 10 Jun 2009 20:07:05 +1000 (EST) Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id BC8C5DDD04 for ; Wed, 10 Jun 2009 20:07:02 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751231AbZFJKG4 (ORCPT ); Wed, 10 Jun 2009 06:06:56 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752697AbZFJKG4 (ORCPT ); Wed, 10 Jun 2009 06:06:56 -0400 Received: from mail176c2.megamailservers.com ([69.49.111.76]:32780 "EHLO mail176c2.megamailservers.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751231AbZFJKGx (ORCPT ); Wed, 10 Jun 2009 06:06:53 -0400 X-Authenticated-User: konrad.gaisler.com Received: from localhost.localdomain (c-10a5e155.260-1-64736c10.cust.bredbandsbolaget.se [85.225.165.16]) (authenticated bits=0) by mail176c2.megamailservers.com (8.13.6/8.13.1) with ESMTP id n5AA6VUx022391; Wed, 10 Jun 2009 06:06:37 -0400 From: konrad@gaisler.com To: sparclinux@vger.kernel.org Cc: sam@ravnborg.org, Konrad Eisele Subject: [PATCH 1/7] CONFIG_SPARC_LEON option Date: Wed, 10 Jun 2009 12:09:34 +0200 Message-Id: <1244628574-23789-1-git-send-email-konrad@gaisler.com> X-Mailer: git-send-email 1.6.3.2 In-Reply-To: <4A2E45CF.8070106@gaisler.com> References: <4A2E45CF.8070106@gaisler.com> Sender: sparclinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: sparclinux@vger.kernel.org From: Konrad Eisele Below the new patch, >> +config LEON >> + bool "Leon processor family" >> + depends on SPARC32 >> + ---help--- >> + If you say Y here if you are running on a LEON processor. > > I would have preferred SPARC_LEON here - but no strong opinion on that. > Rationale is that LEON is a specialzation of a sparc. > Changed to CONFIG_SPARC_LEON >> # Bus options (PCI etc.) > > defconfig updates like this is not needed. > The default is n so that would be picked up anyway. > Removed >> + >> +#if defined(CONFIG_LEON) > > We usually use the shorter: > #ifdef CONFIG_LEON > is there is only one symbol to check. > Changed >> +#define ASI_LEON_BYPASS 0x1c >> +#define ASI_LEON_FLUSH_PAGE 0x10 >> + > >> +#define LEON_TYPEDEF typedef >> +#define LEON_VOLATILE volatile > This obscufation shall die. > > Also you really need to revisit all the abuses of volatile. > Please read: Documentation/volatile-considered-harmful.txt Removed typdef and volatile >> +constant ASI_MMU_BP : std_logic_vector(4 downto 0) := "11100"; >> +constant ASI_MMU_DIAG : std_logic_vector(4 downto 0) := "11101"; >> +constant ASI_MMU_DSU : std_logic_vector(4 downto 0) := "11111"; >> +*/ > This comment block confuses me. Looks like some VHDL sneaked in. > Could you update the proper definitons one-by-one? > Removed >> + >> +#ifdef CONFIG_OPEN_ETH >> +#define LEON_ETH_BASE_ADD ((unsigned long)LEON_VA_ETHERMAC) >> +/* map leon on ethermac adress space at pa 0xb0000000 */ >> +#define LEON_VA_ETHERMAC DVMA_VADDR >> +#endif > At best this looks like some leon specific driver thing? > Removed >> + HARDDBG_PRINTF("[<-%03d @ %22s()]:\n" , __LINE__, __func__); >> +#define HARDDBG_OUT(fmt, arg...) \ >> + HARDDBG_PRINTF("[->%03d @ %22s()]:" fmt , __LINE__, __func__, ## >> arg); > Rest of sparc does not have such stuff. > Why do leon need it? Yes, it is a raw register uart dump routine that makes live easier. > >> +#if 1 > > Not needed. Removed > >> +#ifndef __ASSEMBLER__ >> + > A lot of what follows could be used from assebler with no problem. > Try to restrict your no asm groups to non compatible stuff - with > some common sense applied. > Moved >> + >> +struct amba_prom_registers { >> + unsigned int phys_addr; /* The physical address of this register */ >> + unsigned int reg_size; /* How many bytes does this register take >> up? */ >> +}; > For stuff that maps to HW use bitspecific types like u32, u16 etc. > Changed to u32 >> +} LEON3_IrqCtrl_Regs_Map; >> + > > 1) do not use typedefs > 2) user lower case names > 3) use bitwidt specific types done 1 + 2 >> +#define LEON3_GPTIMER_CTRL_ISPENDING(r) (((r)&LEON3_GPTIMER_CTRL_PENDING) ? 1 : 0) > > Btw - 80 is not a hard limit. > Break it when it makes sense. Done more vertical alignment > >> + >> +LEON_TYPEDEF void (*GPTIMER_CALLBACK) (void); > > small caps.. Ok. > > >> +LEON_TYPEDEF struct _sparc_gptimer { >> + LEON3_GpTimer_Regs_Map *inst; >> + unsigned int ctrl, reload, value, scalarreload; >> + int irq, flags, idxinst, idx, enabled, connected, minscalar; >> + int ticksPerSecond, stat; >> + GPTIMER_CALLBACK callback; >> + int arg; >> +} sparc_gptimer; > >> +LEON_TYPEDEF struct _sparc_gptimer { >> + LEON3_GpTimer_Regs_Map *inst; >> + unsigned int ctrl; > unsigned int reload; > unsigned int value; > unsigned int scalarreload; > .... > >> + int irq, flags, idxinst, idx, enabled, connected, minscalar; >> + int ticksPerSecond, stat; >> + GPTIMER_CALLBACK callback; >> + int arg; >> +} sparc_gptimer; > leon_gptimer? > > Add the following to amba.h? > Or maybe leon_amba.h to split up things? Removed these 2 structs, they where unused here. >> +#define ASI_LEON3_SYSCTRL_DCFG 0x0c >> +#define ASI_LEON3_SYSCTRL_CFG_SNOOPING (1<<27) >> +#define ASI_LEON3_SYSCTRL_CFG_SSIZE(c) (1<<((c>>20)&0xf)) > spaes around operator - also in macros. Ok. >> +#ifdef __sparc > > But his is a kernel only file - confused? > Removed > > Veritical alignmnet would be good. Done > >> + >> +#define PAGE_MIN_SHIFT (12) >> +#define PAGE_MIN_SIZE (1UL << PAGE_MIN_SHIFT) > > Use AC(1,UL) so this is usefull from assembler. I'm a bit unsure about this one. I'll keep 1UL, PAGE_MIN_SIZE is not used in assembly. > > Please use following order: > 1) All linux/* includes. The longest lines first. > --space-- > 2) All asm/* includes. The longest lines first > --space-- > 3) All local includes > Ok, but I'm a bit suspect regarging longest-name-sorting, I rather leave linux/kernel.h at the top. >> +#undef LEON_IMASK >> +#define LEON_IMASK ((&LEON3_IrqCtrl_Regs->mask[0])) > Hack - is it needed? Removed #undef >> +{ >> + return LEON3_BYPASS_LOAD_PA(&LEON3_IrqCtrl_Regs->intid[cpu]) & 0x1f; >> +} > > I wonder what this UPPERCASE LEON3_BYPASS_LOAD_PA thing is? It is a bypass-mmu-and-access-physical address inline. >> +# endif > No space between # and endif. > And please add a comment with the conent of the if so we can follow it. > (Do not do that for short if/endif blocks). > > This function could use a few helper function > to make it more readable and with less ifdeffery. > I removed all SMP stuff for now. This way it gets cleaner. >> +void _amba_init(struct device_node *dp, struct device_node ***nextp); >> +#endif > > This file is leon specific - so why this ifdef/endif? > And I think this prototype belong in a header? Removed the ifdefs. However if I move the prototype to the header I'll draw in many dependencies to define "struct device_node". Therefore I think this way is cleaner. > >> + >> +void console_print_LEON(const char *p); > Same here - why not in a header? This time I move it to leon.h. >> +} > Please revisit all funtions and check if they all need to be non-static. Added some statics >> +#define PFN(x) ((x) >> PAGE_SHIFT) >> +extern unsigned long last_valid_pfn; > Move to header file. > Done >> +#endif >> +} > This is leon spacif - drop the ifdefs. Done This macro will shield, if undefined, the sun-sparc code from LEON specific code. In particular include/asm/leon.h will get empty through #ifdef arch/sparc/kernel/leon.c not compiled through Makefile:obj-$(CONFIG_SPARC_LEON) arch/sparc/mm/leon.c not compiled through Makefile:obj-$(CONFIG_SPARC_LEON) --- arch/sparc/Kconfig | 6 arch/sparc/include/asm/leon.h | 571 +++++++++++++++++++++++++++++++++++++++++ arch/sparc/kernel/leon_k.c | 195 ++++++++++++++ arch/sparc/mm/leon_m.c | 254 ++++++++++++++++++ 4 files changed, 1026 insertions(+), 0 deletions(-) diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 2185cf9..cf621bf 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -435,6 +435,12 @@ config SERIAL_CONSOLE If unsure, say N. +config SPARC_LEON + bool "Sparc Leon processor family" + depends on SPARC32 + ---help--- + If you say Y here if you are running on a SPARC-LEON processor. + endmenu menu "Bus options (PCI etc.)" diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h new file mode 100644 index 0000000..e051692 --- /dev/null +++ b/arch/sparc/include/asm/leon.h @@ -0,0 +1,571 @@ +/* +*Copyright (C) 2004 Konrad Eisele (eiselekd@web.de, +*konrad@gaisler.com), Gaisler Research +*Copyright (C) 2004 Stefan Holst (mail@s-holst.de), Uni-Stuttgart +*Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com), +*Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB +*/ + +#ifndef LEON_H_INCLUDE +#define LEON_H_INCLUDE + +#ifdef CONFIG_SPARC_LEON + +#define CONFIG_LEON +#define CONFIG_LEON_3 +#define SPARC_LEON_STATIC + +#define ASI_LEON_NOCACHE 0x01 + +#define ASI_LEON_DCACHE_MISS 0x1 + +#define ASI_LEON_CACHEREGS 0x02 +#define ASI_LEON_IFLUSH 0x10 +#define ASI_LEON_DFLUSH 0x11 + +#define ASI_LEON_MMUFLUSH 0x18 +#define ASI_LEON_MMUREGS 0x19 +#define ASI_LEON_BYPASS 0x1c +#define ASI_LEON_FLUSH_PAGE 0x10 + +/* mmu register access, ASI_LEON_MMUREGS */ +#define LEON_CNR_CTRL 0x000 +#define LEON_CNR_CTXP 0x100 +#define LEON_CNR_CTX 0x200 +#define LEON_CNR_F 0x300 +#define LEON_CNR_FADDR 0x400 + +#define LEON_CNR_CTX_NCTX 256 /*number of MMU ctx */ + +#define LEON_CNR_CTRL_TLBDIS 0x80000000 + +#define LEON_MMUTLB_ENT_MAX 64 + +/* + * diagnostic access from mmutlb.vhd: + * 0: pte address + * 4: pte + * 8: additional flags + */ +#define LEON_DIAGF_LVL 0x3 +#define LEON_DIAGF_WR 0x8 +#define LEON_DIAGF_WR_SHIFT 3 +#define LEON_DIAGF_HIT 0x10 +#define LEON_DIAGF_HIT_SHIFT 4 +#define LEON_DIAGF_CTX 0x1fe0 +#define LEON_DIAGF_CTX_SHIFT 5 +#define LEON_DIAGF_VALID 0x2000 +#define LEON_DIAGF_VALID_SHIFT 13 + +/* + * Interrupt Sources + * + * The interrupt source numbers directly map to the trap type and to + * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask, + * and the Interrupt Pending Registers. + */ +#define LEON_INTERRUPT_CORRECTABLE_MEMORY_ERROR 1 +#define LEON_INTERRUPT_UART_1_RX_TX 2 +#define LEON_INTERRUPT_UART_0_RX_TX 3 +#define LEON_INTERRUPT_EXTERNAL_0 4 +#define LEON_INTERRUPT_EXTERNAL_1 5 +#define LEON_INTERRUPT_EXTERNAL_2 6 +#define LEON_INTERRUPT_EXTERNAL_3 7 +#define LEON_INTERRUPT_TIMER1 8 +#define LEON_INTERRUPT_TIMER2 9 +#define LEON_INTERRUPT_EMPTY1 10 +#define LEON_INTERRUPT_EMPTY2 11 +#define LEON_INTERRUPT_OPEN_ETH 12 +#define LEON_INTERRUPT_EMPTY4 13 +#define LEON_INTERRUPT_EMPTY5 14 +#define LEON_INTERRUPT_EMPTY6 15 + +/* irq masks */ +#define LEON_HARD_INT(x) (1 << (x)) /* irq 0-15 */ +#define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */ +#define LEON_IRQPRIO_R 0xfffe0000 /* bit 31-17 of lregs.irqmask */ + +/* leon uart register definitions */ +#define LEON_OFF_UDATA 0x0 +#define LEON_OFF_USTAT 0x4 +#define LEON_OFF_UCTRL 0x8 +#define LEON_OFF_USCAL 0xc + +#define LEON_UCTRL_RE 0x01 +#define LEON_UCTRL_TE 0x02 +#define LEON_UCTRL_RI 0x04 +#define LEON_UCTRL_TI 0x08 +#define LEON_UCTRL_PS 0x10 +#define LEON_UCTRL_PE 0x20 +#define LEON_UCTRL_FL 0x40 +#define LEON_UCTRL_LB 0x80 + +#define LEON_USTAT_DR 0x01 +#define LEON_USTAT_TS 0x02 +#define LEON_USTAT_TH 0x04 +#define LEON_USTAT_BR 0x08 +#define LEON_USTAT_OV 0x10 +#define LEON_USTAT_PE 0x20 +#define LEON_USTAT_FE 0x40 + +#define LEON_MCFG2_SRAMDIS 0x00002000 +#define LEON_MCFG2_SDRAMEN 0x00004000 +#define LEON_MCFG2_SRAMBANKSZ 0x00001e00 /* [12-9] */ +#define LEON_MCFG2_SRAMBANKSZ_SHIFT 9 +#define LEON_MCFG2_SDRAMBANKSZ 0x03800000 /* [25-23] */ +#define LEON_MCFG2_SDRAMBANKSZ_SHIFT 23 + +#define LEON_TCNT0_MASK 0x7fffff + +#define LEON_USTAT_ERROR (LEON_USTAT_OV | LEON_USTAT_PE | LEON_USTAT_FE) +/*no break yet */ + +#ifndef __ASSEMBLY__ + +/* do a virtual address read without cache */ +static inline unsigned long leon_readnobuffer_reg(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : "r"(paddr), "i"(ASI_LEON_NOCACHE)); + return retval; +} + +/* do a physical address bypass write, i.e. for 0x80000000 */ +static inline void leon_store_reg(unsigned long paddr, unsigned long value) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : "r"(value), "r"(paddr), + "i"(ASI_LEON_BYPASS) : "memory"); +} + +/* do a physical address bypass load, i.e. for 0x80000000 */ +static inline unsigned long leon_load_reg(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : "r"(paddr), "i"(ASI_LEON_BYPASS)); + return retval; +} + +extern inline void leon_srmmu_disabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval |= LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + +extern inline void leon_srmmu_enabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval = retval & ~LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + +#define LEON3_BYPASS_LOAD_PA(x) (leon_load_reg((unsigned long)(x))) +#define LEON3_BYPASS_STORE_PA(x, v) (leon_store_reg((unsigned long)(x), (unsigned long)(v))) +#define LEON3_BYPASS_ANDIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) & v) +#define LEON3_BYPASS_ORIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) | v) +#define LEON_BYPASS_LOAD_PA(x) leon_load_reg((unsigned long)(x)) +#define LEON_BYPASSCACHE_LOAD_VA(x) leon_readnobuffer_reg((unsigned long)(x)) +#define LEON_BYPASS_STORE_PA(x, v) leon_store_reg((unsigned long)(x), (unsigned long)(v)) +#define LEON_REGLOAD_PA(x) leon_load_reg((unsigned long)(x)+LEON_PREGS) +#define LEON_REGSTORE_PA(x, v) leon_store_reg((unsigned long)(x)+LEON_PREGS, (unsigned long)(v)) +#define LEON_REGSTORE_OR_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) | (unsigned long)(v)) +#define LEON_REGSTORE_AND_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) & (unsigned long)(v)) + +#define HARDDBG_PRINTF(fmt, arg...) do { \ + char b[1000]; \ + sprintf(b, fmt, ## arg); \ + console_print_LEON(b); } while (0) +#define HARDDBG_FUNC \ + HARDDBG_PRINTF("[->%03d @ %22s()]:\n" , __LINE__, __func__); +#define HARDDBG_FUNCOUT \ + HARDDBG_PRINTF("[<-%03d @ %22s()]:\n" , __LINE__, __func__); +#define HARDDBG_OUT(fmt, arg...) \ + HARDDBG_PRINTF("[->%03d @ %22s()]:" fmt , __LINE__, __func__, ## arg); + +void console_print_LEON(const char *p); + +#endif /* !ASM */ + +/* + * The following defines the bits in the LEON UART Status Registers. + */ + +#define LEON_REG_UART_STATUS_DR 0x00000001 /* Data Ready */ +#define LEON_REG_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */ +#define LEON_REG_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */ +#define LEON_REG_UART_STATUS_BR 0x00000008 /* Break Error */ +#define LEON_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */ +#define LEON_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */ +#define LEON_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */ +#define LEON_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */ + +/* + * The following defines the bits in the LEON UART Ctrl Registers. + */ + +#define LEON_REG_UART_CTRL_RE 0x00000001 /* Receiver enable */ +#define LEON_REG_UART_CTRL_TE 0x00000002 /* Transmitter enable */ +#define LEON_REG_UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */ +#define LEON_REG_UART_CTRL_TI 0x00000008 /* Transmitter irq */ +#define LEON_REG_UART_CTRL_PS 0x00000010 /* Parity select */ +#define LEON_REG_UART_CTRL_PE 0x00000020 /* Parity enable */ +#define LEON_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */ +#define LEON_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */ + +#define LEON3_GPTIMER_EN 1 +#define LEON3_GPTIMER_RL 2 +#define LEON3_GPTIMER_LD 4 +#define LEON3_GPTIMER_IRQEN 8 +#define LEON3_GPTIMER_SEPIRQ 8 + +#define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */ +/* 0 = hold scalar and counter */ +#define LEON23_REG_TIMER_CONTROL_RL 0x00000002 /* 1 = reload at 0 */ + /* 0 = stop at 0 */ +#define LEON23_REG_TIMER_CONTROL_LD 0x00000004 /* 1 = load counter */ + /* 0 = no function */ +#define LEON23_REG_TIMER_CONTROL_IQ 0x00000008 /* 1 = irq enable */ + /* 0 = no function */ + +/* + * The following defines the bits in the LEON PS/2 Status Registers. + */ + +#define LEON_REG_PS2_STATUS_DR 0x00000001 /* Data Ready */ +#define LEON_REG_PS2_STATUS_PE 0x00000002 /* Parity error */ +#define LEON_REG_PS2_STATUS_FE 0x00000004 /* Framing error */ +#define LEON_REG_PS2_STATUS_KI 0x00000008 /* Keyboard inhibit */ +#define LEON_REG_PS2_STATUS_RF 0x00000010 /* RX buffer full */ +#define LEON_REG_PS2_STATUS_TF 0x00000020 /* TX buffer full */ + +/* + * The following defines the bits in the LEON PS/2 Ctrl Registers. + */ + +#define LEON_REG_PS2_CTRL_RE 0x00000001 /* Receiver enable */ +#define LEON_REG_PS2_CTRL_TE 0x00000002 /* Transmitter enable */ +#define LEON_REG_PS2_CTRL_RI 0x00000004 /* Keyboard receive irq */ +#define LEON_REG_PS2_CTRL_TI 0x00000008 /* Keyboard transmit irq */ + +#define LEON3_IRQMPSTATUS_CPUNR 28 +#define LEON3_IRQMPSTATUS_BROADCAST 27 + +#ifndef __ASSEMBLER__ + +struct amba_prom_registers { + unsigned int phys_addr; /* The physical address of this register */ + unsigned int reg_size; /* How many bytes does this register take up? */ +}; + +struct leon3_IrqCtrl_Regs_Map { + u32 ilevel; + u32 ipend; + u32 iforce; + u32 iclear; + u32 mpstatus; + u32 mpbroadcast; + u32 notused02; + u32 notused03; + u32 notused10; + u32 notused11; + u32 notused12; + u32 notused13; + u32 notused20; + u32 notused21; + u32 notused22; + u32 notused23; + u32 mask[16]; + u32 force[16]; + /* Extended IRQ registers */ + u32 intid[16]; /* 0xc0 */ +} ; + +struct leon3_APBUART_Regs_Map { + u32 data; + u32 status; + u32 ctrl; + u32 scaler; +} ; + +struct leon3_GpTimerElem_Regs_Map { + u32 val; + u32 rld; + u32 ctrl; + u32 unused; +} ; + +struct leon3_GpTimer_Regs_Map { + u32 scalar; + u32 scalar_reload; + u32 config; + u32 unused; + struct leon3_GpTimerElem_Regs_Map e[8]; +}; + +#define GPTIMER_CONFIG_IRQNT(a) (((a) >> 3) & 0x1f) +#define GPTIMER_CONFIG_ISSEP(a) ((a) & (1 << 8)) +#define GPTIMER_CONFIG_NTIMERS(a) ((a) & (0x7)) +#define LEON3_GPTIMER_CTRL_PENDING 0x10 +#define LEON3_GPTIMER_CONFIG_NRTIMERS(c) ((c)->config & 0x7) +#define LEON3_GPTIMER_CTRL_ISPENDING(r) (((r)&LEON3_GPTIMER_CTRL_PENDING) ? 1 : 0) + +/* + * Types and structure used for AMBA Plug & Play bus scanning + */ + +#define AMBA_MAXAPB_DEVS 64 +#define AMBA_MAXAPB_DEVS_PERBUS 16 + +struct amba_device_table { + int devnr; /* number of devices on AHB or APB bus */ + /* addresses to the devices configuration tables */ + unsigned int *addr[16]; + /* 0=unallocated, 1=allocated driver */ + unsigned int allocbits[1]; +}; + +struct amba_apbslv_device_table { + int devnr; /* number of devices on AHB or APB bus */ + /* addresses to the devices configuration tables */ + unsigned int *addr[AMBA_MAXAPB_DEVS]; + /* apb master if a entry is a apb slave */ + unsigned int apbmst[AMBA_MAXAPB_DEVS]; + /* apb master idx if a entry is a apb slave */ + unsigned int apbmstidx[AMBA_MAXAPB_DEVS]; + unsigned int allocbits[4];/* 0=unallocated, 1=allocated driver */ +}; + +struct amba_confarea_type { + struct amba_confarea_type *next;/* next bus in chain */ + struct amba_device_table ahbmst; + struct amba_device_table ahbslv; + struct amba_apbslv_device_table apbslv; + unsigned int apbmst; +}; + +/* collect apb slaves */ +struct amba_apb_device { + unsigned int start, irq, bus_id; + struct amba_confarea_type *bus; +}; + +/* collect ahb slaves */ +struct amba_ahb_device { + unsigned int start[4], irq, bus_id; + struct amba_confarea_type *bus; +}; + +extern void sparc_leon_eirq_register(int eirq); + +#if defined(CONFIG_SMP) +# define LEON3_IRQ_RESCHEDULE 13 +# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq) +# define LEON3_IRQ_CROSS_CALL 15 +#endif + +#define ASI_LEON3_SYSCTRL 0x02 +#define ASI_LEON3_SYSCTRL_ICFG 0x08 +#define ASI_LEON3_SYSCTRL_DCFG 0x0c +#define ASI_LEON3_SYSCTRL_CFG_SNOOPING (1 << 27) +#define ASI_LEON3_SYSCTRL_CFG_SSIZE(c) (1 << ((c >> 20) & 0xf)) + +extern inline unsigned long sparc_leon3_get_dcachecfg(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : + "r"(ASI_LEON3_SYSCTRL_DCFG), + "i"(ASI_LEON3_SYSCTRL)); + return retval; +} + +/*enable snooping*/ +extern inline void sparc_leon3_enable_snooping(void) +{ + __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" + "set 0x800000, %%l2\n\t" + "or %%l2, %%l1, %%l2\n\t" + "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); +}; + +extern inline void sparc_leon3_disable_cache(void) +{ + __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" + "set 0x00000f, %%l2\n\t" + "andn %%l2, %%l1, %%l2\n\t" + "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); +}; + +#endif /*!__ASSEMBLER__*/ + +#if defined(PAGE_SIZE_LEON_8K) +#define CONFIG_PAGE_SIZE_LEON 1 +#elif defined(PAGE_SIZE_LEON_16K) +#define CONFIG_PAGE_SIZE_LEON 2) +#else +#define CONFIG_PAGE_SIZE_LEON 0 +#endif + +#if CONFIG_PAGE_SIZE_LEON == 0 +/* [ 8, 6, 6 ] + 12 */ +#define LEON_PGD_SH 24 +#define LEON_PGD_M 0xff +#define LEON_PMD_SH 18 +#define LEON_PMD_SH_V (LEON_PGD_SH-2) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 12 +#define LEON_PTE_M 0x3f +#elif CONFIG_PAGE_SIZE_LEON == 1 +/* [ 7, 6, 6 ] + 13 */ +#define LEON_PGD_SH 25 +#define LEON_PGD_M 0x7f +#define LEON_PMD_SH 19 +#define LEON_PMD_SH_V (LEON_PGD_SH-1) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 13 +#define LEON_PTE_M 0x3f +#elif CONFIG_PAGE_SIZE_LEON == 2 +/* [ 6, 6, 6 ] + 14 */ +#define LEON_PGD_SH 26 +#define LEON_PGD_M 0x3f +#define LEON_PMD_SH 20 +#define LEON_PMD_SH_V (LEON_PGD_SH-0) +#define LEON_PMD_M 0x3f +#define LEON_PTE_SH 14 +#define LEON_PTE_M 0x3f +#elif CONFIG_PAGE_SIZE_LEON == 3 +/* [ 4, 7, 6 ] + 15 */ +#define LEON_PGD_SH 28 +#define LEON_PGD_M 0x0f +#define LEON_PMD_SH 21 +#define LEON_PMD_SH_V (LEON_PGD_SH-0) +#define LEON_PMD_M 0x7f +#define LEON_PTE_SH 15 +#define LEON_PTE_M 0x3f +#else +#error cannot determine CONFIG_PAGE_SIZE_LEON +#endif + +#define PAGE_MIN_SHIFT (12) +#define PAGE_MIN_SIZE (1UL << PAGE_MIN_SHIFT) + +#define LEON3_XCCR_SETS_MASK 0x07000000UL +#define LEON3_XCCR_SSIZE_MASK 0x00f00000UL + +#define LEON2_CCR_DSETS_MASK 0x03000000UL +#define LEON2_CFG_SSIZE_MASK 0x00007000UL + +#ifndef __ASSEMBLY__ +#define srmmu_hwprobe(addr) (srmmu_swprobe(addr, 0) & SRMMU_PTE_PMASK) +extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); +extern void leon_flush_icache_all(void); +extern void leon_flush_dcache_all(void); +extern void leon_flush_cache_all(void); +extern void leon_flush_tlb_all(void); +extern int leon_flush_during_switch; +extern int leon_flush_needed(void); + +/* struct that hold LEON3 cache configuration registers */ +struct leon3_cacheregs { /* ASI=2 Address - name */ + unsigned long ccr; /* 0x00 - Cache Control Register */ + /* 0x08 - Instruction Cache Configuration Register */ + unsigned long iccr; + unsigned long dccr; /* 0x0c - Data Cache Configuration Register */ +}; + +/* struct that hold LEON2 cache configuration register + & configuration register */ +struct leon2_cacheregs { + unsigned long ccr, cfg; +}; + +#endif + +#define LEON3_IO_AREA 0xfff00000 +#define LEON3_CONF_AREA 0xff000 +#define LEON3_AHB_SLAVE_CONF_AREA (1 << 11) + +#define LEON3_AHB_CONF_WORDS 8 +#define LEON3_APB_CONF_WORDS 2 +#define LEON3_AHB_MASTERS 16 +#define LEON3_AHB_SLAVES 16 +#define LEON3_APB_SLAVES 16 +#define LEON3_APBUARTS 8 + +/* Vendor codes */ +#define VENDOR_GAISLER 1 +#define VENDOR_PENDER 2 +#define VENDOR_ESA 4 +#define VENDOR_OPENCORES 8 + +/* Gaisler Research device id's */ +#define GAISLER_LEON3 0x003 +#define GAISLER_LEON3DSU 0x004 +#define GAISLER_ETHAHB 0x005 +#define GAISLER_APBMST 0x006 +#define GAISLER_AHBUART 0x007 +#define GAISLER_SRCTRL 0x008 +#define GAISLER_SDCTRL 0x009 +#define GAISLER_APBUART 0x00C +#define GAISLER_IRQMP 0x00D +#define GAISLER_AHBRAM 0x00E +#define GAISLER_GPTIMER 0x011 +#define GAISLER_PCITRG 0x012 +#define GAISLER_PCISBRG 0x013 +#define GAISLER_PCIFBRG 0x014 +#define GAISLER_PCITRACE 0x015 +#define GAISLER_PCIDMA 0x016 +#define GAISLER_AHBTRACE 0x017 +#define GAISLER_ETHDSU 0x018 +#define GAISLER_PIOPORT 0x01A +#define GAISLER_GRGPIO 0x01A +#define GAISLER_AHBJTAG 0x01c +#define GAISLER_ETHMAC 0x01D +#define GAISLER_AHB2AHB 0x020 +#define GAISLER_USBDC 0x021 +#define GAISLER_ATACTRL 0x024 +#define GAISLER_DDRSPA 0x025 +#define GAISLER_USBEHC 0x026 +#define GAISLER_USBUHC 0x027 +#define GAISLER_I2CMST 0x028 +#define GAISLER_SPICTRL 0x02D +#define GAISLER_DDR2SPA 0x02E +#define GAISLER_SPIMCTRL 0x045 +#define GAISLER_LEON4 0x048 +#define GAISLER_LEON4DSU 0x049 +#define GAISLER_AHBSTAT 0x052 +#define GAISLER_FTMCTRL 0x054 +#define GAISLER_KBD 0x060 +#define GAISLER_VGA 0x061 +#define GAISLER_SVGA 0x063 +#define GAISLER_GRSYSMON 0x066 +#define GAISLER_GRACECTRL 0x067 + +#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */ +#define GAISLER_L2C 0xffe /* internal device: leon2compat */ +#define GAISLER_PLUGPLAY 0xfff /* internal device: plug & play configarea */ + +#define amba_vendor(x) (((x) >> 24) & 0xff) + +#define amba_device(x) (((x) >> 12) & 0xfff) + +/* macros used in leon_m.c */ +#define PFN(x) ((x) >> PAGE_SHIFT) +#define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base))) +#define _SRMMU_PTE_PMASK_LEON 0xffffffff + +#else /* defined(CONFIG_SPARC_LEON) */ + +#define SPARC_LEON_STATIC static + +#endif /* !defined(CONFIG_SPARC_LEON) */ + +#endif diff --git a/arch/sparc/kernel/leon_k.c b/arch/sparc/kernel/leon_k.c new file mode 100644 index 0000000..cda0043 --- /dev/null +++ b/arch/sparc/kernel/leon_k.c @@ -0,0 +1,195 @@ +/* Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com), + Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prom.h" +#include "irq.h" + +struct leon3_IrqCtrl_Regs_Map *LEON3_IrqCtrl_Regs; /* interrupt controller base address, initialized by amba_init() */ +struct leon3_GpTimer_Regs_Map *LEON3_GpTimer_Regs; /* timer controller base address, initialized by amba_init() */ +struct amba_apb_device leon_percpu_timer_dev[16]; +#define LEON3_SMPTicker_Regs \ + ((struct leon3_GpTimer_Regs_Map *)leon_percpu_timer_dev[0].start) +int leondebug_irq_disable; +int leon_debug_irqout; +static int dummy_master_l10_counter; + +unsigned long LEON3_GpTimer_Irq; /* interrupt controller irq number, initialized by amba_init() */ +unsigned int sparc_leon_eirq; +#define LEON_IMASK ((&LEON3_IrqCtrl_Regs->mask[0])) + +/* Return the IRQ of the pending IRQ on the extended IRQ controller */ +int sparc_leon_eirq_get(int eirq, int cpu) +{ + return LEON3_BYPASS_LOAD_PA(&LEON3_IrqCtrl_Regs->intid[cpu]) & 0x1f; +} + +irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id) +{ + printk(KERN_ERR "sparc_leon_eirq_isr: ERROR EXTENDED IRQ\n"); + return IRQ_HANDLED; +} + +/* The extended IRQ controller has been found, this function registers it */ +void sparc_leon_eirq_register(int eirq) +{ + int irq; + + /* Register a "BAD" handler for this interrupt, + it should never happen */ + irq = request_irq(eirq, sparc_leon_eirq_isr, + (IRQF_DISABLED | SA_STATIC_ALLOC), "extirq", NULL); + + if (irq) { + printk(KERN_ERR + "sparc_leon_eirq_register: unable to attach IRQ%d\n", + eirq); + } else { + sparc_leon_eirq = eirq; + } + +} + +static inline unsigned long get_irqmask(unsigned int irq) +{ + unsigned long mask; + + if (!irq || ((irq > 0xf) && !sparc_leon_eirq) + || ((irq > 0x1f) && sparc_leon_eirq)) { + printk(KERN_ERR + "leon_get_irqmask: false irq number: %d\n", irq); + mask = 0; + } else { + mask = LEON_HARD_INT(irq); + } + return mask; +} + +static void leon_enable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask))); + local_irq_restore(flags); +} + +static void leon_disable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask))); + local_irq_restore(flags); + +} + +void __init leon_init_timers(irq_handler_t counter_fn) +{ + int irq; + + leondebug_irq_disable = 0; + leon_debug_irqout = 0; + master_l10_counter = &dummy_master_l10_counter; + dummy_master_l10_counter = 0; + + if (LEON3_GpTimer_Regs && LEON3_IrqCtrl_Regs) { + LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs->e[0].val, 0); + LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs->e[0].rld, + (((1000000 / 100) - 1))); + LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs->e[0].ctrl, 0); + + } else { + while (1) + printk(KERN_ERR "No Timer/irqctrl found\n"); + } + + irq = request_irq(LEON3_GpTimer_Irq, + counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); + + if (irq) { + printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n", + LEON_INTERRUPT_TIMER1); + prom_halt(); + } + + if (LEON3_GpTimer_Regs) { + LEON3_BYPASS_STORE_PA(&LEON3_GpTimer_Regs->e[0].ctrl, + LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | + LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); + } +} + +void leon_clear_clock_irq(void) +{ +} + +void leon_load_profile_irq(int cpu, unsigned int limit) +{ + BUG(); +} + +void _amba_init(struct device_node *dp, struct device_node ***nextp); + + + +void __init leon_trans_init(struct device_node *dp) +{ + if (strcmp(dp->type, "cpu") == 0 && strcmp(dp->name, "") == 0) { + struct property *p; + p = of_find_property(dp, "mid", 0); + if (p) { + int mid; + dp->name = prom_early_alloc(5 + 1); + memcpy(&mid, p->value, p->length); + sprintf((char *)dp->name, "cpu%.2d", mid); + } + } +} + +void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) +{ + if (strcmp(dp->type, "ambapp") == 0 && + strcmp(dp->name, "ambapp0") == 0) { + _amba_init(dp, nextp); + } +} + +void __init leon_init_IRQ(void) +{ + sparc_init_timers = leon_init_timers; + + BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, + BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(load_profile_irq, leon_load_profile_irq, + BTFIXUPCALL_NOP); + +#ifdef CONFIG_SMP + BTFIXUPSET_CALL(set_cpu_int, leon_set_cpu_int, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(clear_cpu_int, leon_clear_ipi, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(set_irq_udt, leon_set_udt, BTFIXUPCALL_NORM); +#endif + +} diff --git a/arch/sparc/mm/leon_m.c b/arch/sparc/mm/leon_m.c new file mode 100644 index 0000000..ef66716 --- /dev/null +++ b/arch/sparc/mm/leon_m.c @@ -0,0 +1,254 @@ +/* + * linux/arch/sparc/mm/leon.c + * + * Copyright (C) 2004 Konrad Eisele + * (eiselekd@web.de, konrad@gaisler.com), Gaisler Research + * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com), + * Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB + * + * do srmmu probe in software + */ + +#include +#include +#include +#include + +int leon_flush_during_switch = 1; + +extern unsigned long last_valid_pfn; + +int srmmu_swprobe_trace; +unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) +{ + + unsigned int ctxtbl; + unsigned int pgd, pmd, ped; + unsigned int ptr; + unsigned int lvl, pte, paddrbase; + unsigned int ctx; + unsigned int paddr_calc; + + paddrbase = 0; + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: trace on\n"); + + ctxtbl = srmmu_get_ctable_ptr(); + if (!(ctxtbl)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: srmmu_get_ctable_ptr returned 0=>0\n"); + return 0; + } + if (!_pfn_valid(PFN(ctxtbl))) { + if (srmmu_swprobe_trace) + printk(KERN_INFO + "swprobe: !_pfn_valid(%x)=>0\n", + PFN(ctxtbl)); + return 0; + } + + ctx = srmmu_get_context(); + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- ctx (%x) ---\n", ctx); + + pgd = LEON_BYPASS_LOAD_PA(ctxtbl + (ctx * 4)); + + if (((pgd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pgd is entry level 3\n"); + lvl = 3; + pte = pgd; + paddrbase = pgd & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((pgd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pgd is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- pgd (%x) ---\n", pgd); + + ptr = (pgd & SRMMU_PTD_PMASK) << 4; + ptr += ((((vaddr) >> LEON_PGD_SH) & LEON_PGD_M) * 4); + if (!_pfn_valid(PFN(ptr))) + return 0; + + pmd = LEON_BYPASS_LOAD_PA(ptr); + if (((pmd & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pmd is entry level 2\n"); + lvl = 2; + pte = pmd; + paddrbase = pmd & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((pmd & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: pmd is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- pmd (%x) ---\n", pmd); + + ptr = (pmd & SRMMU_PTD_PMASK) << 4; + ptr += (((vaddr >> LEON_PMD_SH) & LEON_PMD_M) * 4); + if (!_pfn_valid(PFN(ptr))) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: !_pfn_valid(%x)=>0\n", + PFN(ptr)); + return 0; + } + + ped = LEON_BYPASS_LOAD_PA(ptr); + + if (((ped & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ped is entry level 1\n"); + lvl = 1; + pte = ped; + paddrbase = ped & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (((ped & SRMMU_ET_MASK) != SRMMU_ET_PTD)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ped is invalid => 0\n"); + return 0; + } + + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: --- ped (%x) ---\n", ped); + + ptr = (ped & SRMMU_PTD_PMASK) << 4; + ptr += (((vaddr >> LEON_PTE_SH) & LEON_PTE_M) * 4); + if (!_pfn_valid(PFN(ptr))) + return 0; + + ptr = LEON_BYPASS_LOAD_PA(ptr); + if (((ptr & SRMMU_ET_MASK) == SRMMU_ET_PTE)) { + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ptr is entry level 0\n"); + lvl = 0; + pte = ptr; + paddrbase = ptr & _SRMMU_PTE_PMASK_LEON; + goto ready; + } + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: ptr is invalid => 0\n"); + return 0; + +ready: + switch (lvl) { + case 0: + paddr_calc = + (vaddr & ~(-1 << LEON_PTE_SH)) | ((pte & ~0xff) << 4); + break; + case 1: + paddr_calc = + (vaddr & ~(-1 << LEON_PMD_SH)) | ((pte & ~0xff) << 4); + break; + case 2: + paddr_calc = + (vaddr & ~(-1 << LEON_PGD_SH)) | ((pte & ~0xff) << 4); + break; + default: + case 3: + paddr_calc = vaddr; + break; + } + if (srmmu_swprobe_trace) + printk(KERN_INFO "swprobe: padde %x\n", paddr_calc); + if (paddr) + *paddr = paddr_calc; + return paddrbase; +} + +void leon_flush_icache_all(void) +{ + __asm__ __volatile__(" flush "); /*iflush*/ +} + +void leon_flush_dcache_all(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i"(ASI_LEON_DFLUSH) : "memory"); +} + +void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_flags & VM_EXEC) + leon_flush_icache_all(); + leon_flush_dcache_all(); +} + +void leon_flush_cache_all(void) +{ + __asm__ __volatile__(" flush "); /*iflush*/ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i"(ASI_LEON_DFLUSH) : "memory"); +} + +void leon_flush_tlb_all(void) +{ + leon_flush_cache_all(); + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r"(0x400), + "i"(ASI_LEON_MMUFLUSH) : "memory"); +} + +/* get all cache regs */ +void leon3_getCacheRegs(struct leon3_cacheregs *regs) +{ + unsigned long ccr, iccr, dccr; + + if (!regs) + return; + /* Get Cache regs from "Cache ASI" address 0x0, 0x8 and 0xC */ + __asm__ __volatile__("lda [%%g0] %3, %0\n\t" + "mov 0x08, %%g1\n\t" + "lda [%%g1] %3, %1\n\t" + "mov 0x0c, %%g1\n\t" + "lda [%%g1] %3, %2\n\t" + : "=r"(ccr), "=r"(iccr), "=r"(dccr) + /* output */ + : "i"(ASI_LEON_CACHEREGS) /* input */ + : "g1" /* clobber list */ + ); + regs->ccr = ccr; + regs->iccr = iccr; + regs->dccr = dccr; +} + +/* Due to virtual cache we need to check cache configuration if + * it is possible to skip flushing in some cases. + * + * Leon2 and Leon3 differ in their way of telling cache information + * + */ +int leon_flush_needed(void) +{ + int flush_needed = -1; + unsigned int ssize, sets; + char *setStr[4] = + { "direct mapped", "2-way associative", "3-way associative", + "4-way associative" + }; + /* leon 3 */ + struct leon3_cacheregs cregs; + leon3_getCacheRegs(&cregs); + sets = (cregs.dccr & LEON3_XCCR_SETS_MASK) >> 24; + /* (ssize=>realsize) 0=>1k, 1=>2k, 2=>4k, 3=>8k ... */ + ssize = 1 << ((cregs.dccr & LEON3_XCCR_SSIZE_MASK) >> 20); + + printk(KERN_INFO "CACHE: %s cache, set size %dk\n", + sets > 3 ? "unknown" : setStr[sets], ssize); + if ((ssize <= (PAGE_SIZE / 1024)) && (sets == 0)) { + /* Set Size <= Page size ==> + flush on every context switch not needed. */ + flush_needed = 0; + printk(KERN_INFO "CACHE: not flushing on every context switch\n"); + } + return flush_needed; +}