From: Stefan Holst <mail@s-holst.de>
To: sparclinux@vger.kernel.org
Subject: leon support - first proposal
Date: Sat, 03 Apr 2004 00:17:36 +0000 [thread overview]
Message-ID: <20040403001736.GA7330@spike> (raw)
hello!
thanks for merging my patches. just tested rc3 and it works
fine here :)
here is now a first proposal for actual leon support.
it has now a very low impact on existing code (mostly adding
some id's and a few branches for leon).
currently the kernel has to be explicitely configured
for leon architecture (like sun4). this has two reasons:
- gaisler research has received its official implementors
id (0xf) quite recently and this id is still undefined in
latest leon release
- there is an asi code which differs from srmmu and currently
redefined in asi.h
actually there are some more nonstandard asi codes in leon
but these aren't used very often or not at all. ASI_M_MMUREGS
however seems to be used a lot and much code has to be added
to circumvent this redefinition.
if this asi.h change is a showstopper, however, i'll try to remove it.
what do you think anout this patch? are there any issues left
which need to be fixed?
diff -urN a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
--- a/drivers/sbus/sbus.c 2003-11-26 21:43:39.000000000 +0100
+++ b/drivers/sbus/sbus.c 2004-04-03 00:58:21.519621328 +0200
@@ -354,6 +354,8 @@
(nd = prom_searchsiblings(nd, "sbi")) = 0) {
panic("sbi not found");
}
+ } else if(sparc_cpu_model = sparc_leon) {
+ return 0;
} else if((nd = prom_searchsiblings(topnd, "sbus")) = 0) {
if((iommund = prom_searchsiblings(topnd, "iommu")) = 0 ||
(nd = prom_getchild(iommund)) = 0 ||
diff -urN a/include/asm-sparc/asi.h b/include/asm-sparc/asi.h
--- a/include/asm-sparc/asi.h 2003-11-26 21:43:51.000000000 +0100
+++ b/include/asm-sparc/asi.h 2004-04-03 01:06:44.762116840 +0200
@@ -108,4 +108,10 @@
#define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */
+/* FIXME: non-standard Leon ASI definition */
+#ifdef CONFIG_LEON
+#undef ASI_M_MMUREGS
+#define ASI_M_MMUREGS 0x19
+#endif /* CONFIG_LEON */
+
#endif /* _SPARC_ASI_H */
diff -urN a/include/asm-sparc/machines.h b/include/asm-sparc/machines.h
--- a/include/asm-sparc/machines.h 2003-11-26 21:42:50.000000000 +0100
+++ b/include/asm-sparc/machines.h 2004-04-03 00:58:21.521621024 +0200
@@ -15,7 +15,7 @@
/* Current number of machines we know about that has an IDPROM
* machtype entry including one entry for the 0x80 OBP machines.
*/
-#define NUM_SUN_MACHINES 15
+#define NUM_SUN_MACHINES 16
extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
@@ -32,6 +32,7 @@
#define SM_ARCH_MASK 0xf0
#define SM_SUN4 0x20
+#define M_LEON2 0x30
#define SM_SUN4C 0x50
#define SM_SUN4M 0x70
#define SM_SUN4M_OBP 0x80
@@ -43,6 +44,9 @@
#define SM_4_330 0x03 /* Sun 4/300 series */
#define SM_4_470 0x04 /* Sun 4/400 series */
+/* Leon machines */
+#define M_LEON2_SOC 0x01 /* Leon2 SoC */
+
/* Sun4c machines Full Name - PROM NAME */
#define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */
#define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */
diff -urN a/include/asm-sparc/system.h b/include/asm-sparc/system.h
--- a/include/asm-sparc/system.h 2004-03-11 11:33:04.000000000 +0100
+++ b/include/asm-sparc/system.h 2004-04-03 00:58:21.521621024 +0200
@@ -29,6 +29,7 @@
sun4u = 0x05, /* V8 ploos ploos */
sun_unknown = 0x06,
ap1000 = 0x07, /* almost a sun4m */
+ sparc_leon = 0x08, /* Leon2 SoC */
};
/* Really, userland should not be looking at any of this... */
diff -urN a/arch/sparc/Kconfig b/arch/sparc/Kconfig
--- a/arch/sparc/Kconfig 2004-03-30 16:55:31.000000000 +0200
+++ b/arch/sparc/Kconfig 2004-04-03 00:58:21.511622544 +0200
@@ -226,6 +226,14 @@
a kernel compiled with this option will run only on sun4.
(And the current version will probably work only on sun4/330.)
+config LEON
+ bool "Running on SoC 'Leon', the open source sparc VHDL model"
+ help
+ Say Y here if you want to run linux on the Leon System-on-a-Chip
+ platform. For information go to www.gaisler.com. Download the VHDL
+ source and use the instruction level Leon sparc-simulator "tsim" which
+ is free for private use.
+
if !SUN4
config PCI
diff -urN a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile 2004-02-29 23:36:16.000000000 +0100
+++ b/arch/sparc/kernel/Makefile 2004-04-03 00:58:21.511622544 +0200
@@ -6,7 +6,7 @@
EXTRA_AFLAGS := -ansi
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
+IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o leon_irq.o
obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
process.o signal.o ioport.o setup.o idprom.o \
sys_sparc.o sunos_asm.o systbls.o \
diff -urN a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
--- a/arch/sparc/kernel/auxio.c 2003-11-26 21:44:52.000000000 +0100
+++ b/arch/sparc/kernel/auxio.c 2004-04-03 00:58:21.511622544 +0200
@@ -29,6 +29,7 @@
switch (sparc_cpu_model) {
case sun4d:
case sun4:
+ case sparc_leon:
return;
default:
break;
diff -urN a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
--- a/arch/sparc/kernel/cpu.c 2004-03-30 16:55:31.000000000 +0200
+++ b/arch/sparc/kernel/cpu.c 2004-04-03 01:03:39.863225744 +0200
@@ -73,6 +73,9 @@
{ 5, 6, "reserved"},
{ 5, 7, "No FPU"},
{ 9, 3, "Fujitsu or Weitek on-chip FPU"},
+ /* Leon */
+ { 0xf, 0, "Meiko FPU"},
+ { 0xf, 1, "GRFPU"},
};
#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -117,7 +120,9 @@
{ 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
{ 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
{ 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ /* Leon */
+ { 0xf, 2, "Gaisler Research - Leon2 SoC"},
+ { 0xf, 3, "Gaisler Research - Leon3 SoC"},
};
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
@@ -134,10 +139,14 @@
psr_impl = ((get_psr()>>28)&0xf);
psr_vers = ((get_psr()>>24)&0xf);
+#ifdef CONFIG_LEON
+ psr_impl = 0xf; /* hardcoded ids for older models/simulators */
+ psr_vers = 2;
+#endif
psr = get_psr();
put_psr(psr | PSR_EF);
- fpu_vers = ((get_fsr()>>17)&0x7);
+ fpu_vers = (get_psr() & PSR_EF) ? ((get_fsr()>>17)&0x7) : 7;
put_psr(psr);
for(i = 0; i<NSPARCCHIPS; i++) {
diff -urN a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
--- a/arch/sparc/kernel/head.S 2004-03-11 11:32:58.000000000 +0100
+++ b/arch/sparc/kernel/head.S 2004-04-03 00:58:21.513622240 +0200
@@ -838,6 +838,8 @@
cmp %l1, ' '
be 1f
+ cmp %l1, '2' ! leon2 or compatible
+ be 1f
cmp %l1, 'c'
be 1f
cmp %l1, 'm'
@@ -860,6 +862,8 @@
be sun4m_init
cmp %l1, 'd' ! Let us see how the beast will die
be sun4d_init
+ cmp %l1, '2' ! leon2 or compatible
+ be sun4c_continue_boot
nop
/* Jump into mmu context zero. */
diff -urN a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
--- a/arch/sparc/kernel/idprom.c 2003-11-26 21:43:25.000000000 +0100
+++ b/arch/sparc/kernel/idprom.c 2004-04-03 00:58:21.513622240 +0200
@@ -31,6 +31,8 @@
{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+/* Now Leon */
+{ "Leon2 System-on-a-Chip", (M_LEON2 | M_LEON2_SOC) },
/* Now, Sun4c's */
{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
diff -urN a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
--- a/arch/sparc/kernel/irq.c 2004-03-11 11:32:58.000000000 +0100
+++ b/arch/sparc/kernel/irq.c 2004-04-03 00:58:21.514622088 +0200
@@ -579,6 +579,7 @@
extern void sun4c_init_IRQ( void );
extern void sun4m_init_IRQ( void );
extern void sun4d_init_IRQ( void );
+ extern void leon_init_IRQ(void);
switch(sparc_cpu_model) {
case sun4c:
@@ -586,6 +587,10 @@
sun4c_init_IRQ();
break;
+ case sparc_leon:
+ leon_init_IRQ();
+ break;
+
case sun4m:
#ifdef CONFIG_PCI
pcic_probe();
diff -urN a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c 2004-03-30 16:55:31.000000000 +0200
+++ b/arch/sparc/kernel/setup.c 2004-04-03 00:58:21.515621936 +0200
@@ -274,6 +274,7 @@
if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
+ if(!strcmp(&cputypval,"leon2")) { sparc_cpu_model=sparc_leon; }
#ifdef CONFIG_SUN4
if (sparc_cpu_model != sun4) {
@@ -281,6 +282,13 @@
prom_halt();
}
#endif
+#ifdef CONFIG_LEON
+ /* FIXME: psr ids, asi codes */
+ if (sparc_cpu_model != sparc_leon) {
+ prom_printf("This kernel is for Leon architecture only.\n");
+ prom_halt();
+ }
+#endif
printk("ARCH: ");
switch(sparc_cpu_model) {
case sun4:
@@ -301,6 +309,9 @@
case sun4u:
printk("SUN4U\n");
break;
+ case sparc_leon:
+ printk("LEON\n");
+ break;
default:
printk("UNKNOWN!\n");
break;
diff -urN a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
--- a/arch/sparc/kernel/time.c 2004-03-11 11:32:58.000000000 +0100
+++ b/arch/sparc/kernel/time.c 2004-04-03 00:58:21.516621784 +0200
@@ -43,6 +43,7 @@
#include <asm/sun4paddr.h>
#include <asm/page.h>
#include <asm/pcic.h>
+#include <asm/leon.h>
extern unsigned long wall_jiffies;
@@ -309,6 +310,9 @@
case sun4d:
node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus"));
break;
+ case sparc_leon:
+ node = 0;
+ return;
default:
prom_printf("CLOCK: Unsupported architecture!\n");
prom_halt();
@@ -393,6 +397,11 @@
clock_probe();
sparc_init_timers(timer_interrupt);
+
+ if (sparc_cpu_model = sparc_leon) {
+ local_irq_enable();
+ return;
+ }
#ifdef CONFIG_SUN4
if(idprom->id_machtype = (SM_SUN4 | SM_4_330)) {
@@ -469,6 +478,10 @@
extern __inline__ unsigned long do_gettimeoffset(void)
{
+ if (sparc_cpu_model = sparc_leon)
+ return ((LEON_REGLOAD_PA(LEON_TRLD0)&LEON_TCNT0_MASK) -
+ (LEON_REGLOAD_PA(LEON_TCNT0)&LEON_TCNT0_MASK)) >> 2;
+
return (*master_l10_counter >> 10) & 0x1fffff;
}
diff -urN a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
--- a/arch/sparc/mm/Makefile 2003-11-26 21:44:42.000000000 +0100
+++ b/arch/sparc/mm/Makefile 2004-04-03 00:58:21.516621784 +0200
@@ -21,3 +21,7 @@
else
obj-y += sun4c.o
endif
+
+ifdef CONFIG_LEON
+obj-y += leon.o
+endif
diff -urN a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c 2004-03-30 16:55:31.000000000 +0200
+++ b/arch/sparc/mm/init.c 2004-04-03 00:58:21.516621784 +0200
@@ -32,6 +32,7 @@
#include <asm/vaddrs.h>
#include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */
#include <asm/tlb.h>
+#include <asm/leon.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -324,6 +325,7 @@
break;
case sun4m:
case sun4d:
+ case sparc_leon:
srmmu_paging_init();
sparc_unmapped_base = 0x50000000;
BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
diff -urN a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c
--- a/arch/sparc/mm/loadmmu.c 2003-11-26 21:44:31.000000000 +0100
+++ b/arch/sparc/mm/loadmmu.c 2004-04-03 00:58:21.517621632 +0200
@@ -36,6 +36,7 @@
break;
case sun4m:
case sun4d:
+ case sparc_leon:
ld_mmu_srmmu();
break;
default:
diff -urN a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c 2004-04-01 16:08:16.000000000 +0200
+++ b/arch/sparc/mm/srmmu.c 2004-04-03 01:00:25.442782144 +0200
@@ -48,6 +48,7 @@
#include <asm/tsunami.h>
#include <asm/swift.h>
#include <asm/turbosparc.h>
+#include <asm/leon.h>
#include <asm/btfixup.h>
@@ -1269,7 +1270,11 @@
srmmu_nocache_calcsize();
srmmu_nocache_init();
- srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE));
+ if (sparc_cpu_model = sparc_leon) {
+ leon_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE));
+ } else {
+ srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE));
+ }
map_kernel();
/* ctx table has to be physically aligned to its size */
@@ -1966,6 +1971,123 @@
poke_srmmu = poke_viking;
}
+void __init leon_inherit_prom_mappings(unsigned long start,unsigned long end)
+{
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+ int what = 0; /* 0 = normal-pte, 1 = pmd-level pte, 2 = pgd-level pte */
+ unsigned long prompte;
+
+ while(start <= end) {
+ if (start = 0)
+ break; /* probably wrap around */
+ if(start = 0xfef00000)
+ start = KADB_DEBUGGER_BEGVM;
+ if(!(prompte = srmmu_swprobe(start,0))) {
+ start += PAGE_SIZE;
+ continue;
+ }
+
+ /* A red snapper, see what it really is. */
+ what = 0;
+
+ if(!(start & ~(SRMMU_PMD_MASK))) {
+ if(srmmu_swprobe((start-PAGE_SIZE) + SRMMU_PMD_SIZE, 0) = prompte)
+ what = 1;
+ }
+
+ if(!(start & ~(SRMMU_PGDIR_MASK))) {
+ if(srmmu_swprobe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE, 0) =
+ prompte)
+ what = 2;
+ }
+
+ pgdp = pgd_offset_k(start);
+ if(what = 2) {
+ *(pgd_t *)__nocache_fix(pgdp) = __pgd(prompte);
+ start += SRMMU_PGDIR_SIZE;
+ continue;
+ }
+ if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) {
+ pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE);
+ if (pmdp = NULL)
+ early_pgtable_allocfail("pmd");
+ memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE);
+ srmmu_pgd_set(__nocache_fix(pgdp), pmdp);
+ }
+ pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start);
+ if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) {
+ ptep = (pte_t *) __srmmu_get_nocache(SRMMU_PTE_SZ_SOFT,
+ SRMMU_PTE_SZ_SOFT);
+ if (ptep = NULL)
+ early_pgtable_allocfail("pte");
+ memset(__nocache_fix(ptep), 0, SRMMU_PTE_SZ_SOFT);
+ srmmu_pmd_set(__nocache_fix(pmdp), ptep);
+ }
+ if(what = 1) {
+ /*
+ * We bend the rule where all 16 PTPs in a pmd_t point
+ * inside the same PTE page, and we leak a perfectly
+ * good hardware PTE piece. Alternatives seem worse.
+ */
+ unsigned int x; /* Index of HW PMD in soft cluster */
+ x = (start >> SRMMU_PMD_SHIFT) & 15;
+ *(unsigned long *)__nocache_fix(&pmdp->pmdv[x]) = prompte;
+ start += SRMMU_PMD_SIZE;
+ continue;
+ }
+ ptep = srmmu_pte_offset(__nocache_fix(pmdp), start);
+ *(pte_t *)__nocache_fix(ptep) = __pte(prompte);
+ start += PAGE_SIZE;
+ }
+}
+
+void leon_flush_cache_all (void)
+{
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t": :
+ "i" (ASI_LEON_IFLUSH) : "memory");
+ __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");
+}
+
+static void __init poke_leonsparc(void)
+{
+}
+
+static void __init init_leon(void) {
+
+ srmmu_name = "Leon2";
+
+ BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_mm, leon_flush_cache_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_page, leon_flush_cache_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_range, leon_flush_cache_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_page_for_dma, leon_flush_cache_all, BTFIXUPCALL_NORM);
+
+ BTFIXUPSET_CALL(flush_tlb_all, leon_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_mm, leon_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_page, leon_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_range, leon_flush_tlb_all, BTFIXUPCALL_NORM);
+
+ BTFIXUPSET_CALL(__flush_page_to_ram, leon_flush_cache_all, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(flush_sig_insns, leon_flush_cache_all, BTFIXUPCALL_NOP);
+
+ poke_srmmu = poke_leonsparc;
+
+ srmmu_cache_pagetables = 0;
+}
+
+
+
/* Probe for the srmmu chip version. */
static void __init get_srmmu_type(void)
{
@@ -1975,11 +2097,20 @@
srmmu_modtype = SRMMU_INVAL_MOD;
hwbug_bitmask = 0;
- mreg = srmmu_get_mmureg(); psr = get_psr();
- mod_typ = (mreg & 0xf0000000) >> 28;
- mod_rev = (mreg & 0x0f000000) >> 24;
+ psr = get_psr();
psr_typ = (psr >> 28) & 0xf;
psr_vers = (psr >> 24) & 0xf;
+#ifdef CONFIG_LEON
+ psr_typ = 0xf; /* hardcoded ids for older models/simulators */
+ psr_vers = 2;
+#endif
+ if(psr_typ = 0xf) {
+ init_leon();
+ return;
+ }
+ mreg = srmmu_get_mmureg();
+ mod_typ = (mreg & 0xf0000000) >> 28;
+ mod_rev = (mreg & 0x0f000000) >> 24;
/* First, check for HyperSparc or Cypress. */
if(mod_typ = 1) {
diff -urN a/include/asm-sparc/leon.h b/include/asm-sparc/leon.h
--- a/include/asm-sparc/leon.h 1970-01-01 01:00:00.000000000 +0100
+++ b/include/asm-sparc/leon.h 2004-04-03 00:58:21.520621176 +0200
@@ -0,0 +1,217 @@
+/* Konrad Eisele<eiselekd@web.de>, 2003: include/asm/leon.h */
+
+#ifndef LEON_H_INCLUDE
+#define LEON_H_INCLUDE
+
+#include <linux/config.h>
+#include <asm/vaddrs.h>
+
+/* memory mapped leon control registers */
+#define LEON_PREGS 0x80000000
+#define LEON_MCFG1 0x00
+#define LEON_MCFG2 0x04
+#define LEON_ECTRL 0x08
+#define LEON_FADDR 0x0c
+#define LEON_MSTAT 0x10
+#define LEON_CCTRL 0x14
+#define LEON_PWDOWN 0x18
+#define LEON_WPROT1 0x1C
+#define LEON_WPROT2 0x20
+#define LEON_LCONF 0x24
+#define LEON_TCNT0 0x40
+#define LEON_TRLD0 0x44
+#define LEON_TCTRL0 0x48
+#define LEON_TCNT1 0x50
+#define LEON_TRLD1 0x54
+#define LEON_TCTRL1 0x58
+#define LEON_SCNT 0x60
+#define LEON_SRLD 0x64
+#define LEON_UART0 0x70
+#define LEON_UDATA0 0x70
+#define LEON_USTAT0 0x74
+#define LEON_UCTRL0 0x78
+#define LEON_USCAL0 0x7c
+#define LEON_UART1 0x80
+#define LEON_UDATA1 0x80
+#define LEON_USTAT1 0x84
+#define LEON_UCTRL1 0x88
+#define LEON_USCAL1 0x8c
+#define LEON_IMASK 0x90
+#define LEON_IPEND 0x94
+#define LEON_IFORCE 0x98
+#define LEON_ICLEAR 0x9c
+#define LEON_IOREG 0xA0
+#define LEON_IODIR 0xA4
+#define LEON_IOICONF 0xA8
+#define LEON_IPEND2 0xB0
+#define LEON_IMASK2 0xB4
+#define LEON_ISTAT2 0xB8
+#define LEON_ICLEAR2 0xBC
+
+/* ASI codes */
+#define ASI_LEON_PCI 0x04
+#define ASI_LEON_IFLUSH 0x05
+#define ASI_LEON_DFLUSH 0x06
+#define ASI_LEON_ITAG 0x0c
+#define ASI_LEON_IDATA 0x0d
+#define ASI_LEON_DTAG 0x0e
+#define ASI_LEON_DDATA 0x0f
+#define ASI_LEON_MMUFLUSH 0x18
+#define ASI_LEON_MMUREGS 0x19
+#define ASI_LEON_BYPASS 0x1c
+#define ASI_LEON_FLUSH_PAGE 0x10
+/*
+#define ASI_LEON_FLUSH_SEGMENT 0x11
+#define ASI_LEON_FLUSH_REGION 0x12
+*/
+#define ASI_LEON_FLUSH_CTX 0x13
+#define ASI_LEON_DCTX 0x14
+#define ASI_LEON_ICTX 0x15
+#define ASI_MMU_DIAG 0x1d
+
+/* 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*/
+
+#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
+
+#ifndef __ASSEMBLY__
+
+/* 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 LEON_BYPASS_LOAD_PA(x) leon_load_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))
+
+extern unsigned long srmmu_swprobe(unsigned long vaddr,unsigned long *paddr);
+extern void leon_inherit_prom_mappings(unsigned long start,unsigned long end);
+
+#endif /* !ASM */
+#endif
diff -urN a/arch/sparc/kernel/leon_irq.c b/arch/sparc/kernel/leon_irq.c
--- a/arch/sparc/kernel/leon_irq.c 1970-01-01 01:00:00.000000000 +0100
+++ b/arch/sparc/kernel/leon_irq.c 2004-04-03 00:58:21.514622088 +0200
@@ -0,0 +1,164 @@
+/* Konrad Eisele <eiselekd@web.de>, 2003: arch/sparc/leon/kernel/irq.c */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/pgtsrmmu.h>
+#include <asm/leon.h>
+#include <asm/sbus.h> /* for struct sbus_bus, warning suppress */
+#include <asm/timer.h>
+
+/* scaled down to timer to 1Mhz, used in sparc/kernel/leon_irq.c */
+#define CLOCK_TIMER_SCALAR 25
+
+static inline unsigned long get_irqmask(unsigned int irq)
+{
+ unsigned long mask;
+ if (!irq || irq > 0xf) {
+ printk("leon_get_irqmask: false irq number\n");
+ mask = 0;
+ } else {
+ mask = LEON_HARD_INT(irq);
+ }
+ return mask;
+}
+
+void leon_disable_irq(unsigned int irq_nr)
+{
+ unsigned long mask, flags;
+ mask = get_irqmask(irq_nr) & LEON_IRQMASK_R;
+ save_and_cli(flags);
+ LEON_REGSTORE_PA(LEON_IMASK, LEON_REGLOAD_PA(LEON_IMASK) & ~(mask));
+ restore_flags(flags);
+}
+
+void leon_enable_irq(unsigned int irq_nr)
+{
+ unsigned long mask, flags;
+ mask = get_irqmask(irq_nr) & LEON_IRQMASK_R;
+ save_and_cli(flags);
+ LEON_REGSTORE_PA(LEON_IMASK, LEON_REGLOAD_PA(LEON_IMASK) | (mask));
+ restore_flags(flags);
+}
+
+/* We assume the caller is local cli()'d when these are called, or else
+ * very bizarre behavior will result. */
+void leon_disable_pil_irq(unsigned int pil)
+{
+ unsigned long mask = get_irqmask(pil);
+ LEON_REGSTORE_PA(LEON_IMASK, LEON_REGLOAD_PA(LEON_IMASK) & ~(mask));
+}
+
+void leon_enable_pil_irq(unsigned int pil)
+{
+ unsigned long mask = get_irqmask(pil);
+ LEON_REGSTORE_PA(LEON_IMASK, LEON_REGLOAD_PA(LEON_IMASK) | (mask));
+}
+
+int leondebug_irq_disable;
+int leon_debug_irqout;
+static int dummy_master_l10_counter;
+static int dummy_master_l10_limit;
+
+/* called by time_init():timer.c */
+void __init leon_init_timers (irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
+{
+ int irq;
+
+ leondebug_irq_disable = 0;
+ leon_debug_irqout = 0;
+
+ LEON_REGSTORE_PA(LEON_TCTRL0, 0);
+ LEON_REGSTORE_PA(LEON_TCNT0, 0);
+ LEON_REGSTORE_PA(LEON_TRLD0, (((1000000/HZ) - 1)));
+
+ printk("Todo: init master_l10_counter\r\n");
+ master_l10_counter = &dummy_master_l10_counter;
+ master_l10_limit = &dummy_master_l10_limit;
+ dummy_master_l10_counter = 0;
+ dummy_master_l10_limit = 0;
+
+ irq = request_irq(LEON_INTERRUPT_TIMER1,
+ counter_fn,
+ (SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", NULL);
+ if (irq) {
+ printk("leon_time_init: unable to attach IRQ%d\n",LEON_INTERRUPT_TIMER1);
+ prom_halt();
+ }
+
+ /* enable, load reload into counter, set automatic reload */
+ LEON_REGSTORE_PA(LEON_TCTRL0, 0x7);
+}
+
+void leon_clear_clock_irq(void)
+{
+}
+
+void leon_clear_profile_irq(int cpu)
+{
+ BUG();
+}
+
+void leon_load_profile_irq(int cpu, unsigned int limit)
+{
+ BUG();
+}
+
+unsigned int leon_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
+{
+ BUG();
+ return 0;
+}
+
+static char *leon_irq_itoa(unsigned int irq)
+{
+ static char buff[16];
+ sprintf(buff, "%d", irq);
+ return buff;
+}
+
+#ifdef CONFIG_SMP
+static void leon_set_cpu_int(int cpu, int level)
+{
+ printk("Not implemented\n");
+ BUG();
+}
+
+static void leon_clear_ipi(int cpu, int level)
+{
+}
+
+static void leon_set_udt(int cpu)
+{
+}
+#endif
+
+void __init leon_init_IRQ(void)
+{
+ sparc_init_timers = leon_init_timers;
+
+ BTFIXUPSET_CALL(sbint_to_irq, leon_sbint_to_irq, BTFIXUPCALL_NORM);
+
+ 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(clear_profile_irq, leon_clear_profile_irq, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(load_profile_irq, leon_load_profile_irq, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(__irq_itoa, leon_irq_itoa, BTFIXUPCALL_NORM);
+
+#ifdef CONFIG_SMP
+ BTFIXUPSET_CALL(set_cpu_int, leon_set_cpu_int, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(clear_cpu_int, leon_clear_ipi, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(set_irq_udt, leon_set_udt, BTFIXUPCALL_NOP);
+#endif
+
+}
diff -urN a/arch/sparc/mm/leon.c b/arch/sparc/mm/leon.c
--- a/arch/sparc/mm/leon.c 1970-01-01 01:00:00.000000000 +0100
+++ b/arch/sparc/mm/leon.c 2004-04-03 00:58:21.517621632 +0200
@@ -0,0 +1,99 @@
+/* Konrad Eisele <eiselekd@web.de>, 2003: arch/sparc/leon/mm/leon.c */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <asm/asi.h>
+#include <asm/leon.h>
+
+#define PFN(x) ((x) >> PAGE_SHIFT)
+extern unsigned long last_valid_pfn;
+
+/* max_mapnr not initialized yet */
+#define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base)))
+
+unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) {
+
+ unsigned long ctxtbl;
+ unsigned long pgd,pmd,ped;
+ unsigned long ptr;
+ unsigned long lvl, pte, paddrbase;
+ unsigned long ctx;
+
+ paddrbase = 0;
+
+ if (!(ctxtbl = srmmu_get_ctable_ptr()))
+ return 0;
+ if (!_pfn_valid(PFN(ctxtbl)))
+ return 0;
+
+ ctx = srmmu_get_context();
+
+ pgd = LEON_BYPASS_LOAD_PA(ctxtbl+(ctx*4));
+
+ if (((pgd&SRMMU_ET_MASK) = SRMMU_ET_PTE)) {
+ lvl = 3;
+ pte = pgd;
+ paddrbase = pgd & SRMMU_PTE_PMASK;
+ goto ready;
+ }
+ if (((pgd&SRMMU_ET_MASK) != SRMMU_ET_PTD))
+ return 0;
+
+ ptr = (pgd & SRMMU_PTD_PMASK) << 4;
+ ptr += (((vaddr & 0xff000000)>>24)*4);
+ if (!_pfn_valid(PFN(ptr)))
+ return 0;
+
+ pmd = LEON_BYPASS_LOAD_PA(ptr);
+ if (((pmd&SRMMU_ET_MASK) = SRMMU_ET_PTE)) {
+ lvl = 2;
+ pte = pmd;
+ paddrbase = pmd & SRMMU_PTE_PMASK;
+ goto ready;
+ }
+ if (((pmd&SRMMU_ET_MASK) != SRMMU_ET_PTD))
+ return 0;
+
+ ptr = (pmd & SRMMU_PTD_PMASK) << 4;
+ ptr += (((vaddr & 0x00fc0000)>>18)*4);
+ if (!_pfn_valid(PFN(ptr)))
+ return 0;
+
+ ped = LEON_BYPASS_LOAD_PA(ptr);
+ if (((ped&SRMMU_ET_MASK) = SRMMU_ET_PTE)) {
+ lvl = 1;
+ pte = ped;
+ paddrbase = ped & SRMMU_PTE_PMASK;
+ goto ready;
+ }
+ if (((ped&SRMMU_ET_MASK) != SRMMU_ET_PTD))
+ return 0;
+
+ ptr = (ped & SRMMU_PTD_PMASK) << 4;
+ ptr += (((vaddr & 0x0003f000)>>12)*4);
+ if (!_pfn_valid(PFN(ptr)))
+ return 0;
+
+ ptr = LEON_BYPASS_LOAD_PA(ptr);
+ if (((ptr&SRMMU_ET_MASK) = SRMMU_ET_PTE)) {
+ lvl = 0;
+ pte = ptr;
+ paddrbase = ptr & SRMMU_PTE_PMASK;
+ goto ready;
+ }
+ return 0;
+
+ready:
+ if (paddr) {
+ switch (lvl) {
+ case 0: *paddr = (vaddr & 0x00000fff) | ((pte&~0xff)<<4); break;
+ case 1: *paddr = (vaddr & 0x0003ffff) | ((pte&~0xff)<<4); break;
+ case 2: *paddr = (vaddr & 0x00ffffff) | ((pte&~0xff)<<4); break;
+ default:
+ case 3: *paddr = vaddr; break;
+ }
+ }
+ return paddrbase;
+}
+
+
--
RY Stefan
+-----------------+----------------+
| mail@s-holst.de | www.s-holst.de |
+-----------------+----------------+
reply other threads:[~2004-04-03 0:17 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040403001736.GA7330@spike \
--to=mail@s-holst.de \
--cc=sparclinux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.