summaryrefslogtreecommitdiffstats
path: root/arch/m68k/sun3x
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/sun3x')
-rw-r--r--arch/m68k/sun3x/Makefile6
-rw-r--r--arch/m68k/sun3x/config.c78
-rw-r--r--arch/m68k/sun3x/dvma.c201
-rw-r--r--arch/m68k/sun3x/prom.c165
-rw-r--r--arch/m68k/sun3x/time.c104
-rw-r--r--arch/m68k/sun3x/time.h19
6 files changed, 573 insertions, 0 deletions
diff --git a/arch/m68k/sun3x/Makefile b/arch/m68k/sun3x/Makefile
new file mode 100644
index 000000000..f36020e9d
--- /dev/null
+++ b/arch/m68k/sun3x/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for Linux arch/m68k/sun3x source directory
+#
+
+obj-y := config.o time.o dvma.o prom.o
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
new file mode 100644
index 000000000..d806dee71
--- /dev/null
+++ b/arch/m68k/sun3x/config.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Setup kernel for a Sun3x machine
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * based on code from Oliver Jowett <oliver@jowett.manawatu.gen.nz>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sun3xprom.h>
+#include <asm/sun3ints.h>
+#include <asm/setup.h>
+#include <asm/oplib.h>
+
+#include "time.h"
+
+volatile char *clock_va;
+
+extern void sun3_get_model(char *model);
+
+void sun3_leds(unsigned int i)
+{
+
+}
+
+static void sun3x_get_hardware_list(struct seq_file *m)
+{
+ seq_printf(m, "PROM Revision:\t%s\n", romvec->pv_monid);
+}
+
+/*
+ * Setup the sun3x configuration info
+ */
+void __init config_sun3x(void)
+{
+
+ sun3x_prom_init();
+
+ mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
+
+ mach_sched_init = sun3x_sched_init;
+ mach_init_IRQ = sun3_init_IRQ;
+
+ mach_reset = sun3x_reboot;
+
+ mach_hwclk = sun3x_hwclk;
+ mach_get_model = sun3_get_model;
+ mach_get_hardware_list = sun3x_get_hardware_list;
+
+ sun3_intreg = (unsigned char *)SUN3X_INTREG;
+
+ /* only the serial console is known to work anyway... */
+#if 0
+ switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+ case 0x10:
+ serial_console = 1;
+ conswitchp = NULL;
+ break;
+ case 0x11:
+ serial_console = 2;
+ conswitchp = NULL;
+ break;
+ default:
+ serial_console = 0;
+ break;
+ }
+#endif
+
+}
+
diff --git a/arch/m68k/sun3x/dvma.c b/arch/m68k/sun3x/dvma.c
new file mode 100644
index 000000000..08bb92113
--- /dev/null
+++ b/arch/m68k/sun3x/dvma.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Virtual DMA allocation
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * 11/26/2000 -- disabled the existing code because it didn't work for
+ * me in 2.4. Replaced with a significantly more primitive version
+ * similar to the sun3 code. the old functionality was probably more
+ * desirable, but.... -- Sam Creasey (sammy@oh.verio.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+#include <linux/memblock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+
+/* IOMMU support */
+
+#define IOMMU_ADDR_MASK 0x03ffe000
+#define IOMMU_CACHE_INHIBIT 0x00000040
+#define IOMMU_FULL_BLOCK 0x00000020
+#define IOMMU_MODIFIED 0x00000010
+#define IOMMU_USED 0x00000008
+#define IOMMU_WRITE_PROTECT 0x00000004
+#define IOMMU_DT_MASK 0x00000003
+#define IOMMU_DT_INVALID 0x00000000
+#define IOMMU_DT_VALID 0x00000001
+#define IOMMU_DT_BAD 0x00000002
+
+
+static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
+
+
+#define dvma_entry_paddr(index) (iommu_pte[index] & IOMMU_ADDR_MASK)
+#define dvma_entry_vaddr(index,paddr) ((index << DVMA_PAGE_SHIFT) | \
+ (paddr & (DVMA_PAGE_SIZE-1)))
+#if 0
+#define dvma_entry_set(index,addr) (iommu_pte[index] = \
+ (addr & IOMMU_ADDR_MASK) | \
+ IOMMU_DT_VALID | IOMMU_CACHE_INHIBIT)
+#else
+#define dvma_entry_set(index,addr) (iommu_pte[index] = \
+ (addr & IOMMU_ADDR_MASK) | \
+ IOMMU_DT_VALID)
+#endif
+#define dvma_entry_clr(index) (iommu_pte[index] = IOMMU_DT_INVALID)
+#define dvma_entry_hash(addr) ((addr >> DVMA_PAGE_SHIFT) ^ \
+ ((addr & 0x03c00000) >> \
+ (DVMA_PAGE_SHIFT+4)))
+
+#ifdef DEBUG
+/* code to print out a dvma mapping for debugging purposes */
+void dvma_print (unsigned long dvma_addr)
+{
+
+ unsigned long index;
+
+ index = dvma_addr >> DVMA_PAGE_SHIFT;
+
+ pr_info("idx %lx dvma_addr %08lx paddr %08lx\n", index, dvma_addr,
+ dvma_entry_paddr(index));
+}
+#endif
+
+
+/* create a virtual mapping for a page assigned within the IOMMU
+ so that the cpu can reach it easily */
+inline int dvma_map_cpu(unsigned long kaddr,
+ unsigned long vaddr, int len)
+{
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ unsigned long end;
+ int ret = 0;
+
+ kaddr &= PAGE_MASK;
+ vaddr &= PAGE_MASK;
+
+ end = PAGE_ALIGN(vaddr + len);
+
+ pr_debug("dvma: mapping kern %08lx to virt %08lx\n", kaddr, vaddr);
+ pgd = pgd_offset_k(vaddr);
+ p4d = p4d_offset(pgd, vaddr);
+ pud = pud_offset(p4d, vaddr);
+
+ do {
+ pmd_t *pmd;
+ unsigned long end2;
+
+ if((pmd = pmd_alloc(&init_mm, pud, vaddr)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if((end & PGDIR_MASK) > (vaddr & PGDIR_MASK))
+ end2 = (vaddr + (PGDIR_SIZE-1)) & PGDIR_MASK;
+ else
+ end2 = end;
+
+ do {
+ pte_t *pte;
+ unsigned long end3;
+
+ if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if((end2 & PMD_MASK) > (vaddr & PMD_MASK))
+ end3 = (vaddr + (PMD_SIZE-1)) & PMD_MASK;
+ else
+ end3 = end2;
+
+ do {
+ pr_debug("mapping %08lx phys to %08lx\n",
+ __pa(kaddr), vaddr);
+ set_pte(pte, pfn_pte(virt_to_pfn(kaddr),
+ PAGE_KERNEL));
+ pte++;
+ kaddr += PAGE_SIZE;
+ vaddr += PAGE_SIZE;
+ } while(vaddr < end3);
+
+ } while(vaddr < end2);
+
+ } while(vaddr < end);
+
+ flush_tlb_all();
+
+ out:
+ return ret;
+}
+
+
+inline int dvma_map_iommu(unsigned long kaddr, unsigned long baddr,
+ int len)
+{
+ unsigned long end, index;
+
+ index = baddr >> DVMA_PAGE_SHIFT;
+ end = ((baddr+len) >> DVMA_PAGE_SHIFT);
+
+ if(len & ~DVMA_PAGE_MASK)
+ end++;
+
+ for(; index < end ; index++) {
+// if(dvma_entry_use(index))
+// BUG();
+// pr_info("mapping pa %lx to ba %lx\n", __pa(kaddr),
+// index << DVMA_PAGE_SHIFT);
+
+ dvma_entry_set(index, __pa(kaddr));
+
+ iommu_pte[index] |= IOMMU_FULL_BLOCK;
+// dvma_entry_inc(index);
+
+ kaddr += DVMA_PAGE_SIZE;
+ }
+
+#ifdef DEBUG
+ for(index = (baddr >> DVMA_PAGE_SHIFT); index < end; index++)
+ dvma_print(index << DVMA_PAGE_SHIFT);
+#endif
+ return 0;
+
+}
+
+void dvma_unmap_iommu(unsigned long baddr, int len)
+{
+
+ int index, end;
+
+
+ index = baddr >> DVMA_PAGE_SHIFT;
+ end = (DVMA_PAGE_ALIGN(baddr+len) >> DVMA_PAGE_SHIFT);
+
+ for(; index < end ; index++) {
+ pr_debug("freeing bus mapping %08x\n",
+ index << DVMA_PAGE_SHIFT);
+#if 0
+ if(!dvma_entry_use(index))
+ pr_info("dvma_unmap freeing unused entry %04x\n",
+ index);
+ else
+ dvma_entry_dec(index);
+#endif
+ dvma_entry_clr(index);
+ }
+
+}
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
new file mode 100644
index 000000000..74d2fe575
--- /dev/null
+++ b/arch/m68k/sun3x/prom.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Prom access routines for the sun3x */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <asm/sun3xprom.h>
+#include <asm/idprom.h>
+#include <asm/segment.h>
+#include <asm/sun3ints.h>
+#include <asm/openprom.h>
+#include <asm/machines.h>
+
+void (*sun3x_putchar)(int);
+int (*sun3x_getchar)(void);
+int (*sun3x_mayget)(void);
+int (*sun3x_mayput)(int);
+void (*sun3x_prom_reboot)(void);
+e_vector sun3x_prom_abort;
+struct linux_romvec *romvec;
+
+/* prom vector table */
+e_vector *sun3x_prom_vbr;
+
+/* Handle returning to the prom */
+void sun3x_halt(void)
+{
+ unsigned long flags;
+
+ /* Disable interrupts while we mess with things */
+ local_irq_save(flags);
+
+ /* Restore prom vbr */
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+ /* Restore prom NMI clock */
+// sun3x_disable_intreg(5);
+ sun3_enable_irq(7);
+
+ /* Let 'er rip */
+ asm volatile ("trap #14");
+
+ /* Restore everything */
+ sun3_disable_irq(7);
+ sun3_enable_irq(5);
+
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+ local_irq_restore(flags);
+}
+
+void sun3x_reboot(void)
+{
+ /* This never returns, don't bother saving things */
+ local_irq_disable();
+
+ /* Restore prom vbr */
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+ /* Restore prom NMI clock */
+ sun3_disable_irq(5);
+ sun3_enable_irq(7);
+
+ /* Let 'er rip */
+ (*romvec->pv_reboot)("vmlinux");
+}
+
+static void sun3x_prom_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ while (count--) {
+ if (*s == '\n')
+ sun3x_putchar('\r');
+ sun3x_putchar(*s++);
+ }
+}
+
+/* debug console - write-only */
+
+static struct console sun3x_debug = {
+ .name = "debug",
+ .write = sun3x_prom_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+void __init sun3x_prom_init(void)
+{
+ /* Read the vector table */
+
+ sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
+ sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
+ sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET);
+ sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT);
+ sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
+ sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT);
+ romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
+
+ idprom_init();
+
+ if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
+ pr_warn("Machine reports strange type %02x\n",
+ idprom->id_machtype);
+ pr_warn("Pretending it's a 3/80, but very afraid...\n");
+ idprom->id_machtype = SM_SUN3X | SM_3_80;
+ }
+
+ /* point trap #14 at abort.
+ * XXX this is futile since we restore the vbr first - oops
+ */
+ vectors[VEC_TRAP14] = sun3x_prom_abort;
+}
+
+static int __init sun3x_debug_setup(char *arg)
+{
+ /* If debug=prom was specified, start the debug console */
+ if (MACH_IS_SUN3X && !strcmp(arg, "prom"))
+ register_console(&sun3x_debug);
+ return 0;
+}
+
+early_param("debug", sun3x_debug_setup);
+
+/* some prom functions to export */
+int prom_getintdefault(int node, char *property, int deflt)
+{
+ return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+ return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+}
+
+void prom_halt (void)
+{
+ sun3x_halt();
+}
+
+/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
+ * format type. 'num_bytes' is the number of bytes that your idbuf
+ * has space for. Returns 0xff on error.
+ */
+unsigned char
+prom_get_idprom(char *idbuf, int num_bytes)
+{
+ int i;
+
+ /* make a copy of the idprom structure */
+ for (i = 0; i < num_bytes; i++)
+ idbuf[i] = ((char *)SUN3X_IDPROM)[i];
+
+ return idbuf[0];
+}
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
new file mode 100644
index 000000000..9163294b0
--- /dev/null
+++ b/arch/m68k/sun3x/time.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/m68k/sun3x/time.c
+ *
+ * Sun3x-specific time handling
+ */
+
+#include <linux/types.h>
+#include <linux/kd.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/traps.h>
+#include <asm/sun3x.h>
+#include <asm/sun3ints.h>
+
+#include "time.h"
+
+#define M_CONTROL 0xf8
+#define M_SEC 0xf9
+#define M_MIN 0xfa
+#define M_HOUR 0xfb
+#define M_DAY 0xfc
+#define M_DATE 0xfd
+#define M_MONTH 0xfe
+#define M_YEAR 0xff
+
+#define C_WRITE 0x80
+#define C_READ 0x40
+#define C_SIGN 0x20
+#define C_CALIB 0x1f
+
+int sun3x_hwclk(int set, struct rtc_time *t)
+{
+ volatile struct mostek_dt *h =
+ (struct mostek_dt *)(SUN3X_EEPROM+M_CONTROL);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if(set) {
+ h->csr |= C_WRITE;
+ h->sec = bin2bcd(t->tm_sec);
+ h->min = bin2bcd(t->tm_min);
+ h->hour = bin2bcd(t->tm_hour);
+ h->wday = bin2bcd(t->tm_wday);
+ h->mday = bin2bcd(t->tm_mday);
+ h->month = bin2bcd(t->tm_mon + 1);
+ h->year = bin2bcd(t->tm_year % 100);
+ h->csr &= ~C_WRITE;
+ } else {
+ h->csr |= C_READ;
+ t->tm_sec = bcd2bin(h->sec);
+ t->tm_min = bcd2bin(h->min);
+ t->tm_hour = bcd2bin(h->hour);
+ t->tm_wday = bcd2bin(h->wday);
+ t->tm_mday = bcd2bin(h->mday);
+ t->tm_mon = bcd2bin(h->month) - 1;
+ t->tm_year = bcd2bin(h->year);
+ h->csr &= ~C_READ;
+ if (t->tm_year < 70)
+ t->tm_year += 100;
+ }
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+#if 0
+static irqreturn_t sun3x_timer_tick(int irq, void *dev_id)
+{
+ irq_handler_t timer_routine = dev_id;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /* Clear the pending interrupt - pulse the enable line low */
+ disable_irq(5);
+ enable_irq(5);
+ timer_routine(0, NULL);
+ local_irq_restore(flags);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+void __init sun3x_sched_init(irq_handler_t vector)
+{
+
+ sun3_disable_interrupts();
+
+
+ /* Pulse enable low to get the clock started */
+ sun3_disable_irq(5);
+ sun3_enable_irq(5);
+ sun3_enable_interrupts();
+}
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
new file mode 100644
index 000000000..86ce78bb3
--- /dev/null
+++ b/arch/m68k/sun3x/time.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef SUN3X_TIME_H
+#define SUN3X_TIME_H
+
+extern int sun3x_hwclk(int set, struct rtc_time *t);
+void sun3x_sched_init(irq_handler_t vector);
+
+struct mostek_dt {
+ volatile unsigned char csr;
+ volatile unsigned char sec;
+ volatile unsigned char min;
+ volatile unsigned char hour;
+ volatile unsigned char wday;
+ volatile unsigned char mday;
+ volatile unsigned char month;
+ volatile unsigned char year;
+};
+
+#endif