Update of /cvsroot/linux-vax/kernel-2.4/arch/mips/au1000/common
In directory usw-pr-cvs1:/tmp/cvs-serv20728/mips/au1000/common
Added Files:
Makefile dbg_io.c int-handler.S irq.c prom.c puts.c reset.c
serial.c time.c
Log Message:
synch 2.4.15 commit 39
--- NEW FILE ---
#
# Copyright 2000 MontaVista Software Inc.
# Author: MontaVista Software, Inc.
# pp...@mv... or so...@mv...
#
# Makefile for the Alchemy Au1000 CPU, generic files.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
.S.s:
$(CPP) $(CFLAGS) $< -o $*.s
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
all: au1000.o
O_TARGET := au1000.o
obj-y := prom.o dbg_io.o int-handler.o irq.o puts.o time.o reset.o
obj-$(CONFIG_AU1000_UART) += serial.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o
ramdisk.o:
mkramobj ramdisk ramdisk.o
include $(TOPDIR)/Rules.make
--- NEW FILE ---
#include <linux/config.h>
#include <asm/io.h>
#include <asm/au1000.h>
#ifdef CONFIG_REMOTE_DEBUG
/*
* FIXME the user should be able to select the
* uart to be used for debugging.
*/
#define DEBUG_BASE UART2_ADDR
/**/
/* we need uint32 uint8 */
/* #include "types.h" */
typedef unsigned char uint8;
typedef unsigned int uint32;
#define UART16550_BAUD_2400 2400
#define UART16550_BAUD_4800 4800
#define UART16550_BAUD_9600 9600
#define UART16550_BAUD_19200 19200
#define UART16550_BAUD_38400 38400
#define UART16550_BAUD_57600 57600
#define UART16550_BAUD_115200 115200
#define UART16550_PARITY_NONE 0
#define UART16550_PARITY_ODD 0x08
#define UART16550_PARITY_EVEN 0x18
#define UART16550_PARITY_MARK 0x28
#define UART16550_PARITY_SPACE 0x38
#define UART16550_DATA_5BIT 0x0
#define UART16550_DATA_6BIT 0x1
#define UART16550_DATA_7BIT 0x2
#define UART16550_DATA_8BIT 0x3
#define UART16550_STOP_1BIT 0x0
#define UART16550_STOP_2BIT 0x4
#define UART_RX 0 /* Receive buffer */
#define UART_TX 4 /* Transmit buffer */
#define UART_IER 8 /* Interrupt Enable Register */
#define UART_IIR 0xC /* Interrupt ID Register */
#define UART_FCR 0x10 /* FIFO Control Register */
#define UART_LCR 0x14 /* Line Control Register */
#define UART_MCR 0x18 /* Modem Control Register */
#define UART_LSR 0x1C /* Line Status Register */
#define UART_MSR 0x20 /* Modem Status Register */
#define UART_CLK 0x28 /* Baud Rat4e Clock Divider */
#define UART_MOD_CNTRL 0x100 /* Module Control */
/* memory-mapped read/write of the port */
#define UART16550_READ(y) (inl(DEBUG_BASE + y) & 0xff)
#define UART16550_WRITE(y,z) (outl(z&0xff, DEBUG_BASE + y))
void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
{
if (UART16550_READ(UART_MOD_CNTRL) != 0x3) {
UART16550_WRITE(UART_MOD_CNTRL, 3);
}
cal_r4koff();
/* disable interrupts */
UART16550_WRITE(UART_IER, 0);
/* set up baud rate */
{
uint32 divisor;
/* set divisor */
divisor = get_au1000_uart_baud() / baud;
UART16550_WRITE(UART_CLK, divisor & 0xffff);
}
/* set data format */
UART16550_WRITE(UART_LCR, data | parity | stop);
}
static int remoteDebugInitialized = 0;
uint8 getDebugChar(void)
{
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(UART16550_BAUD_115200,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE,
UART16550_STOP_1BIT);
}
while((UART16550_READ(UART_LSR) & 0x1) == 0);
return UART16550_READ(UART_RX);
}
int putDebugChar(uint8 byte)
{
int i;
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(UART16550_BAUD_115200,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE,
UART16550_STOP_1BIT);
}
while ((UART16550_READ(UART_LSR)&0x40) == 0);
UART16550_WRITE(UART_TX, byte);
//for (i=0;i<0xfff;i++);
return 1;
}
#endif
--- NEW FILE ---
/*
* Copyright 2001 MontaVista Software Inc.
* Author: pp...@mv...
*
* Interrupt dispatcher for Au1000 boards.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
.text
.set macro
.set noat
.align 5
NESTED(au1000_IRQ, PT_SIZE, sp)
SAVE_ALL
CLI # Important: mark KERNEL mode !
mfc0 t0,CP0_CAUSE # get pending interrupts
mfc0 t1,CP0_STATUS # get enabled interrupts
and t0,t1 # isolate allowed ones
andi t0,0xff00 # isolate pending bits
beqz t0, 3f # spurious interrupt
andi a0, t0, CAUSEF_IP7
beq a0, zero, 1f
move a0, sp
jal mips_timer_interrupt
j ret_from_irq
1:
andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
beq a0, zero, 2f
move a0,sp
jal intc0_req0_irqdispatch
j ret_from_irq
2:
andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
beq a0, zero, 3f
move a0,sp
jal intc0_req1_irqdispatch
j ret_from_irq
3:
andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
beq a0, zero, 4f
move a0,sp
jal intc1_req0_irqdispatch
j ret_from_irq
4:
andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
beq a0, zero, 5f
move a0, sp
jal intc1_req1_irqdispatch
j ret_from_irq
5:
move a0, sp
jal mips_spurious_interrupt
done:
j ret_from_irq
END(au1000_IRQ)
--- NEW FILE ---
/*
* BRIEF MODULE DESCRIPTION
* Au1000 interrupt routines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/au1000.h>
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
#undef DEBUG_IRQ
#ifdef DEBUG_IRQ
/* note: prints function name for you */
#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#define EXT_INTC0_REQ0 2 /* IP 2 */
#define EXT_INTC0_REQ1 3 /* IP 3 */
#define EXT_INTC1_REQ0 4 /* IP 4 */
#define EXT_INTC1_REQ1 5 /* IP 5 */
#define MIPS_TIMER_IP 7 /* IP 7 */
#ifdef CONFIG_REMOTE_DEBUG
extern void breakpoint(void);
#endif
extern asmlinkage void au1000_IRQ(void);
extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [];
extern irq_desc_t irq_desc[NR_IRQS];
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
static void setup_local_irq(unsigned int irq, int type, int int_req);
static unsigned int startup_irq(unsigned int irq);
static void end_irq(unsigned int irq_nr);
static inline void mask_and_ack_level_irq(unsigned int irq_nr);
static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr);
static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr);
static inline void local_enable_irq(unsigned int irq_nr);
static inline void local_disable_irq(unsigned int irq_nr);
unsigned long spurious_interrupts;
extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
extern void __init init_generic_irq(void);
static inline void sync(void)
{
__asm volatile ("sync");
}
/* Function for careful CP0 interrupt mask access */
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
{
unsigned long status = read_32bit_cp0_register(CP0_STATUS);
status &= ~((clr_mask & 0xFF) << 8);
status |= (set_mask & 0xFF) << 8;
write_32bit_cp0_register(CP0_STATUS, status);
}
static inline void mask_cpu_irq_input(unsigned int irq_nr)
{
modify_cp0_intmask(irq_nr, 0);
}
static inline void unmask_cpu_irq_input(unsigned int irq_nr)
{
modify_cp0_intmask(0, irq_nr);
}
static void disable_cpu_irq_input(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
mask_cpu_irq_input(irq_nr);
restore_flags(flags);
}
static void enable_cpu_irq_input(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
unmask_cpu_irq_input(irq_nr);
restore_flags(flags);
}
static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
{
/* Config2[n], Config1[n], Config0[n] */
if (irq_nr > AU1000_LAST_INTC0_INT) {
switch (type) {
case INTC_INT_RISE_EDGE: /* 0:0:1 */
outl(1<<irq_nr,INTC1_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG0_SET);
break;
case INTC_INT_FALL_EDGE: /* 0:1:0 */
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_SET);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
break;
case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
outl(1<<irq_nr, INTC1_CONFIG2_SET);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG0_SET);
break;
case INTC_INT_LOW_LEVEL: /* 1:1:0 */
outl(1<<irq_nr, INTC1_CONFIG2_SET);
outl(1<<irq_nr, INTC1_CONFIG1_SET);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
break;
case INTC_INT_DISABLED: /* 0:0:0 */
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
break;
default: /* disable the interrupt */
printk("unexpected int type %d (irq %d)\n", type, irq_nr);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
return;
}
if (int_req) /* assign to interrupt request 1 */
outl(1<<irq_nr, INTC1_ASSIGN_REQ_CLEAR);
else /* assign to interrupt request 0 */
outl(1<<irq_nr, INTC1_ASSIGN_REQ_SET);
outl(1<<irq_nr, INTC1_SOURCE_SET);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
}
else {
switch (type) {
case INTC_INT_RISE_EDGE: /* 0:0:1 */
outl(1<<irq_nr,INTC0_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG0_SET);
break;
case INTC_INT_FALL_EDGE: /* 0:1:0 */
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_SET);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
break;
case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
outl(1<<irq_nr, INTC0_CONFIG2_SET);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG0_SET);
break;
case INTC_INT_LOW_LEVEL: /* 1:1:0 */
outl(1<<irq_nr, INTC0_CONFIG2_SET);
outl(1<<irq_nr, INTC0_CONFIG1_SET);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
break;
case INTC_INT_DISABLED: /* 0:0:0 */
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
break;
default: /* disable the interrupt */
printk("unexpected int type %d (irq %d)\n", type, irq_nr);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
return;
}
if (int_req) /* assign to interrupt request 1 */
outl(1<<irq_nr, INTC0_ASSIGN_REQ_CLEAR);
else /* assign to interrupt request 0 */
outl(1<<irq_nr, INTC0_ASSIGN_REQ_SET);
outl(1<<irq_nr, INTC0_SOURCE_SET);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
sync();
}
static unsigned int startup_irq(unsigned int irq_nr)
{
local_enable_irq(irq_nr);
return 0;
}
static void shutdown_irq(unsigned int irq_nr)
{
local_disable_irq(irq_nr);
return;
}
static inline void local_enable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_SET);
}
else {
outl(1<<irq_nr, INTC0_MASK_SET);
}
sync();
}
static inline void local_disable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_CLEAR);
}
else {
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
sync();
}
static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_R_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
}
else {
outl(1<<irq_nr, INTC0_R_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
sync();
}
static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_F_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
}
else {
outl(1<<irq_nr, INTC0_F_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
}
static inline void mask_and_ack_level_irq(unsigned int irq_nr)
{
local_disable_irq(irq_nr);
sync();
return;
}
static void end_irq(unsigned int irq_nr)
{
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
local_enable_irq(irq_nr);
else
printk("warning: end_irq %d did not enable\n", irq_nr);
}
static struct hw_interrupt_type rise_edge_irq_type = {
"Au1000 Rise Edge",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_rise_edge_irq,
end_irq,
NULL
};
static struct hw_interrupt_type fall_edge_irq_type = {
"Au1000 Fall Edge",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_fall_edge_irq,
end_irq,
NULL
};
static struct hw_interrupt_type level_irq_type = {
"Au1000 Level",
startup_irq,
shutdown_irq,
local_enable_irq,
local_disable_irq,
mask_and_ack_level_irq,
end_irq,
NULL
};
void enable_cpu_timer(void)
{
enable_cpu_irq_input(1<<MIPS_TIMER_IP); /* timer interrupt */
}
void __init init_IRQ(void)
{
int i;
unsigned long cp0_status;
cp0_status = read_32bit_cp0_register(CP0_STATUS);
memset(irq_desc, 0, sizeof(irq_desc));
set_except_vector(0, au1000_IRQ);
init_generic_irq();
/*
* Setup high priority interrupts on int_request0; low priority on
* int_request1
*/
for (i = 0; i <= NR_IRQS; i++) {
switch (i) {
case AU1000_MAC0_DMA_INT:
case AU1000_MAC1_DMA_INT:
setup_local_irq(i, INTC_INT_HIGH_LEVEL, 0);
irq_desc[i].handler = &level_irq_type;
break;
default: /* active high, level interrupt */
setup_local_irq(i, INTC_INT_HIGH_LEVEL, 1);
irq_desc[i].handler = &level_irq_type;
break;
}
}
set_cp0_status(ALLINTS);
#ifdef CONFIG_REMOTE_DEBUG
/* If local serial I/O used for debug port, enter kgdb at once */
puts("Waiting for kgdb to connect...");
set_debug_traps();
breakpoint();
#endif
}
void mips_spurious_interrupt(struct pt_regs *regs)
{
spurious_interrupts++;
}
void intc0_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
int_request = inl(INTC0_REQ0_INT);
if (!int_request) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
}
irq++;
int_request >>= 1;
}
}
void intc0_req1_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
int_request = inl(INTC0_REQ1_INT);
if (!int_request) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
}
irq++;
int_request >>= 1;
}
}
void intc1_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
int_request = inl(INTC1_REQ0_INT);
if (!int_request) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
}
irq++;
int_request >>= 1;
}
}
void intc1_req1_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
int_request = inl(INTC1_REQ1_INT);
if (!int_request) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
}
irq++;
int_request >>= 1;
}
}
--- NEW FILE ---
/*
*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, assuming a version of
* pmon is the boot code.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, car...@mi...
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
/* #define DEBUG_CMDLINE */
char arcs_cmdline[COMMAND_LINE_SIZE];
int prom_argc;
char **prom_argv, **prom_envp;
typedef struct {
char *name;
/* char *val; */
} t_env_var;
char * __init prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while(actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
*cp = '\0';
}
char *prom_getenv(char *envname)
{
/*
* Return a pointer to the given environment variable.
* Environment variables are stored in the form of "memsize=64".
*/
t_env_var *env = (t_env_var *)prom_envp;
int i;
i = strlen(envname);
while(env->name) {
if(strncmp(envname, env->name, i) == 0) {
return(env->name + strlen(envname) + 1);
}
env++;
}
return(NULL);
}
static inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
return 0; /* foo */
}
int __init page_is_ram(unsigned long pagenr)
{
return 1;
}
void prom_free_prom_memory (void)
{
}
--- NEW FILE ---
/*
*
* BRIEF MODULE DESCRIPTION
* Low level uart routines to directly access a 16550 uart.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/types.h>
#define SERIAL_BASE 0xB1100000 /* au1000, uart 0 */
#define SER_CMD 0x7
#define SER_DATA 0x1
#define TX_BUSY 0x20
#define TIMEOUT 0xffffff
#define SLOW_DOWN
static const char digits[16] = "0123456789abcdef";
static volatile unsigned long * const com1 = (unsigned char *)SERIAL_BASE;
#ifdef SLOW_DOWN
static inline void slow_down()
{
int k;
for (k=0; k<10000; k++);
}
#else
#define slow_down()
#endif
void
putch(const unsigned char c)
{
unsigned char ch;
int i = 0;
do {
ch = com1[SER_CMD];
slow_down();
i++;
if (i>TIMEOUT) {
break;
}
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = c;
}
void
puts(unsigned char *cp)
{
unsigned char ch;
int i = 0;
while (*cp) {
do {
ch = com1[SER_CMD];
slow_down();
i++;
if (i>TIMEOUT) {
break;
}
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = *cp++;
}
putch('\r');
putch('\n');
}
void
fputs(unsigned char *cp)
{
unsigned char ch;
int i = 0;
while (*cp) {
do {
ch = com1[SER_CMD];
slow_down();
i++;
if (i>TIMEOUT) {
break;
}
} while (0 == (ch & TX_BUSY));
com1[SER_DATA] = *cp++;
}
}
void
put64(uint64_t ul)
{
int cnt;
unsigned ch;
cnt = 16; /* 16 nibbles in a 64 bit long */
putch('0');
putch('x');
do {
cnt--;
ch = (unsigned char)(ul >> cnt * 4) & 0x0F;
putch(digits[ch]);
} while (cnt > 0);
}
void
put32(unsigned u)
{
int cnt;
unsigned ch;
cnt = 8; /* 8 nibbles in a 32 bit long */
putch('0');
putch('x');
do {
cnt--;
ch = (unsigned char)(u >> cnt * 4) & 0x0F;
putch(digits[ch]);
} while (cnt > 0);
}
--- NEW FILE ---
/*
*
* BRIEF MODULE DESCRIPTION
* Au1000 reset routines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* 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.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
void au1000_restart(char *command)
{
set_cp0_status(ST0_BEV | ST0_ERL);
set_cp0_config(CONF_CM_UNCACHED);
flush_cache_all();
write_32bit_cp0_register(CP0_WIRED, 0);
__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
}
void au1000_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
}
void au1000_power_off(void)
{
au1000_halt();
}
--- NEW FILE ---
/*
*
* BRIEF MODULE DESCRIPTION
* Au1000 serial port driver.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* Derived almost entirely from drivers/char/serial.c:
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
* 1998, 1999 Theodore Ts'o
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
[...3058 lines suppressed...]
wait_key: serial_console_wait_key,
setup: serial_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
/*
* Register console.
*/
void __init au1000_serial_console_init(void)
{
register_console(&sercons);
}
#endif
/*
Local variables:
compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/
--- NEW FILE ---
/*
* Copyright (C) 2001 MontaVista Software, pp...@mv...
* Copied and modified Carsten Langgaard's time.c
*
* Carsten Langgaard, car...@mi...
* 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.
*
* ########################################################################
*
* Setting up the clock on the MIPS boards.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <asm/mipsregs.h>
#include <asm/ptrace.h>
#include <asm/div64.h>
#include <asm/au1000.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
extern volatile unsigned long wall_jiffies;
unsigned long missed_heart_beats = 0;
unsigned long uart_baud_base;
static unsigned long r4k_offset; /* Amount to increment compare reg each time */
static unsigned long r4k_cur; /* What counter should be at next timer irq */
extern rwlock_t xtime_lock;
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
static inline void ack_r4ktimer(unsigned long newval)
{
write_32bit_cp0_register(CP0_COMPARE, newval);
}
/*
* There are a lot of conceptually broken versions of the MIPS timer interrupt
* handler floating around. This one is rather different, but the algorithm
* is provably more robust.
*/
unsigned long wtimer;
void mips_timer_interrupt(struct pt_regs *regs)
{
int irq = 7;
if (r4k_offset == 0)
goto null;
do {
kstat.irqs[0][irq]++;
do_timer(regs);
r4k_cur += r4k_offset;
ack_r4ktimer(r4k_cur);
} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
- r4k_cur) < 0x7fffffff);
return;
null:
ack_r4ktimer(0);
}
/*
* Figure out the r4k offset, the amount to increment the compare
* register for each time tick.
* Use the Programmable Counter 1 to do this.
*/
unsigned long cal_r4koff(void)
{
unsigned long count;
unsigned long cpu_pll;
unsigned long cpu_speed;
unsigned long start, end;
unsigned long counter;
int i;
int trim_divide = 16;
counter = inl(PC_COUNTER_CNTRL);
outl(counter | PC_CNTRL_EN1, PC_COUNTER_CNTRL);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
outl(trim_divide-1, PC1_TRIM); /* RTC now ticks at 32.768/16 kHz */
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
outl (0, PC1_COUNTER_WRITE);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
start = inl(PC1_COUNTER_READ);
start += 2;
/* wait for the beginning of a new tick */
while (inl(PC1_COUNTER_READ) < start);
/* Start r4k counter. */
write_32bit_cp0_register(CP0_COUNT, 0);
end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */
while (end > inl(PC1_COUNTER_READ));
count = read_32bit_cp0_register(CP0_COUNT);
cpu_speed = count * 2;
uart_baud_base = (((cpu_speed) / 4) / 16);
return (cpu_speed / HZ);
}
static unsigned long __init get_mips_time(void)
{
return inl(PC0_COUNTER_READ);
}
void __init time_init(void)
{
unsigned int est_freq, flags;
printk("calculating r4koff... ");
r4k_offset = cal_r4koff();
printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
//est_freq = 2*r4k_offset*HZ;
est_freq = r4k_offset*HZ;
est_freq += 5000; /* round */
est_freq -= est_freq%10000;
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
set_cp0_status(ALLINTS);
/* Read time from the RTC chipset. */
write_lock_irqsave (&xtime_lock, flags);
xtime.tv_sec = get_mips_time();
xtime.tv_usec = 0;
write_unlock_irqrestore(&xtime_lock, flags);
}
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff)
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi = 0, timerlo = 0;
static unsigned long
div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
{
unsigned long r0;
do_div64_32(r0, v1, v2, v3);
return r0;
}
/*
* FIXME: Does playing with the RP bit in c0_status interfere with this code?
*/
static unsigned long do_fast_gettimeoffset(void)
{
u32 count;
unsigned long res, tmp;
unsigned long r0;
/* Last jiffy when do_fast_gettimeoffset() was called. */
static unsigned long last_jiffies=0;
unsigned long quotient;
/*
* Cached "1/(clocks per usec)*2^32" value.
* It has to be recalculated once each jiffy.
*/
static unsigned long cached_quotient=0;
tmp = jiffies;
quotient = cached_quotient;
if (tmp && last_jiffies != tmp) {
last_jiffies = tmp;
if (last_jiffies != 0) {
r0 = div64_32(timerhi, timerlo, tmp);
quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0);
cached_quotient = quotient;
}
}
/* Get last timer tick in absolute kernel time */
count = read_32bit_cp0_register(CP0_COUNT);
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
__asm__("multu\t%1,%2\n\t"
"mfhi\t%0"
:"=r" (res)
:"r" (count),
"r" (quotient));
/*
* Due to possible jiffies inconsistencies, we need to check
* the result so that we'll get a timer that is monotonic.
*/
if (res >= USECS_PER_JIFFY)
res = USECS_PER_JIFFY-1;
return res;
}
void do_gettimeofday(struct timeval *tv)
{
unsigned int flags;
read_lock_irqsave (&xtime_lock, flags);
*tv = xtime;
tv->tv_usec += do_fast_gettimeoffset();
/*
* xtime is atomically updated in timer_bh. jiffies - wall_jiffies
* is nonzero if the timer bottom half hasnt executed yet.
*/
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
read_unlock_irqrestore (&xtime_lock, flags);
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
}
void do_settimeofday(struct timeval *tv)
{
write_lock_irq (&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec correctly.
* However, the value in this location is is value at the last tick.
* Discover what correction gettimeofday would have done, and then
* undo it!
*/
tv->tv_usec -= do_fast_gettimeoffset();
if (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_unlock_irq (&xtime_lock);
}
/*
* The UART baud base is not known at compile time ... if
* we want to be able to use the same code on different
* speed CPUs.
*/
unsigned long get_au1000_uart_baud()
{
return uart_baud_base;
}
|