summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mvme16x
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mvme16x')
-rw-r--r--arch/m68k/mvme16x/16xints.c2
-rw-r--r--arch/m68k/mvme16x/Makefile2
-rw-r--r--arch/m68k/mvme16x/config.c139
-rw-r--r--arch/m68k/mvme16x/rtc.c166
4 files changed, 223 insertions, 86 deletions
diff --git a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
index c79ff17ad..fbb370a07 100644
--- a/arch/m68k/mvme16x/16xints.c
+++ b/arch/m68k/mvme16x/16xints.c
@@ -127,7 +127,7 @@ int mvme16x_get_irq_list (char *buf)
static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
{
- panic ("Unknown interrupt 0x%02x", irq);
+ printk ("Unknown interrupt 0x%02x\n", irq);
}
diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile
index 97c670f3c..bb7485ab8 100644
--- a/arch/m68k/mvme16x/Makefile
+++ b/arch/m68k/mvme16x/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := mvme16x.o
-O_OBJS := config.o 16xints.o
+O_OBJS := config.o 16xints.o rtc.o
#OX_OBJS = ksyms.o
include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 00e7db8d1..838c3bbac 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -34,26 +34,10 @@
#include <asm/machdep.h>
#include <asm/mvme16xhw.h>
-typedef struct {
- unsigned char
- ctrl,
- bcd_sec,
- bcd_min,
- bcd_hr,
- bcd_dow,
- bcd_dom,
- bcd_mth,
- bcd_year;
-} MK48T08;
-
-#define RTC_WRITE 0x80
-#define RTC_READ 0x40
-#define RTC_STOP 0x20
-
int atari_SCC_reset_done = 1; /* So SCC doesn't get reset */
u_long atari_mch_cookie = 0;
-MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8;
+static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
extern void mvme16x_process_int (int level, struct pt_regs *regs);
extern void mvme16x_init_IRQ (void);
@@ -143,6 +127,11 @@ static int mvme16x_get_hardware_list(char *buffer)
}
+#define pcc2chip ((volatile u_char *)0xfff42000)
+#define PccSCCMICR 0x1d
+#define PccSCCTICR 0x1e
+#define PccSCCRICR 0x1f
+
__initfunc(void config_mvme16x(void))
{
p_bdid p = (p_bdid)mvme_bdid_ptr;
@@ -197,7 +186,43 @@ __initfunc(void config_mvme16x(void))
rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
}
else
+ {
mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401;
+
+ /* Dont allow any interrupts from the CD2401 until the interrupt */
+ /* handlers are installed */
+
+ pcc2chip[PccSCCMICR] = 0x10;
+ pcc2chip[PccSCCTICR] = 0x10;
+ pcc2chip[PccSCCRICR] = 0x10;
+ }
+}
+
+static void mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+ p_bdid p = (p_bdid)mvme_bdid_ptr;
+ unsigned long *new = (unsigned long *)vectors;
+ unsigned long *old = (unsigned long *)0xffe00000;
+ volatile unsigned char uc, *ucp;
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ {
+ ucp = (volatile unsigned char *)0xfff42043;
+ uc = *ucp | 8;
+ *ucp = uc;
+ }
+ else
+ {
+ *(volatile unsigned long *)0xfff40074 = 0x40000000;
+ }
+ *(new+4) = *(old+4); /* Illegal instruction */
+ *(new+9) = *(old+9); /* Trace */
+ *(new+47) = *(old+47); /* Trap #15 */
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ *(new+0x5e) = *(old+0x5e); /* ABORT switch */
+ else
+ *(new+0x6e) = *(old+0x6e); /* ABORT switch */
}
static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
@@ -208,15 +233,26 @@ static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
{
+ p_bdid p = (p_bdid)mvme_bdid_ptr;
+ int irq;
+
tick_handler = timer_routine;
/* Using PCCchip2 or MC2 chip tick timer 1 */
*(volatile unsigned long *)0xfff42008 = 0;
*(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */
*(volatile unsigned char *)0xfff42017 |= 3;
*(volatile unsigned char *)0xfff4201b = 0x16;
- if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0,
+ if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0,
"timer", mvme16x_timer_int))
panic ("Couldn't register timer int");
+
+ if (p->brdno == 0x0162 || p->brdno == 0x172)
+ irq = MVME162_IRQ_ABORT;
+ else
+ irq = MVME167_IRQ_ABORT;
+ if (request_irq(irq, mvme16x_abort_int, 0,
+ "abort", mvme16x_abort_int))
+ panic ("Couldn't register abort int");
}
@@ -254,76 +290,11 @@ int mvme16x_set_clock_mmss (unsigned long nowtime)
return 0;
}
-/*
- * console_map_init(), here to avoid having to modify drivers/block/genhd.c
- */
-
-void console_map_init(void)
-{
-}
-
-/*
- * fbmem_init(), here to avoid having to modify drivers/char/mem.c
- */
-
-void fbmem_init(void)
-{
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-unsigned long con_init(unsigned long kmem_start)
-{
- return (kmem_start);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int vcs_init(void)
-{
- return (0);
-}
-
-/* Avoid mods to drivers/char/tty_io.c */
-
-int kbd_init(void)
-{
- return (0);
-}
-
-/* Avoid mods to init/main.c */
-
-void no_scroll(char *str, int *ints)
-{
-}
-
-/* Avoid mods to kernel/panic.c */
-
-void do_unblank_screen(void)
-{
-}
-
int mvme16x_keyb_init (void)
{
return 0;
}
-void mvme16x_set_vectors (void)
-{
- p_bdid p = (p_bdid)mvme_bdid_ptr;
- unsigned long *new = (unsigned long *)vectors;
- unsigned long *old = (unsigned long *)0xffe00000;;
-
- *(new+4) = *(old+4); /* Illegal instruction */
- *(new+9) = *(old+9); /* Trace */
- *(new+47) = *(old+47); /* Trap #15 */
-
- if (p->brdno == 0x0162 || p->brdno == 0x172)
- *(new+0x5e) = *(old+0x5e); /* ABORT switch */
- else
- *(new+0x6e) = *(old+0x6e); /* ABORT switch */
-}
-
/*------------------- Serial console stuff ------------------------*/
extern void mvme167_serial_console_setup(int cflag);
@@ -372,7 +343,7 @@ static void scc_delay (void)
static void scc_write (char ch)
{
- volatile char *p = (volatile char *)SCC_A_ADDR;
+ volatile char *p = (volatile char *)MVME_SCC_A_ADDR;
do {
scc_delay();
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
new file mode 100644
index 000000000..6b7c0c011
--- /dev/null
+++ b/arch/m68k/mvme16x/rtc.c
@@ -0,0 +1,166 @@
+/*
+ * Real Time Clock interface for Linux on the MVME16x
+ *
+ * Based on the PC driver by Paul Gortmaker.
+ */
+
+#define RTC_VERSION "1.00"
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
+#include <asm/mvme16xhw.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+
+/*
+ * We sponge a minor off of the misc major. No need slurping
+ * up another valuable major dev number for this. If you add
+ * an ioctl, make sure you don't conflict with SPARC's RTC
+ * ioctls.
+ */
+
+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static unsigned char days_in_mo[] =
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char rtc_status = 0;
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE;
+ unsigned long flags;
+ struct rtc_time wtime;
+
+ switch (cmd) {
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ {
+ save_flags(flags);
+ cli();
+ /* Ensure clock and real-time-mode-register are accessible */
+ rtc->ctrl = RTC_READ;
+ wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
+ wtime.tm_min = BCD2BIN(rtc->bcd_min);
+ wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
+ wtime.tm_mday = BCD2BIN(rtc->bcd_dom);
+ wtime.tm_mon = BCD2BIN(rtc->bcd_mth)-1;
+ wtime.tm_year = BCD2BIN(rtc->bcd_year);
+ if (wtime.tm_year < 70)
+ wtime.tm_year += 100;
+ wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+ rtc->ctrl = 0;
+ restore_flags(flags);
+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
+ -EFAULT : 0;
+ }
+ case RTC_SET_TIME: /* Set the RTC */
+ {
+ unsigned char leap_yr;
+ struct rtc_time rtc_tm;
+
+ if (!suser())
+ return -EACCES;
+
+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+ sizeof(struct rtc_time)))
+ return -EFAULT;
+
+ leap_yr = ((!(rtc_tm.tm_year % 4) && (rtc_tm.tm_year % 100)) || !(rtc_tm.tm_year % 400));
+
+ if ((rtc_tm.tm_mon > 12) || (rtc_tm.tm_mday == 0))
+ return -EINVAL;
+
+ if (rtc_tm.tm_mday > (days_in_mo[rtc_tm.tm_mon] + ((rtc_tm.tm_mon == 2) && leap_yr)))
+ return -EINVAL;
+
+ if ((rtc_tm.tm_hour >= 24) || (rtc_tm.tm_min >= 60) || (rtc_tm.tm_sec >= 60))
+ return -EINVAL;
+
+ save_flags(flags);
+ cli();
+ rtc->ctrl = RTC_WRITE;
+
+ rtc->bcd_sec = BIN2BCD(rtc_tm.tm_sec);
+ rtc->bcd_min = BIN2BCD(rtc_tm.tm_min);
+ rtc->bcd_hr = BIN2BCD(rtc_tm.tm_hour);
+ rtc->bcd_dom = BIN2BCD(rtc_tm.tm_mday);
+ rtc->bcd_mth = BIN2BCD(rtc_tm.tm_mon + 1);
+ rtc->bcd_year = BIN2BCD(rtc_tm.tm_year%100);
+ if (rtc_tm.tm_wday >= 0)
+ rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+
+ rtc->ctrl = 0;
+ restore_flags(flags);
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * We enforce only one user at a time here with the open/close.
+ * Also clear the previous interrupt data on an open, and clean
+ * up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+ if(rtc_status)
+ return -EBUSY;
+
+ rtc_status = 1;
+ return 0;
+}
+
+static int rtc_release(struct inode *inode, struct file *file)
+{
+ rtc_status = 0;
+ return 0;
+}
+
+/*
+ * The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+ NULL,
+ NULL,
+ NULL, /* No write */
+ NULL, /* No readdir */
+ NULL,
+ rtc_ioctl,
+ NULL, /* No mmap */
+ rtc_open,
+ rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+ RTC_MINOR,
+ "rtc",
+ &rtc_fops
+};
+
+__initfunc(int rtc_MK48T08_init(void))
+{
+ if (!MACH_IS_MVME16x)
+ return -ENODEV;
+
+ printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
+ misc_register(&rtc_dev);
+ return 0;
+}
+