aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/lasat
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/lasat')
-rw-r--r--arch/mips/lasat/Makefile14
-rw-r--r--arch/mips/lasat/at93c.c148
-rw-r--r--arch/mips/lasat/at93c.h18
-rw-r--r--arch/mips/lasat/ds1603.c174
-rw-r--r--arch/mips/lasat/ds1603.h33
-rw-r--r--arch/mips/lasat/image/Makefile53
-rw-r--r--arch/mips/lasat/image/head.S31
-rw-r--r--arch/mips/lasat/image/romscript.normal22
-rw-r--r--arch/mips/lasat/interrupt.c160
-rw-r--r--arch/mips/lasat/lasatIRQ.S69
-rw-r--r--arch/mips/lasat/lasat_board.c277
-rw-r--r--arch/mips/lasat/lasat_models.h63
-rw-r--r--arch/mips/lasat/picvue.c240
-rw-r--r--arch/mips/lasat/picvue.h48
-rw-r--r--arch/mips/lasat/picvue_proc.c186
-rw-r--r--arch/mips/lasat/prom.c143
-rw-r--r--arch/mips/lasat/prom.h6
-rw-r--r--arch/mips/lasat/reset.c67
-rw-r--r--arch/mips/lasat/setup.c192
-rw-r--r--arch/mips/lasat/sysctl.c355
-rw-r--r--arch/mips/lasat/sysctl.h24
21 files changed, 2323 insertions, 0 deletions
diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile
new file mode 100644
index 00000000000..0d5aec43672
--- /dev/null
+++ b/arch/mips/lasat/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the LASAT specific kernel interface routines under Linux.
+#
+
+obj-y += reset.o setup.o prom.o lasat_board.o \
+ at93c.o interrupt.o lasatIRQ.o
+
+obj-$(CONFIG_LASAT_SYSCTL) += sysctl.o
+obj-$(CONFIG_DS1603) += ds1603.o
+obj-$(CONFIG_PICVUE) += picvue.o
+obj-$(CONFIG_PICVUE_PROC) += picvue_proc.o
+
+clean:
+ make -C image clean
diff --git a/arch/mips/lasat/at93c.c b/arch/mips/lasat/at93c.c
new file mode 100644
index 00000000000..f6add041ebe
--- /dev/null
+++ b/arch/mips/lasat/at93c.c
@@ -0,0 +1,148 @@
+/*
+ * Atmel AT93C46 serial eeprom driver
+ *
+ * Brian Murphy <brian.murphy@eicon.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <asm/lasat/lasat.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "at93c.h"
+
+#define AT93C_ADDR_SHIFT 7
+#define AT93C_ADDR_MAX ((1 << AT93C_ADDR_SHIFT) - 1)
+#define AT93C_RCMD (0x6 << AT93C_ADDR_SHIFT)
+#define AT93C_WCMD (0x5 << AT93C_ADDR_SHIFT)
+#define AT93C_WENCMD 0x260
+#define AT93C_WDSCMD 0x200
+
+struct at93c_defs *at93c;
+
+static void at93c_reg_write(u32 val)
+{
+ *at93c->reg = val;
+}
+
+static u32 at93c_reg_read(void)
+{
+ u32 tmp = *at93c->reg;
+ return tmp;
+}
+
+static u32 at93c_datareg_read(void)
+{
+ u32 tmp = *at93c->rdata_reg;
+ return tmp;
+}
+
+static void at93c_cycle_clk(u32 data)
+{
+ at93c_reg_write(data | at93c->clk);
+ lasat_ndelay(250);
+ at93c_reg_write(data & ~at93c->clk);
+ lasat_ndelay(250);
+}
+
+static void at93c_write_databit(u8 bit)
+{
+ u32 data = at93c_reg_read();
+ if (bit)
+ data |= 1 << at93c->wdata_shift;
+ else
+ data &= ~(1 << at93c->wdata_shift);
+
+ at93c_reg_write(data);
+ lasat_ndelay(100);
+ at93c_cycle_clk(data);
+}
+
+static unsigned int at93c_read_databit(void)
+{
+ u32 data;
+
+ at93c_cycle_clk(at93c_reg_read());
+ data = (at93c_datareg_read() >> at93c->rdata_shift) & 1;
+ return data;
+}
+
+static u8 at93c_read_byte(void)
+{
+ int i;
+ u8 data = 0;
+
+ for (i = 0; i<=7; i++) {
+ data <<= 1;
+ data |= at93c_read_databit();
+ }
+ return data;
+}
+
+static void at93c_write_bits(u32 data, int size)
+{
+ int i;
+ int shift = size - 1;
+ u32 mask = (1 << shift);
+
+ for (i = 0; i < size; i++) {
+ at93c_write_databit((data & mask) >> shift);
+ data <<= 1;
+ }
+}
+
+static void at93c_init_op(void)
+{
+ at93c_reg_write((at93c_reg_read() | at93c->cs) & ~at93c->clk & ~(1 << at93c->rdata_shift));
+ lasat_ndelay(50);
+}
+
+static void at93c_end_op(void)
+{
+ at93c_reg_write(at93c_reg_read() & ~at93c->cs);
+ lasat_ndelay(250);
+}
+
+static void at93c_wait(void)
+{
+ at93c_init_op();
+ while (!at93c_read_databit())
+ ;
+ at93c_end_op();
+};
+
+static void at93c_disable_wp(void)
+{
+ at93c_init_op();
+ at93c_write_bits(AT93C_WENCMD, 10);
+ at93c_end_op();
+}
+
+static void at93c_enable_wp(void)
+{
+ at93c_init_op();
+ at93c_write_bits(AT93C_WDSCMD, 10);
+ at93c_end_op();
+}
+
+u8 at93c_read(u8 addr)
+{
+ u8 byte;
+ at93c_init_op();
+ at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_RCMD, 10);
+ byte = at93c_read_byte();
+ at93c_end_op();
+ return byte;
+}
+
+void at93c_write(u8 addr, u8 data)
+{
+ at93c_disable_wp();
+ at93c_init_op();
+ at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_WCMD, 10);
+ at93c_write_bits(data, 8);
+ at93c_end_op();
+ at93c_wait();
+ at93c_enable_wp();
+}
diff --git a/arch/mips/lasat/at93c.h b/arch/mips/lasat/at93c.h
new file mode 100644
index 00000000000..a912ac2171b
--- /dev/null
+++ b/arch/mips/lasat/at93c.h
@@ -0,0 +1,18 @@
+/*
+ * Atmel AT93C46 serial eeprom driver
+ *
+ * Brian Murphy <brian.murphy@eicon.com>
+ *
+ */
+
+extern struct at93c_defs {
+ volatile u32 *reg;
+ volatile u32 *rdata_reg;
+ int rdata_shift;
+ int wdata_shift;
+ u32 cs;
+ u32 clk;
+} *at93c;
+
+u8 at93c_read(u8 addr);
+void at93c_write(u8 addr, u8 data);
diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c
new file mode 100644
index 00000000000..7bbf6cf923c
--- /dev/null
+++ b/arch/mips/lasat/ds1603.c
@@ -0,0 +1,174 @@
+/*
+ * Dallas Semiconductors 1603 RTC driver
+ *
+ * Brian Murphy <brian@murphy.dk>
+ *
+ */
+#include <linux/kernel.h>
+#include <asm/lasat/lasat.h>
+#include <linux/delay.h>
+#include <asm/lasat/ds1603.h>
+
+#include "ds1603.h"
+
+#define READ_TIME_CMD 0x81
+#define SET_TIME_CMD 0x80
+#define TRIMMER_SET_CMD 0xC0
+#define TRIMMER_VALUE_MASK 0x38
+#define TRIMMER_SHIFT 3
+
+struct ds_defs *ds1603 = NULL;
+
+/* HW specific register functions */
+static void rtc_reg_write(unsigned long val)
+{
+ *ds1603->reg = val;
+}
+
+static unsigned long rtc_reg_read(void)
+{
+ unsigned long tmp = *ds1603->reg;
+ return tmp;
+}
+
+static unsigned long rtc_datareg_read(void)
+{
+ unsigned long tmp = *ds1603->data_reg;
+ return tmp;
+}
+
+static void rtc_nrst_high(void)
+{
+ rtc_reg_write(rtc_reg_read() | ds1603->rst);
+}
+
+static void rtc_nrst_low(void)
+{
+ rtc_reg_write(rtc_reg_read() & ~ds1603->rst);
+}
+
+static void rtc_cycle_clock(unsigned long data)
+{
+ data |= ds1603->clk;
+ rtc_reg_write(data);
+ lasat_ndelay(250);
+ if (ds1603->data_reversed)
+ data &= ~ds1603->data;
+ else
+ data |= ds1603->data;
+ data &= ~ds1603->clk;
+ rtc_reg_write(data);
+ lasat_ndelay(250 + ds1603->huge_delay);
+}
+
+static void rtc_write_databit(unsigned int bit)
+{
+ unsigned long data = rtc_reg_read();
+ if (ds1603->data_reversed)
+ bit = !bit;
+ if (bit)
+ data |= ds1603->data;
+ else
+ data &= ~ds1603->data;
+
+ rtc_reg_write(data);
+ lasat_ndelay(50 + ds1603->huge_delay);
+ rtc_cycle_clock(data);
+}
+
+static unsigned int rtc_read_databit(void)
+{
+ unsigned int data;
+
+ data = (rtc_datareg_read() & (1 << ds1603->data_read_shift))
+ >> ds1603->data_read_shift;
+ rtc_cycle_clock(rtc_reg_read());
+ return data;
+}
+
+static void rtc_write_byte(unsigned int byte)
+{
+ int i;
+
+ for (i = 0; i<=7; i++) {
+ rtc_write_databit(byte & 1L);
+ byte >>= 1;
+ }
+}
+
+static void rtc_write_word(unsigned long word)
+{
+ int i;
+
+ for (i = 0; i<=31; i++) {
+ rtc_write_databit(word & 1L);
+ word >>= 1;
+ }
+}
+
+static unsigned long rtc_read_word(void)
+{
+ int i;
+ unsigned long word = 0;
+ unsigned long shift = 0;
+
+ for (i = 0; i<=31; i++) {
+ word |= rtc_read_databit() << shift;
+ shift++;
+ }
+ return word;
+}
+
+static void rtc_init_op(void)
+{
+ rtc_nrst_high();
+
+ rtc_reg_write(rtc_reg_read() & ~ds1603->clk);
+
+ lasat_ndelay(50);
+}
+
+static void rtc_end_op(void)
+{
+ rtc_nrst_low();
+ lasat_ndelay(1000);
+}
+
+/* interface */
+unsigned long ds1603_read(void)
+{
+ unsigned long word;
+ rtc_init_op();
+ rtc_write_byte(READ_TIME_CMD);
+ word = rtc_read_word();
+ rtc_end_op();
+ return word;
+}
+
+int ds1603_set(unsigned long time)
+{
+ rtc_init_op();
+ rtc_write_byte(SET_TIME_CMD);
+ rtc_write_word(time);
+ rtc_end_op();
+
+ return 0;
+}
+
+void ds1603_set_trimmer(unsigned int trimval)
+{
+ rtc_init_op();
+ rtc_write_byte(((trimval << TRIMMER_SHIFT) & TRIMMER_VALUE_MASK)
+ | (TRIMMER_SET_CMD));
+ rtc_end_op();
+}
+
+void ds1603_disable(void)
+{
+ ds1603_set_trimmer(TRIMMER_DISABLE_RTC);
+}
+
+void ds1603_enable(void)
+{
+ ds1603_set_trimmer(TRIMMER_DEFAULT);
+}
diff --git a/arch/mips/lasat/ds1603.h b/arch/mips/lasat/ds1603.h
new file mode 100644
index 00000000000..55f3b0423c2
--- /dev/null
+++ b/arch/mips/lasat/ds1603.h
@@ -0,0 +1,33 @@
+/*
+ * Dallas Semiconductors 1603 RTC driver
+ *
+ * Brian Murphy <brian@murphy.dk>
+ *
+ */
+#ifndef __DS1603_H
+#define __DS1603_H
+
+struct ds_defs {
+ volatile u32 *reg;
+ volatile u32 *data_reg;
+ u32 rst;
+ u32 clk;
+ u32 data;
+ u32 data_read_shift;
+ char data_reversed;
+ u32 huge_delay;
+};
+
+extern struct ds_defs *ds1603;
+
+unsigned long ds1603_read(void);
+int ds1603_set(unsigned long);
+void ds1603_set_trimmer(unsigned int);
+void ds1603_enable(void);
+void ds1603_disable(void);
+void ds1603_init(struct ds_defs *);
+
+#define TRIMMER_DEFAULT 3
+#define TRIMMER_DISABLE_RTC 0
+
+#endif
diff --git a/arch/mips/lasat/image/Makefile b/arch/mips/lasat/image/Makefile
new file mode 100644
index 00000000000..18b6430f11b
--- /dev/null
+++ b/arch/mips/lasat/image/Makefile
@@ -0,0 +1,53 @@
+#
+# MAKEFILE FOR THE MIPS LINUX BOOTLOADER AND ROM DEBUGGER
+#
+# i-data Networks
+#
+# Author: Thomas Horsten <thh@i-data.com>
+#
+
+ifndef Version
+ Version = "$(USER)-test"
+endif
+
+MKLASATIMG = mklasatimg
+MKLASATIMG_ARCH = mq2,mqpro,sp100,sp200
+KERNEL_IMAGE = $(TOPDIR)/vmlinux
+KERNEL_START = $(shell $(NM) $(KERNEL_IMAGE) | grep " _text" | cut -f1 -d\ )
+KERNEL_ENTRY = $(shell $(NM) $(KERNEL_IMAGE) | grep kernel_entry | cut -f1 -d\ )
+
+LDSCRIPT= -L$(obj) -Tromscript.normal
+
+HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
+ -D_kernel_entry=0x$(KERNEL_ENTRY) \
+ -D VERSION="\"$(Version)\"" \
+ -D TIMESTAMP=$(shell date +%s)
+
+$(obj)/head.o: $(obj)/head.S $(KERNEL_IMAGE)
+ $(CC) -fno-pic $(HEAD_DEFINES) -I$(TOPDIR)/include -c -o $@ $<
+
+OBJECTS = head.o kImage.o
+
+rom.sw: $(obj)/rom.sw
+
+$(obj)/rom.sw: $(obj)/rom.bin
+ $(MKLASATIMG) -o $@ -k $^ -m $(MKLASATIMG_ARCH)
+
+$(obj)/rom.bin: $(obj)/rom
+ $(OBJCOPY) -O binary -S $^ $@
+
+# Rule to make the bootloader
+$(obj)/rom: $(addprefix $(obj)/,$(OBJECTS))
+ $(LD) $(LDFLAGS) $(LDSCRIPT) -o $@ $^
+
+$(obj)/%.o: $(obj)/%.gz
+ $(LD) -r -o $@ -b binary $<
+
+$(obj)/%.gz: $(obj)/%.bin
+ gzip -cf -9 $< > $@
+
+$(obj)/kImage.bin: $(KERNEL_IMAGE)
+ $(OBJCOPY) -O binary -S $^ $@
+
+clean:
+ rm -f rom rom.bin rom.sw kImage.bin kImage.o
diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S
new file mode 100644
index 00000000000..426bd7de17b
--- /dev/null
+++ b/arch/mips/lasat/image/head.S
@@ -0,0 +1,31 @@
+#include <asm/lasat/head.h>
+
+ .text
+ .section .text.start, "ax"
+ .set noreorder
+ .set mips3
+
+ /* Magic words identifying a software image */
+ .word LASAT_K_MAGIC0_VAL
+ .word LASAT_K_MAGIC1_VAL
+
+ /* Image header version */
+ .word 0x00000002
+
+ /* image start and size */
+ .word _image_start
+ .word _image_size
+
+ /* start of kernel and entrypoint in uncompressed image */
+ .word _kernel_start
+ .word _kernel_entry
+
+ /* Here we have room for future flags */
+
+ .org 0x40
+reldate:
+ .word TIMESTAMP
+
+ .org 0x50
+release:
+ .string VERSION
diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal
new file mode 100644
index 00000000000..ca22336f6c3
--- /dev/null
+++ b/arch/mips/lasat/image/romscript.normal
@@ -0,0 +1,22 @@
+OUTPUT_ARCH(mips)
+
+SECTIONS
+{
+ .text :
+ {
+ *(.text.start)
+ }
+
+ /* Data in ROM */
+
+ .data ALIGN(0x10) :
+ {
+ *(.data)
+ }
+ _image_start = ADDR(.data);
+ _image_size = SIZEOF(.data);
+
+ .other : {
+ *(.*)
+ }
+}
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
new file mode 100644
index 00000000000..1148a2d20aa
--- /dev/null
+++ b/arch/mips/lasat/interrupt.c
@@ -0,0 +1,160 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Routines for generic manipulation of the interrupts found on the
+ * Lasat boards.
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/lasat/lasatint.h>
+#include <asm/gdb-stub.h>
+
+static volatile int *lasat_int_status = NULL;
+static volatile int *lasat_int_mask = NULL;
+static volatile int lasat_int_mask_shift;
+
+extern asmlinkage void lasatIRQ(void);
+
+void disable_lasat_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift;
+ local_irq_restore(flags);
+}
+
+void enable_lasat_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift;
+ local_irq_restore(flags);
+}
+
+static unsigned int startup_lasat_irq(unsigned int irq)
+{
+ enable_lasat_irq(irq);
+
+ return 0; /* never anything pending */
+}
+
+#define shutdown_lasat_irq disable_lasat_irq
+
+#define mask_and_ack_lasat_irq disable_lasat_irq
+
+static void end_lasat_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_lasat_irq(irq);
+}
+
+static struct hw_interrupt_type lasat_irq_type = {
+ "Lasat",
+ startup_lasat_irq,
+ shutdown_lasat_irq,
+ enable_lasat_irq,
+ disable_lasat_irq,
+ mask_and_ack_lasat_irq,
+ end_lasat_irq,
+ NULL
+};
+
+static inline int ls1bit32(unsigned int x)
+{
+ int b = 31, s;
+
+ s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+ s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s;
+ s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s;
+ s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s;
+ s = 1; if (x << 1 == 0) s = 0; b -= s;
+
+ return b;
+}
+
+static unsigned long (* get_int_status)(void);
+
+static unsigned long get_int_status_100(void)
+{
+ return *lasat_int_status & *lasat_int_mask;
+}
+
+static unsigned long get_int_status_200(void)
+{
+ unsigned long int_status;
+
+ int_status = *lasat_int_status;
+ int_status &= (int_status >> LASATINT_MASK_SHIFT_200) & 0xffff;
+ return int_status;
+}
+
+void lasat_hw0_irqdispatch(struct pt_regs *regs)
+{
+ unsigned long int_status;
+ int irq;
+
+ int_status = get_int_status();
+
+ /* if int_status == 0, then the interrupt has already been cleared */
+ if (int_status) {
+ irq = ls1bit32(int_status);
+
+ do_IRQ(irq, regs);
+ }
+}
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ switch (mips_machtype) {
+ case MACH_LASAT_100:
+ lasat_int_status = (void *)LASAT_INT_STATUS_REG_100;
+ lasat_int_mask = (void *)LASAT_INT_MASK_REG_100;
+ lasat_int_mask_shift = LASATINT_MASK_SHIFT_100;
+ get_int_status = get_int_status_100;
+ *lasat_int_mask = 0;
+ break;
+ case MACH_LASAT_200:
+ lasat_int_status = (void *)LASAT_INT_STATUS_REG_200;
+ lasat_int_mask = (void *)LASAT_INT_MASK_REG_200;
+ lasat_int_mask_shift = LASATINT_MASK_SHIFT_200;
+ get_int_status = get_int_status_200;
+ *lasat_int_mask &= 0xffff;
+ break;
+ default:
+ panic("arch_init_irq: mips_machtype incorrect");
+ }
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, lasatIRQ);
+
+ for (i = 0; i <= LASATINT_END; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = 0;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &lasat_irq_type;
+ }
+}
diff --git a/arch/mips/lasat/lasatIRQ.S b/arch/mips/lasat/lasatIRQ.S
new file mode 100644
index 00000000000..2a2b0d05656
--- /dev/null
+++ b/arch/mips/lasat/lasatIRQ.S
@@ -0,0 +1,69 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Interrupt exception dispatch code.
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ .text
+ .set noreorder
+ .align 5
+ NESTED(lasatIRQ, PT_SIZE, sp)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+ .set noreorder
+
+ mfc0 s0, CP0_CAUSE # get irq mask
+
+ /* First we check for r4k counter/timer IRQ. */
+ andi a0, s0, CAUSEF_IP7
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
+
+ /* Wheee, a timer interrupt. */
+ li a0, 7
+ jal ll_timer_interrupt
+ move a1, sp
+
+ j ret_from_irq
+ nop
+
+1:
+ /* Wheee, combined hardware level zero interrupt. */
+ jal lasat_hw0_irqdispatch
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ /*
+ * Here by mistake? This is possible, what can happen is that by the
+ * time we take the exception the IRQ pin goes low, so just leave if
+ * this is the case.
+ */
+ move a1,s0
+ mfc0 a1, CP0_EPC
+
+ j ret_from_irq
+ nop
+ END(lasatIRQ)
diff --git a/arch/mips/lasat/lasat_board.c b/arch/mips/lasat/lasat_board.c
new file mode 100644
index 00000000000..8c784bcf111
--- /dev/null
+++ b/arch/mips/lasat/lasat_board.c
@@ -0,0 +1,277 @@
+/*
+ * Thomas Horsten <thh@lasat.com>
+ * Copyright (C) 2000 LASAT Networks A/S.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Routines specific to the LASAT boards
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/crc32.h>
+#include <asm/lasat/lasat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include "at93c.h"
+/* New model description table */
+#include "lasat_models.h"
+
+#define EEPROM_CRC(data, len) (~0 ^ crc32(~0, data, len))
+
+struct lasat_info lasat_board_info;
+
+void update_bcastaddr(void);
+
+int EEPROMRead(unsigned int pos, unsigned char *data, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ *data++ = at93c_read(pos++);
+
+ return 0;
+}
+int EEPROMWrite(unsigned int pos, unsigned char *data, int len)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ at93c_write(pos++, *data++);
+
+ return 0;
+}
+
+static void init_flash_sizes(void)
+{
+ int i;
+ unsigned long *lb = lasat_board_info.li_flashpart_base;
+ unsigned long *ls = lasat_board_info.li_flashpart_size;
+
+ ls[LASAT_MTD_BOOTLOADER] = 0x40000;
+ ls[LASAT_MTD_SERVICE] = 0xC0000;
+ ls[LASAT_MTD_NORMAL] = 0x100000;
+
+ if (mips_machtype == MACH_LASAT_100) {
+ lasat_board_info.li_flash_base = 0x1e000000;
+
+ lb[LASAT_MTD_BOOTLOADER] = 0x1e400000;
+
+ if (lasat_board_info.li_flash_size > 0x200000) {
+ ls[LASAT_MTD_CONFIG] = 0x100000;
+ ls[LASAT_MTD_FS] = 0x500000;
+ }
+ } else {
+ lasat_board_info.li_flash_base = 0x10000000;
+
+ if (lasat_board_info.li_flash_size < 0x1000000) {
+ lb[LASAT_MTD_BOOTLOADER] = 0x10000000;
+ ls[LASAT_MTD_CONFIG] = 0x100000;
+ if (lasat_board_info.li_flash_size >= 0x400000) {
+ ls[LASAT_MTD_FS] = lasat_board_info.li_flash_size - 0x300000;
+ }
+ }
+ }
+
+ for (i = 1; i < LASAT_MTD_LAST; i++)
+ lb[i] = lb[i-1] + ls[i-1];
+}
+
+int lasat_init_board_info(void)
+{
+ int c;
+ unsigned long crc;
+ unsigned long cfg0, cfg1;
+ const product_info_t *ppi;
+ int i_n_base_models = N_BASE_MODELS;
+ const char * const * i_txt_base_models = txt_base_models;
+ int i_n_prids = N_PRIDS;
+
+ memset(&lasat_board_info, 0, sizeof(lasat_board_info));
+
+ /* First read the EEPROM info */
+ EEPROMRead(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
+ sizeof(struct lasat_eeprom_struct));
+
+ /* Check the CRC */
+ crc = EEPROM_CRC((unsigned char *)(&lasat_board_info.li_eeprom_info),
+ sizeof(struct lasat_eeprom_struct) - 4);
+
+ if (crc != lasat_board_info.li_eeprom_info.crc32) {
+ prom_printf("WARNING...\nWARNING...\nEEPROM CRC does not match calculated, attempting to soldier on...\n");
+ }
+
+ if (lasat_board_info.li_eeprom_info.version != LASAT_EEPROM_VERSION)
+ {
+ prom_printf("WARNING...\nWARNING...\nEEPROM version %d, wanted version %d, attempting to soldier on...\n",
+ (unsigned int)lasat_board_info.li_eeprom_info.version,
+ LASAT_EEPROM_VERSION);
+ }
+
+ cfg0 = lasat_board_info.li_eeprom_info.cfg[0];
+ cfg1 = lasat_board_info.li_eeprom_info.cfg[1];
+
+ if ( LASAT_W0_DSCTYPE(cfg0) != 1) {
+ prom_printf("WARNING...\nWARNING...\nInvalid configuration read from EEPROM, attempting to soldier on...");
+ }
+ /* We have a valid configuration */
+
+ switch (LASAT_W0_SDRAMBANKSZ(cfg0)) {
+ case 0:
+ lasat_board_info.li_memsize = 0x0800000;
+ break;
+ case 1:
+ lasat_board_info.li_memsize = 0x1000000;
+ break;
+ case 2:
+ lasat_board_info.li_memsize = 0x2000000;
+ break;
+ case 3:
+ lasat_board_info.li_memsize = 0x4000000;
+ break;
+ case 4:
+ lasat_board_info.li_memsize = 0x8000000;
+ break;
+ default:
+ lasat_board_info.li_memsize = 0;
+ }
+
+ switch (LASAT_W0_SDRAMBANKS(cfg0)) {
+ case 0:
+ break;
+ case 1:
+ lasat_board_info.li_memsize *= 2;
+ break;
+ default:
+ break;
+ }
+
+ switch (LASAT_W0_BUSSPEED(cfg0)) {
+ case 0x0:
+ lasat_board_info.li_bus_hz = 60000000;
+ break;
+ case 0x1:
+ lasat_board_info.li_bus_hz = 66000000;
+ break;
+ case 0x2:
+ lasat_board_info.li_bus_hz = 66666667;
+ break;
+ case 0x3:
+ lasat_board_info.li_bus_hz = 80000000;
+ break;
+ case 0x4:
+ lasat_board_info.li_bus_hz = 83333333;
+ break;
+ case 0x5:
+ lasat_board_info.li_bus_hz = 100000000;
+ break;
+ }
+
+ switch (LASAT_W0_CPUCLK(cfg0)) {
+ case 0x0:
+ lasat_board_info.li_cpu_hz =
+ lasat_board_info.li_bus_hz;
+ break;
+ case 0x1:
+ lasat_board_info.li_cpu_hz =
+ lasat_board_info.li_bus_hz +
+ (lasat_board_info.li_bus_hz >> 1);
+ break;
+ case 0x2:
+ lasat_board_info.li_cpu_hz =
+ lasat_board_info.li_bus_hz +
+ lasat_board_info.li_bus_hz;
+ break;
+ case 0x3:
+ lasat_board_info.li_cpu_hz =
+ lasat_board_info.li_bus_hz +
+ lasat_board_info.li_bus_hz +
+ (lasat_board_info.li_bus_hz >> 1);
+ break;
+ case 0x4:
+ lasat_board_info.li_cpu_hz =
+ lasat_board_info.li_bus_hz +
+ lasat_board_info.li_bus_hz +
+ lasat_board_info.li_bus_hz;
+ break;
+ }
+
+ /* Flash size */
+ switch (LASAT_W1_FLASHSIZE(cfg1)) {
+ case 0:
+ lasat_board_info.li_flash_size = 0x200000;
+ break;
+ case 1:
+ lasat_board_info.li_flash_size = 0x400000;
+ break;
+ case 2:
+ lasat_board_info.li_flash_size = 0x800000;
+ break;
+ case 3:
+ lasat_board_info.li_flash_size = 0x1000000;
+ break;
+ case 4:
+ lasat_board_info.li_flash_size = 0x2000000;
+ break;
+ }
+
+ init_flash_sizes();
+
+ lasat_board_info.li_bmid = LASAT_W0_BMID(cfg0);
+ lasat_board_info.li_prid = lasat_board_info.li_eeprom_info.prid;
+ if (lasat_board_info.li_prid == 0xffff || lasat_board_info.li_prid == 0)
+ lasat_board_info.li_prid = lasat_board_info.li_bmid;
+
+ /* Base model stuff */
+ if (lasat_board_info.li_bmid > i_n_base_models)
+ lasat_board_info.li_bmid = i_n_base_models;
+ strcpy(lasat_board_info.li_bmstr, i_txt_base_models[lasat_board_info.li_bmid]);
+
+ /* Product ID dependent values */
+ c = lasat_board_info.li_prid;
+ if (c >= i_n_prids) {
+ strcpy(lasat_board_info.li_namestr, "Unknown Model");
+ strcpy(lasat_board_info.li_typestr, "Unknown Type");
+ } else {
+ ppi = &vendor_info_table[0].vi_product_info[c];
+ strcpy(lasat_board_info.li_namestr, ppi->pi_name);
+ if (ppi->pi_type)
+ strcpy(lasat_board_info.li_typestr, ppi->pi_type);
+ else
+ sprintf(lasat_board_info.li_typestr, "%d",10*c);
+ }
+
+#if defined(CONFIG_INET) && defined(CONFIG_SYSCTL)
+ update_bcastaddr();
+#endif
+
+ return 0;
+}
+
+void lasat_write_eeprom_info(void)
+{
+ unsigned long crc;
+
+ /* Generate the CRC */
+ crc = EEPROM_CRC((unsigned char *)(&lasat_board_info.li_eeprom_info),
+ sizeof(struct lasat_eeprom_struct) - 4);
+ lasat_board_info.li_eeprom_info.crc32 = crc;
+
+ /* Write the EEPROM info */
+ EEPROMWrite(0, (unsigned char *)&lasat_board_info.li_eeprom_info,
+ sizeof(struct lasat_eeprom_struct));
+}
+
diff --git a/arch/mips/lasat/lasat_models.h b/arch/mips/lasat/lasat_models.h
new file mode 100644
index 00000000000..ae0c5d0bd40
--- /dev/null
+++ b/arch/mips/lasat/lasat_models.h
@@ -0,0 +1,63 @@
+/*
+ * Model description tables
+ */
+
+typedef struct product_info_t {
+ const char *pi_name;
+ const char *pi_type;
+} product_info_t;
+
+typedef struct vendor_info_t {
+ const char *vi_name;
+ const product_info_t *vi_product_info;
+} vendor_info_t;
+
+/*
+ * Base models
+ */
+static const char * const txt_base_models[] = {
+ "MQ 2", "MQ Pro", "SP 25", "SP 50", "SP 100", "SP 5000", "SP 7000", "SP 1000", "Unknown"
+};
+#define N_BASE_MODELS (sizeof(txt_base_models)/sizeof(char*)-1)
+
+/*
+ * Eicon Networks
+ */
+static const char txt_en_mq[] = "Masquerade";
+static const char txt_en_sp[] = "Safepipe";
+
+static const product_info_t product_info_eicon[] = {
+ { txt_en_mq, "II" }, /* 0 */
+ { txt_en_mq, "Pro" }, /* 1 */
+ { txt_en_sp, "25" }, /* 2 */
+ { txt_en_sp, "50" }, /* 3 */
+ { txt_en_sp, "100" }, /* 4 */
+ { txt_en_sp, "5000" }, /* 5 */
+ { txt_en_sp, "7000" }, /* 6 */
+ { txt_en_sp, "30" }, /* 7 */
+ { txt_en_sp, "5100" }, /* 8 */
+ { txt_en_sp, "7100" }, /* 9 */
+ { txt_en_sp, "1110" }, /* 10 */
+ { txt_en_sp, "3020" }, /* 11 */
+ { txt_en_sp, "3030" }, /* 12 */
+ { txt_en_sp, "5020" }, /* 13 */
+ { txt_en_sp, "5030" }, /* 14 */
+ { txt_en_sp, "1120" }, /* 15 */
+ { txt_en_sp, "1130" }, /* 16 */
+ { txt_en_sp, "6010" }, /* 17 */
+ { txt_en_sp, "6110" }, /* 18 */
+ { txt_en_sp, "6210" }, /* 19 */
+ { txt_en_sp, "1020" }, /* 20 */
+ { txt_en_sp, "1040" }, /* 21 */
+ { txt_en_sp, "1050" }, /* 22 */
+ { txt_en_sp, "1060" }, /* 23 */
+};
+#define N_PRIDS (sizeof(product_info_eicon)/sizeof(product_info_t))
+
+/*
+ * The vendor table
+ */
+static vendor_info_t const vendor_info_table[] = {
+ { "Eicon Networks", product_info_eicon },
+};
+#define N_VENDORS (sizeof(vendor_info_table)/sizeof(vendor_info_t))
diff --git a/arch/mips/lasat/picvue.c b/arch/mips/lasat/picvue.c
new file mode 100644
index 00000000000..5637cd15392
--- /dev/null
+++ b/arch/mips/lasat/picvue.c
@@ -0,0 +1,240 @@
+/*
+ * Picvue PVC160206 display driver
+ *
+ * Brian Murphy <brian@murphy.dk>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <asm/bootinfo.h>
+#include <asm/lasat/lasat.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include "picvue.h"
+
+#define PVC_BUSY 0x80
+#define PVC_NLINES 2
+#define PVC_DISPMEM 80
+#define PVC_LINELEN PVC_DISPMEM / PVC_NLINES
+
+struct pvc_defs *picvue = NULL;
+
+DECLARE_MUTEX(pvc_sem);
+
+static void pvc_reg_write(u32 val)
+{
+ *picvue->reg = val;
+}
+
+static u32 pvc_reg_read(void)
+{
+ u32 tmp = *picvue->reg;
+ return tmp;
+}
+
+static void pvc_write_byte(u32 data, u8 byte)
+{
+ data |= picvue->e;
+ pvc_reg_write(data);
+ data &= ~picvue->data_mask;
+ data |= byte << picvue->data_shift;
+ pvc_reg_write(data);
+ ndelay(220);
+ pvc_reg_write(data & ~picvue->e);
+ ndelay(220);
+}
+
+static u8 pvc_read_byte(u32 data)
+{
+ u8 byte;
+
+ data |= picvue->e;
+ pvc_reg_write(data);
+ ndelay(220);
+ byte = (pvc_reg_read() & picvue->data_mask) >> picvue->data_shift;
+ data &= ~picvue->e;
+ pvc_reg_write(data);
+ ndelay(220);
+ return byte;
+}
+
+static u8 pvc_read_data(void)
+{
+ u32 data = pvc_reg_read();
+ u8 byte;
+ data |= picvue->rw;
+ data &= ~picvue->rs;
+ pvc_reg_write(data);
+ ndelay(40);
+ byte = pvc_read_byte(data);
+ data |= picvue->rs;
+ pvc_reg_write(data);
+ return byte;
+}
+
+#define TIMEOUT 1000
+static int pvc_wait(void)
+{
+ int i = TIMEOUT;
+ int err = 0;
+
+ while ((pvc_read_data() & PVC_BUSY) && i)
+ i--;
+ if (i == 0)
+ err = -ETIME;
+
+ return err;
+}
+
+#define MODE_INST 0
+#define MODE_DATA 1
+static void pvc_write(u8 byte, int mode)
+{
+ u32 data = pvc_reg_read();
+ data &= ~picvue->rw;
+ if (mode == MODE_DATA)
+ data |= picvue->rs;
+ else
+ data &= ~picvue->rs;
+ pvc_reg_write(data);
+ ndelay(40);
+ pvc_write_byte(data, byte);
+ if (mode == MODE_DATA)
+ data &= ~picvue->rs;
+ else
+ data |= picvue->rs;
+ pvc_reg_write(data);
+ pvc_wait();
+}
+
+void pvc_write_string(const unsigned char *str, u8 addr, int line)
+{
+ int i = 0;
+
+ if (line > 0 && (PVC_NLINES > 1))
+ addr += 0x40 * line;
+ pvc_write(0x80 | addr, MODE_INST);
+
+ while (*str != 0 && i < PVC_LINELEN) {
+ pvc_write(*str++, MODE_DATA);
+ i++;
+ }
+}
+
+void pvc_write_string_centered(const unsigned char *str, int line)
+{
+ int len = strlen(str);
+ u8 addr;
+
+ if (len > PVC_VISIBLE_CHARS)
+ addr = 0;
+ else
+ addr = (PVC_VISIBLE_CHARS - strlen(str))/2;
+
+ pvc_write_string(str, addr, line);
+}
+
+void pvc_dump_string(const unsigned char *str)
+{
+ int len = strlen(str);
+
+ pvc_write_string(str, 0, 0);
+ if (len > PVC_VISIBLE_CHARS)
+ pvc_write_string(&str[PVC_VISIBLE_CHARS], 0, 1);
+}
+
+#define BM_SIZE 8
+#define MAX_PROGRAMMABLE_CHARS 8
+int pvc_program_cg(int charnum, u8 bitmap[BM_SIZE])
+{
+ int i;
+ int addr;
+
+ if (charnum > MAX_PROGRAMMABLE_CHARS)
+ return -ENOENT;
+
+ addr = charnum * 8;
+ pvc_write(0x40 | addr, MODE_INST);
+
+ for (i=0; i<BM_SIZE; i++)
+ pvc_write(bitmap[i], MODE_DATA);
+ return 0;
+}
+
+#define FUNC_SET_CMD 0x20
+#define EIGHT_BYTE (1 << 4)
+#define FOUR_BYTE 0
+#define TWO_LINES (1 << 3)
+#define ONE_LINE 0
+#define LARGE_FONT (1 << 2)
+#define SMALL_FONT 0
+static void pvc_funcset(u8 cmd)
+{
+ pvc_write(FUNC_SET_CMD | (cmd & (EIGHT_BYTE|TWO_LINES|LARGE_FONT)), MODE_INST);
+}
+
+#define ENTRYMODE_CMD 0x4
+#define AUTO_INC (1 << 1)
+#define AUTO_DEC 0
+#define CURSOR_FOLLOWS_DISP (1 << 0)
+static void pvc_entrymode(u8 cmd)
+{
+ pvc_write(ENTRYMODE_CMD | (cmd & (AUTO_INC|CURSOR_FOLLOWS_DISP)), MODE_INST);
+}
+
+#define DISP_CNT_CMD 0x08
+#define DISP_OFF 0
+#define DISP_ON (1 << 2)
+#define CUR_ON (1 << 1)
+#define CUR_BLINK (1 << 0)
+void pvc_dispcnt(u8 cmd)
+{
+ pvc_write(DISP_CNT_CMD | (cmd & (DISP_ON|CUR_ON|CUR_BLINK)), MODE_INST);
+}
+
+#define MOVE_CMD 0x10
+#define DISPLAY (1 << 3)
+#define CURSOR 0
+#define RIGHT (1 << 2)
+#define LEFT 0
+void pvc_move(u8 cmd)
+{
+ pvc_write(MOVE_CMD | (cmd & (DISPLAY|RIGHT)), MODE_INST);
+}
+
+#define CLEAR_CMD 0x1
+void pvc_clear(void)
+{
+ pvc_write(CLEAR_CMD, MODE_INST);
+}
+
+#define HOME_CMD 0x2
+void pvc_home(void)
+{
+ pvc_write(HOME_CMD, MODE_INST);
+}
+
+int pvc_init(void)
+{
+ u8 cmd = EIGHT_BYTE;
+
+ if (PVC_NLINES == 2)
+ cmd |= (SMALL_FONT|TWO_LINES);
+ else
+ cmd |= (LARGE_FONT|ONE_LINE);
+ pvc_funcset(cmd);
+ pvc_dispcnt(DISP_ON);
+ pvc_entrymode(AUTO_INC);
+
+ pvc_clear();
+ pvc_write_string_centered("Display", 0);
+ pvc_write_string_centered("Initialized", 1);
+
+ return 0;
+}
+
+module_init(pvc_init);
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/lasat/picvue.h b/arch/mips/lasat/picvue.h
new file mode 100644
index 00000000000..74a39039135
--- /dev/null
+++ b/arch/mips/lasat/picvue.h
@@ -0,0 +1,48 @@
+/*
+ * Picvue PVC160206 display driver
+ *
+ * Brian Murphy <brian.murphy@eicon.com>
+ *
+ */
+#include <asm/semaphore.h>
+
+struct pvc_defs {
+ volatile u32 *reg;
+ u32 data_shift;
+ u32 data_mask;
+ u32 e;
+ u32 rw;
+ u32 rs;
+};
+
+extern struct pvc_defs *picvue;
+
+#define PVC_NLINES 2
+#define PVC_DISPMEM 80
+#define PVC_LINELEN PVC_DISPMEM / PVC_NLINES
+#define PVC_VISIBLE_CHARS 16
+
+void pvc_write_string(const unsigned char *str, u8 addr, int line);
+void pvc_write_string_centered(const unsigned char *str, int line);
+void pvc_dump_string(const unsigned char *str);
+
+#define BM_SIZE 8
+#define MAX_PROGRAMMABLE_CHARS 8
+int pvc_program_cg(int charnum, u8 bitmap[BM_SIZE]);
+
+void pvc_dispcnt(u8 cmd);
+#define DISP_OFF 0
+#define DISP_ON (1 << 2)
+#define CUR_ON (1 << 1)
+#define CUR_BLINK (1 << 0)
+
+void pvc_move(u8 cmd);
+#define DISPLAY (1 << 3)
+#define CURSOR 0
+#define RIGHT (1 << 2)
+#define LEFT 0
+
+void pvc_clear(void);
+void pvc_home(void);
+
+extern struct semaphore pvc_sem;
diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c
new file mode 100644
index 00000000000..eaa2b462512
--- /dev/null
+++ b/arch/mips/lasat/picvue_proc.c
@@ -0,0 +1,186 @@
+/*
+ * Picvue PVC160206 display driver
+ *
+ * Brian Murphy <brian.murphy@eicon.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+
+#include <linux/timer.h>
+
+#include "picvue.h"
+
+static char pvc_lines[PVC_NLINES][PVC_LINELEN+1];
+static int pvc_linedata[PVC_NLINES];
+static struct proc_dir_entry *pvc_display_dir;
+static char *pvc_linename[PVC_NLINES] = {"line1", "line2"};
+#define DISPLAY_DIR_NAME "display"
+static int scroll_dir = 0, scroll_interval = 0;
+
+static struct timer_list timer;
+
+static void pvc_display(unsigned long data) {
+ int i;
+
+ pvc_clear();
+ for (i=0; i<PVC_NLINES; i++)
+ pvc_write_string(pvc_lines[i], 0, i);
+}
+
+static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0);
+
+static int pvc_proc_read_line(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ char *origpage = page;
+ int lineno = *(int *)data;
+
+ if (lineno < 0 || lineno > PVC_NLINES) {
+ printk("proc_read_line: invalid lineno %d\n", lineno);
+ return 0;
+ }
+
+ down(&pvc_sem);
+ page += sprintf(page, "%s\n", pvc_lines[lineno]);
+ up(&pvc_sem);
+
+ return page - origpage;
+}
+
+static int pvc_proc_write_line(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int origcount = count;
+ int lineno = *(int *)data;
+
+ if (lineno < 0 || lineno > PVC_NLINES) {
+ printk("proc_write_line: invalid lineno %d\n", lineno);
+ return origcount;
+ }
+
+ if (count > PVC_LINELEN)
+ count = PVC_LINELEN;
+
+ if (buffer[count-1] == '\n')
+ count--;
+
+ down(&pvc_sem);
+ strncpy(pvc_lines[lineno], buffer, count);
+ pvc_lines[lineno][count] = '\0';
+ up(&pvc_sem);
+
+ tasklet_schedule(&pvc_display_tasklet);
+
+ return origcount;
+}
+
+static int pvc_proc_write_scroll(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int origcount = count;
+ int cmd = simple_strtol(buffer, NULL, 10);
+
+ down(&pvc_sem);
+ if (scroll_interval != 0)
+ del_timer(&timer);
+
+ if (cmd == 0) {
+ scroll_dir = 0;
+ scroll_interval = 0;
+ } else {
+ if (cmd < 0) {
+ scroll_dir = -1;
+ scroll_interval = -cmd;
+ } else {
+ scroll_dir = 1;
+ scroll_interval = cmd;
+ }
+ add_timer(&timer);
+ }
+ up(&pvc_sem);
+
+ return origcount;
+}
+
+static int pvc_proc_read_scroll(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ char *origpage = page;
+
+ down(&pvc_sem);
+ page += sprintf(page, "%d\n", scroll_dir * scroll_interval);
+ up(&pvc_sem);
+
+ return page - origpage;
+}
+
+
+void pvc_proc_timerfunc(unsigned long data)
+{
+ if (scroll_dir < 0)
+ pvc_move(DISPLAY|RIGHT);
+ else if (scroll_dir > 0)
+ pvc_move(DISPLAY|LEFT);
+
+ timer.expires = jiffies + scroll_interval;
+ add_timer(&timer);
+}
+
+static void pvc_proc_cleanup(void)
+{
+ int i;
+ for (i=0; i<PVC_NLINES; i++)
+ remove_proc_entry(pvc_linename[i], pvc_display_dir);
+ remove_proc_entry("scroll", pvc_display_dir);
+ remove_proc_entry(DISPLAY_DIR_NAME, NULL);
+
+ del_timer(&timer);
+}
+
+static int __init pvc_proc_init(void)
+{
+ struct proc_dir_entry *proc_entry;
+ int i;
+
+ pvc_display_dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
+ if (pvc_display_dir == NULL)
+ goto error;
+
+ for (i=0; i<PVC_NLINES; i++) {
+ strcpy(pvc_lines[i], "");
+ pvc_linedata[i] = i;
+ }
+ for (i=0; i<PVC_NLINES; i++) {
+ proc_entry = create_proc_entry(pvc_linename[i], 0644, pvc_display_dir);
+ if (proc_entry == NULL)
+ goto error;
+ proc_entry->read_proc = pvc_proc_read_line;
+ proc_entry->write_proc = pvc_proc_write_line;
+ proc_entry->data = &pvc_linedata[i];
+ }
+ proc_entry = create_proc_entry("scroll", 0644, pvc_display_dir);
+ if (proc_entry == NULL)
+ goto error;
+ proc_entry->write_proc = pvc_proc_write_scroll;
+ proc_entry->read_proc = pvc_proc_read_scroll;
+
+ init_timer(&timer);
+ timer.function = pvc_proc_timerfunc;
+
+ return 0;
+error:
+ pvc_proc_cleanup();
+ return -ENOMEM;
+}
+
+module_init(pvc_proc_init);
+module_exit(pvc_proc_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c
new file mode 100644
index 00000000000..ca62881c9e5
--- /dev/null
+++ b/arch/mips/lasat/prom.c
@@ -0,0 +1,143 @@
+/*
+ * PROM interface routines.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+#include <asm/lasat/lasat.h>
+#include <asm/cpu.h>
+
+#include "at93c.h"
+#include <asm/lasat/eeprom.h>
+#include "prom.h"
+
+#define RESET_VECTOR 0xbfc00000
+#define PROM_JUMP_TABLE_ENTRY(n) (*((u32 *)(RESET_VECTOR + 0x20) + n))
+#define PROM_DISPLAY_ADDR PROM_JUMP_TABLE_ENTRY(0)
+#define PROM_PUTC_ADDR PROM_JUMP_TABLE_ENTRY(1)
+#define PROM_MONITOR_ADDR PROM_JUMP_TABLE_ENTRY(2)
+
+static void null_prom_printf(const char * fmt, ...)
+{
+}
+
+static void null_prom_display(const char *string, int pos, int clear)
+{
+}
+
+static void null_prom_monitor(void)
+{
+}
+
+static void null_prom_putc(char c)
+{
+}
+
+/* these are functions provided by the bootloader */
+static void (* prom_putc)(char c) = null_prom_putc;
+void (* prom_printf)(const char * fmt, ...) = null_prom_printf;
+void (* prom_display)(const char *string, int pos, int clear) =
+ null_prom_display;
+void (* prom_monitor)(void) = null_prom_monitor;
+
+unsigned int lasat_ndelay_divider;
+
+#define PROM_PRINTFBUF_SIZE 256
+static char prom_printfbuf[PROM_PRINTFBUF_SIZE];
+
+static void real_prom_printf(const char * fmt, ...)
+{
+ va_list ap;
+ int len;
+ char *c = prom_printfbuf;
+ int i;
+
+ va_start(ap, fmt);
+ len = vsnprintf(prom_printfbuf, PROM_PRINTFBUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ /* output overflowed the buffer */
+ if (len < 0 || len > PROM_PRINTFBUF_SIZE)
+ len = PROM_PRINTFBUF_SIZE;
+
+ for (i=0; i < len; i++) {
+ if (*c == '\n')
+ prom_putc('\r');
+ prom_putc(*c++);
+ }
+}
+
+static void setup_prom_vectors(void)
+{
+ u32 version = *(u32 *)(RESET_VECTOR + 0x90);
+
+ if (version >= 307) {
+ prom_display = (void *)PROM_DISPLAY_ADDR;
+ prom_putc = (void *)PROM_PUTC_ADDR;
+ prom_printf = real_prom_printf;
+ prom_monitor = (void *)PROM_MONITOR_ADDR;
+ }
+ prom_printf("prom vectors set up\n");
+}
+
+static struct at93c_defs at93c_defs[N_MACHTYPES] = {
+ {(void *)AT93C_REG_100, (void *)AT93C_RDATA_REG_100, AT93C_RDATA_SHIFT_100,
+ AT93C_WDATA_SHIFT_100, AT93C_CS_M_100, AT93C_CLK_M_100},
+ {(void *)AT93C_REG_200, (void *)AT93C_RDATA_REG_200, AT93C_RDATA_SHIFT_200,
+ AT93C_WDATA_SHIFT_200, AT93C_CS_M_200, AT93C_CLK_M_200},
+};
+
+void __init prom_init(void)
+{
+ int argc = fw_arg0;
+ char **argv = (char **) fw_arg1;
+
+ setup_prom_vectors();
+
+ if (current_cpu_data.cputype == CPU_R5000) {
+ prom_printf("LASAT 200 board\n");
+ mips_machtype = MACH_LASAT_200;
+ lasat_ndelay_divider = LASAT_200_DIVIDER;
+ } else {
+ prom_printf("LASAT 100 board\n");
+ mips_machtype = MACH_LASAT_100;
+ lasat_ndelay_divider = LASAT_100_DIVIDER;
+ }
+
+ at93c = &at93c_defs[mips_machtype];
+
+ lasat_init_board_info(); /* Read info from EEPROM */
+
+ mips_machgroup = MACH_GROUP_LASAT;
+
+ /* Get the command line */
+ if (argc > 0) {
+ strncpy(arcs_cmdline, argv[0], CL_SIZE-1);
+ arcs_cmdline[CL_SIZE-1] = '\0';
+ }
+
+ /* Set the I/O base address */
+ set_io_port_base(KSEG1);
+
+ /* Set memory regions */
+ ioport_resource.start = 0;
+ ioport_resource.end = 0xffffffff; /* Wrong, fixme. */
+
+ add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM);
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+ return 0;
+}
+
+const char *get_system_type(void)
+{
+ return lasat_board_info.li_bmstr;
+}
diff --git a/arch/mips/lasat/prom.h b/arch/mips/lasat/prom.h
new file mode 100644
index 00000000000..07be7bf1e4a
--- /dev/null
+++ b/arch/mips/lasat/prom.h
@@ -0,0 +1,6 @@
+#ifndef PROM_H
+#define PROM_H
+extern void (* prom_display)(const char *string, int pos, int clear);
+extern void (* prom_monitor)(void);
+extern void (* prom_printf)(const char * fmt, ...);
+#endif
diff --git a/arch/mips/lasat/reset.c b/arch/mips/lasat/reset.c
new file mode 100644
index 00000000000..37e4912ee1c
--- /dev/null
+++ b/arch/mips/lasat/reset.c
@@ -0,0 +1,67 @@
+/*
+ * Thomas Horsten <thh@lasat.com>
+ * Copyright (C) 2000 LASAT Networks A/S.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Reset the LASAT board.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/lasat/lasat.h>
+#include "picvue.h"
+#include "prom.h"
+
+static void lasat_machine_restart(char *command);
+static void lasat_machine_halt(void);
+
+/* Used to set machine to boot in service mode via /proc interface */
+int lasat_boot_to_service = 0;
+
+static void lasat_machine_restart(char *command)
+{
+ local_irq_disable();
+
+ if (lasat_boot_to_service) {
+ printk("machine_restart: Rebooting to service mode\n");
+ *(volatile unsigned int *)0xa0000024 = 0xdeadbeef;
+ *(volatile unsigned int *)0xa00000fc = 0xfedeabba;
+ }
+ *lasat_misc->reset_reg = 0xbedead;
+ for (;;) ;
+}
+
+#define MESSAGE "System halted"
+static void lasat_machine_halt(void)
+{
+ local_irq_disable();
+
+ /* Disable interrupts and loop forever */
+ printk(KERN_NOTICE MESSAGE "\n");
+#ifdef CONFIG_PICVUE
+ pvc_clear();
+ pvc_write_string(MESSAGE, 0, 0);
+#endif
+ prom_monitor();
+ for (;;) ;
+}
+
+void lasat_reboot_setup(void)
+{
+ _machine_restart = lasat_machine_restart;
+ _machine_halt = lasat_machine_halt;
+ _machine_power_off = lasat_machine_halt;
+}
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
new file mode 100644
index 00000000000..e371ed5cbe3
--- /dev/null
+++ b/arch/mips/lasat/setup.c
@@ -0,0 +1,192 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999 MIPS Technologies, Inc. All rights reserved.
+ *
+ * Thomas Horsten <thh@lasat.com>
+ * Copyright (C) 2000 LASAT Networks A/S.
+ *
+ * Brian Murphy <brian@murphy.dk>
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Lasat specific setup.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/time.h>
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/serial.h>
+#include <asm/lasat/lasat.h>
+#include <asm/lasat/serial.h>
+
+#ifdef CONFIG_PICVUE
+#include <linux/notifier.h>
+#endif
+
+#include "ds1603.h"
+#include <asm/lasat/ds1603.h>
+#include <asm/lasat/picvue.h>
+#include <asm/lasat/eeprom.h>
+
+#include "prom.h"
+
+int lasat_command_line = 0;
+void lasatint_init(void);
+
+extern void lasat_reboot_setup(void);
+extern void pcisetup(void);
+extern void edhac_init(void *, void *, void *);
+extern void addrflt_init(void);
+
+struct lasat_misc lasat_misc_info[N_MACHTYPES] = {
+ {(void *)KSEG1ADDR(0x1c840000), (void *)KSEG1ADDR(0x1c800000), 2},
+ {(void *)KSEG1ADDR(0x11080000), (void *)KSEG1ADDR(0x11000000), 6}
+};
+
+struct lasat_misc *lasat_misc = NULL;
+
+#ifdef CONFIG_DS1603
+static struct ds_defs ds_defs[N_MACHTYPES] = {
+ { (void *)DS1603_REG_100, (void *)DS1603_REG_100,
+ DS1603_RST_100, DS1603_CLK_100, DS1603_DATA_100,
+ DS1603_DATA_SHIFT_100, 0, 0 },
+ { (void *)DS1603_REG_200, (void *)DS1603_DATA_REG_200,
+ DS1603_RST_200, DS1603_CLK_200, DS1603_DATA_200,
+ DS1603_DATA_READ_SHIFT_200, 1, 2000 }
+};
+#endif
+
+#ifdef CONFIG_PICVUE
+#include "picvue.h"
+static struct pvc_defs pvc_defs[N_MACHTYPES] = {
+ { (void *)PVC_REG_100, PVC_DATA_SHIFT_100, PVC_DATA_M_100,
+ PVC_E_100, PVC_RW_100, PVC_RS_100 },
+ { (void *)PVC_REG_200, PVC_DATA_SHIFT_200, PVC_DATA_M_200,
+ PVC_E_200, PVC_RW_200, PVC_RS_200 }
+};
+#endif
+
+static int lasat_panic_display(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+#ifdef CONFIG_PICVUE
+ unsigned char *string = ptr;
+ if (string == NULL)
+ string = "Kernel Panic";
+ pvc_dump_string(string);
+#endif
+ return NOTIFY_DONE;
+}
+
+static int lasat_panic_prom_monitor(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ prom_monitor();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block lasat_panic_block[] =
+{
+ { lasat_panic_display, NULL, INT_MAX },
+ { lasat_panic_prom_monitor, NULL, INT_MIN }
+};
+
+static void lasat_time_init(void)
+{
+ mips_hpt_frequency = lasat_board_info.li_cpu_hz / 2;
+}
+
+static void lasat_timer_setup(struct irqaction *irq)
+{
+
+ write_c0_compare(
+ read_c0_count() +
+ mips_hpt_frequency / HZ);
+ change_c0_status(ST0_IM, IE_IRQ0 | IE_IRQ5);
+}
+
+#define DYNAMIC_SERIAL_INIT
+#ifdef DYNAMIC_SERIAL_INIT
+void __init serial_init(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+
+ memset(&s, 0, sizeof(s));
+
+ s.flags = STD_COM_FLAGS;
+ s.iotype = SERIAL_IO_MEM;
+
+ if (mips_machtype == MACH_LASAT_100) {
+ s.uartclk = LASAT_BASE_BAUD_100 * 16;
+ s.irq = LASATINT_UART_100;
+ s.regshift = LASAT_UART_REGS_SHIFT_100;
+ s.membase = (char *)KSEG1ADDR(LASAT_UART_REGS_BASE_100);
+ } else {
+ s.uartclk = LASAT_BASE_BAUD_200 * 16;
+ s.irq = LASATINT_UART_200;
+ s.regshift = LASAT_UART_REGS_SHIFT_200;
+ s.membase = (char *)KSEG1ADDR(LASAT_UART_REGS_BASE_200);
+ }
+
+ if (early_serial_setup(&s) != 0)
+ printk(KERN_ERR "Serial setup failed!\n");
+#endif
+}
+#endif
+
+static int __init lasat_setup(void)
+{
+ int i;
+ lasat_misc = &lasat_misc_info[mips_machtype];
+#ifdef CONFIG_PICVUE
+ picvue = &pvc_defs[mips_machtype];
+#endif
+
+ /* Set up panic notifier */
+ for (i = 0; i < sizeof(lasat_panic_block) / sizeof(struct notifier_block); i++)
+ notifier_chain_register(&panic_notifier_list, &lasat_panic_block[i]);
+
+ lasat_reboot_setup();
+
+ board_time_init = lasat_time_init;
+ board_timer_setup = lasat_timer_setup;
+
+#ifdef CONFIG_DS1603
+ ds1603 = &ds_defs[mips_machtype];
+ rtc_get_time = ds1603_read;
+ rtc_set_time = ds1603_set;
+#endif
+
+#ifdef DYNAMIC_SERIAL_INIT
+ serial_init();
+#endif
+ /* Switch from prom exception handler to normal mode */
+ change_c0_status(ST0_BEV,0);
+
+ prom_printf("Lasat specific initialization complete\n");
+
+ return 0;
+}
+
+early_initcall(lasat_setup);
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
new file mode 100644
index 00000000000..1c0cc620a43
--- /dev/null
+++ b/arch/mips/lasat/sysctl.c
@@ -0,0 +1,355 @@
+/*
+ * Thomas Horsten <thh@lasat.com>
+ * Copyright (C) 2000 LASAT Networks A/S.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Routines specific to the LASAT boards
+ */
+#include <linux/types.h>
+#include <asm/lasat/lasat.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sysctl.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <asm/uaccess.h>
+
+#include "sysctl.h"
+#include "ds1603.h"
+
+static DECLARE_MUTEX(lasat_info_sem);
+
+/* Strategy function to write EEPROM after changing string entry */
+int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ int r;
+ down(&lasat_info_sem);
+ r = sysctl_string(table, name,
+ nlen, oldval, oldlenp, newval, newlen, context);
+ if (r < 0) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ if (newval && newlen) {
+ lasat_write_eeprom_info();
+ }
+ up(&lasat_info_sem);
+ return 1;
+}
+
+
+/* And the same for proc */
+int proc_dolasatstring(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int r;
+ down(&lasat_info_sem);
+ r = proc_dostring(table, write, filp, buffer, lenp, ppos);
+ if ( (!write) || r) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ lasat_write_eeprom_info();
+ up(&lasat_info_sem);
+ return 0;
+}
+
+/* proc function to write EEPROM after changing int entry */
+int proc_dolasatint(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int r;
+ down(&lasat_info_sem);
+ r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+ if ( (!write) || r) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ lasat_write_eeprom_info();
+ up(&lasat_info_sem);
+ return 0;
+}
+
+static int rtctmp;
+
+#ifdef CONFIG_DS1603
+/* proc function to read/write RealTime Clock */
+int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int r;
+ down(&lasat_info_sem);
+ if (!write) {
+ rtctmp = ds1603_read();
+ /* check for time < 0 and set to 0 */
+ if (rtctmp < 0)
+ rtctmp = 0;
+ }
+ r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+ if ( (!write) || r) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ ds1603_set(rtctmp);
+ up(&lasat_info_sem);
+ return 0;
+}
+#endif
+
+/* Sysctl for setting the IP addresses */
+int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ int r;
+ down(&lasat_info_sem);
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ if (r < 0) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ if (newval && newlen) {
+ lasat_write_eeprom_info();
+ }
+ up(&lasat_info_sem);
+ return 1;
+}
+
+#ifdef CONFIG_DS1603
+/* Same for RTC */
+int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ int r;
+ down(&lasat_info_sem);
+ rtctmp = ds1603_read();
+ if (rtctmp < 0)
+ rtctmp = 0;
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ if (r < 0) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ if (newval && newlen) {
+ ds1603_set(rtctmp);
+ }
+ up(&lasat_info_sem);
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_INET
+static char lasat_bcastaddr[16];
+
+void update_bcastaddr(void)
+{
+ unsigned int ip;
+
+ ip = (lasat_board_info.li_eeprom_info.ipaddr &
+ lasat_board_info.li_eeprom_info.netmask) |
+ ~lasat_board_info.li_eeprom_info.netmask;
+
+ sprintf(lasat_bcastaddr, "%d.%d.%d.%d",
+ (ip ) & 0xff,
+ (ip >> 8) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 24) & 0xff);
+}
+
+static char proc_lasat_ipbuf[32];
+/* Parsing of IP address */
+int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int len;
+ unsigned int ip;
+ char *p, c;
+
+ if (!table->data || !table->maxlen || !*lenp ||
+ (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+ }
+
+ down(&lasat_info_sem);
+ if (write) {
+ len = 0;
+ p = buffer;
+ while (len < *lenp) {
+ if(get_user(c, p++)) {
+ up(&lasat_info_sem);
+ return -EFAULT;
+ }
+ if (c == 0 || c == '\n')
+ break;
+ len++;
+ }
+ if (len >= sizeof(proc_lasat_ipbuf)-1)
+ len = sizeof(proc_lasat_ipbuf) - 1;
+ if (copy_from_user(proc_lasat_ipbuf, buffer, len))
+ {
+ up(&lasat_info_sem);
+ return -EFAULT;
+ }
+ proc_lasat_ipbuf[len] = 0;
+ *ppos += *lenp;
+ /* Now see if we can convert it to a valid IP */
+ ip = in_aton(proc_lasat_ipbuf);
+ *(unsigned int *)(table->data) = ip;
+ lasat_write_eeprom_info();
+ } else {
+ ip = *(unsigned int *)(table->data);
+ sprintf(proc_lasat_ipbuf, "%d.%d.%d.%d",
+ (ip ) & 0xff,
+ (ip >> 8) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 24) & 0xff);
+ len = strlen(proc_lasat_ipbuf);
+ if (len > *lenp)
+ len = *lenp;
+ if (len)
+ if(copy_to_user(buffer, proc_lasat_ipbuf, len)) {
+ up(&lasat_info_sem);
+ return -EFAULT;
+ }
+ if (len < *lenp) {
+ if(put_user('\n', ((char *) buffer) + len)) {
+ up(&lasat_info_sem);
+ return -EFAULT;
+ }
+ len++;
+ }
+ *lenp = len;
+ *ppos += len;
+ }
+ update_bcastaddr();
+ up(&lasat_info_sem);
+ return 0;
+}
+#endif /* defined(CONFIG_INET) */
+
+static int sysctl_lasat_eeprom_value(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen,
+ void **context)
+{
+ int r;
+
+ down(&lasat_info_sem);
+ r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+ if (r < 0) {
+ up(&lasat_info_sem);
+ return r;
+ }
+
+ if (newval && newlen)
+ {
+ if (name && *name == LASAT_PRID)
+ lasat_board_info.li_eeprom_info.prid = *(int*)newval;
+
+ lasat_write_eeprom_info();
+ lasat_init_board_info();
+ }
+ up(&lasat_info_sem);
+
+ return 0;
+}
+
+int proc_lasat_eeprom_value(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ int r;
+ down(&lasat_info_sem);
+ r = proc_dointvec(table, write, filp, buffer, lenp, ppos);
+ if ( (!write) || r) {
+ up(&lasat_info_sem);
+ return r;
+ }
+ if (filp && filp->f_dentry)
+ {
+ if (!strcmp(filp->f_dentry->d_name.name, "prid"))
+ lasat_board_info.li_eeprom_info.prid = lasat_board_info.li_prid;
+ if (!strcmp(filp->f_dentry->d_name.name, "debugaccess"))
+ lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
+ }
+ lasat_write_eeprom_info();
+ up(&lasat_info_sem);
+ return 0;
+}
+
+extern int lasat_boot_to_service;
+
+#ifdef CONFIG_SYSCTL
+
+static ctl_table lasat_table[] = {
+ {LASAT_CPU_HZ, "cpu-hz", &lasat_board_info.li_cpu_hz, sizeof(int),
+ 0444, NULL, &proc_dointvec, &sysctl_intvec},
+ {LASAT_BUS_HZ, "bus-hz", &lasat_board_info.li_bus_hz, sizeof(int),
+ 0444, NULL, &proc_dointvec, &sysctl_intvec},
+ {LASAT_MODEL, "bmid", &lasat_board_info.li_bmid, sizeof(int),
+ 0444, NULL, &proc_dointvec, &sysctl_intvec},
+ {LASAT_PRID, "prid", &lasat_board_info.li_prid, sizeof(int),
+ 0644, NULL, &proc_lasat_eeprom_value, &sysctl_lasat_eeprom_value},
+#ifdef CONFIG_INET
+ {LASAT_IPADDR, "ipaddr", &lasat_board_info.li_eeprom_info.ipaddr, sizeof(int),
+ 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec},
+ {LASAT_NETMASK, "netmask", &lasat_board_info.li_eeprom_info.netmask, sizeof(int),
+ 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec},
+ {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr,
+ sizeof(lasat_bcastaddr), 0600, NULL,
+ &proc_dostring, &sysctl_string},
+#endif
+ {LASAT_PASSWORD, "passwd_hash", &lasat_board_info.li_eeprom_info.passwd_hash, sizeof(lasat_board_info.li_eeprom_info.passwd_hash),
+ 0600, NULL, &proc_dolasatstring, &sysctl_lasatstring},
+ {LASAT_SBOOT, "boot-service", &lasat_boot_to_service, sizeof(int),
+ 0644, NULL, &proc_dointvec, &sysctl_intvec},
+#ifdef CONFIG_DS1603
+ {LASAT_RTC, "rtc", &rtctmp, sizeof(int),
+ 0644, NULL, &proc_dolasatrtc, &sysctl_lasat_rtc},
+#endif
+ {LASAT_NAMESTR, "namestr", &lasat_board_info.li_namestr, sizeof(lasat_board_info.li_namestr),
+ 0444, NULL, &proc_dostring, &sysctl_string},
+ {LASAT_TYPESTR, "typestr", &lasat_board_info.li_typestr, sizeof(lasat_board_info.li_typestr),
+ 0444, NULL, &proc_dostring, &sysctl_string},
+ {0}
+};
+
+#define CTL_LASAT 1 // CTL_ANY ???
+static ctl_table lasat_root_table[] = {
+ { CTL_LASAT, "lasat", NULL, 0, 0555, lasat_table },
+ { 0 }
+};
+
+static int __init lasat_register_sysctl(void)
+{
+ struct ctl_table_header *lasat_table_header;
+
+ lasat_table_header =
+ register_sysctl_table(lasat_root_table, 0);
+
+ return 0;
+}
+
+__initcall(lasat_register_sysctl);
+#endif /* CONFIG_SYSCTL */
diff --git a/arch/mips/lasat/sysctl.h b/arch/mips/lasat/sysctl.h
new file mode 100644
index 00000000000..4d139d2adbd
--- /dev/null
+++ b/arch/mips/lasat/sysctl.h
@@ -0,0 +1,24 @@
+/*
+ * LASAT sysctl values
+ */
+
+#ifndef _LASAT_SYSCTL_H
+#define _LASAT_SYSCTL_H
+
+/* /proc/sys/lasat */
+enum {
+ LASAT_CPU_HZ=1,
+ LASAT_BUS_HZ,
+ LASAT_MODEL,
+ LASAT_PRID,
+ LASAT_IPADDR,
+ LASAT_NETMASK,
+ LASAT_BCAST,
+ LASAT_PASSWORD,
+ LASAT_SBOOT,
+ LASAT_RTC,
+ LASAT_NAMESTR,
+ LASAT_TYPESTR,
+};
+
+#endif /* _LASAT_SYSCTL_H */