|
From: Pete P. <pp...@us...> - 2001-08-28 07:23:57
|
Update of /cvsroot/linux-mips/linux/arch/mips/au1000/common
In directory usw-pr-cvs1:/tmp/cvs-serv14591/arch/mips/au1000/common
Modified Files:
Makefile irq.c prom.c reset.c serial.c time.c
Added Files:
clocks.c power.c
Log Message:
Added preliminary power management supuport:
* turn off the clocks to the uarts when not used
* turn off the clocks to the ethernets when not used
* adhoc /proc interface for putting the cpu to sleep and
dynamically scaling the cpu frequency.
* fixed a pci compile problem
--- NEW FILE: clocks.c ---
/*
* BRIEF MODULE DESCRIPTION
* Simple Au1000 clocks 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.
*/
static unsigned int au1000_clock;
static unsigned long uart_baud_base;
/*
* Set the au1000_clock
*/
void set_au1000_speed(unsigned int new_freq)
{
au1000_clock = new_freq;
}
unsigned int get_au1000_speed(void)
{
return au1000_clock;
}
/*
* 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_base(void)
{
return uart_baud_base;
}
void set_au1000_uart_baud_base(unsigned long new_baud_base)
{
uart_baud_base = new_baud_base;
}
--- NEW FILE: power.c ---
/*
* BRIEF MODULE DESCRIPTION
* Au1000 Power Management routines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* pp...@mv... or so...@mv...
*
* Some of the routines are right out of init/main.c, whose
* copyrights apply here.
*
* 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/init.h>
#include <linux/pm.h>
#include <linux/malloc.h>
#include <linux/sysctl.h>
#include <linux/acpi.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/au1000.h>
#define DEBUG 1
#ifdef DEBUG
# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
inline void au1_wait(void);
static void calibrate_delay(void);
extern void set_au1000_speed(unsigned int new_freq);
extern unsigned int get_au1000_speed(void);
extern unsigned long get_au1000_uart_baud_base(void);
extern void set_au1000_uart_baud_base(unsigned long new_baud_base);
extern unsigned long save_local_and_disable(int controller);
extern void restore_local_and_enable(int controller, unsigned long mask);
extern void local_enable_irq(unsigned int irq_nr);
#ifdef CONFIG_PM
unsigned long suspend_mode;
void wakeup_from_suspend(void)
{
suspend_mode = 0;
}
int au_sleep(void)
{
unsigned long wakeup, flags;
save_and_cli(flags);
flush_cache_all();
/* pin 6 is gpio */
writel(readl(PIN_STATE) & ~(1<<11), PIN_STATE);
/* gpio 6 can cause a wake up event */
wakeup = readl(PM_WAKEUP_SOURCE_MASK);
wakeup &= ~(1<<8); /* turn off match20 wakeup */
wakeup |= 1<<6; /* turn on gpio 6 wakeup */
writel(wakeup, PM_WAKEUP_SOURCE_MASK);
writel(1, PM_WAKEUP_CAUSE); /* clear cause */
writel(1, PM_SLEEP_POWER); /* prepare to sleep */
__asm__("la $4, 1f\n\t"
"lui $5, 0xb190\n\t"
"ori $5, 0x18\n\t"
"sw $4, 0($5)\n\t"
"li $4, 1\n\t"
"lui $5, 0xb190\n\t"
"ori $5, 0x7c\n\t"
"sw $4, 0($5)\n\t"
"sync\n\t"
"1:\t\n\t"
"nop\n\t");
/* after a wakeup, the cpu vectors back to 0x1fc00000 so
* it's up to the boot code to get us back here.
*/
restore_flags(flags);
return 0;
}
static int pm_do_sleep(ctl_table *ctl, int write, struct file *file, void *buffer, size_t *len)
{
int retval = 0;
if (!write) {
*len = 0;
}
else {
retval = pm_send_all(PM_SUSPEND, (void *)2);
if (retval)
return retval;
au_sleep();
retval = pm_send_all(PM_RESUME, (void *)0);
}
return retval;
}
static int pm_do_suspend(ctl_table *ctl, int write, struct file *file, void *buffer, size_t *len)
{
int retval = 0;
if (!write) {
*len = 0;
}
else {
retval = pm_send_all(PM_SUSPEND, (void *)2);
if (retval)
return retval;
suspend_mode = 1;
au1_wait();
retval = pm_send_all(PM_RESUME, (void *)0);
}
return retval;
}
static int pm_do_freq(ctl_table *ctl, int write, struct file *file, void *buffer, size_t *len)
{
int retval = 0, i;
unsigned long val, pll;
#define TMPBUFLEN 64
#define MAX_CPU_FREQ 396
char buf[8], *p;
unsigned long flags, intc0_mask, intc1_mask;
unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk, old_refresh;
unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
save_and_cli(flags);
if (!write) {
*len = 0;
}
else {
/* Parse the new frequency */
if (*len > TMPBUFLEN-1) {
restore_flags(flags);
return -EFAULT;
}
if(copy_from_user(buf, buffer, *len)) {
restore_flags(flags);
return -EFAULT;
}
buf[*len] = 0;
p = buf;
val = simple_strtoul(p, &p, 0);
if (val > MAX_CPU_FREQ) {
restore_flags(flags);
return -EFAULT;
}
pll = val/12;
if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
/* revisit this for higher speed cpus */
restore_flags(flags);
return -EFAULT;
}
old_baud_base = get_au1000_uart_baud_base();
old_cpu_freq = get_au1000_speed();
new_cpu_freq = pll * 12 * 1000000;
new_baud_base = (new_cpu_freq / 4) / 16;
set_au1000_speed(new_cpu_freq);
set_au1000_uart_baud_base(new_baud_base);
old_refresh = readl(REFRESH_CONFIG) & 0x1ffffff;
new_refresh = ((old_refresh * new_cpu_freq)/old_cpu_freq) |
(readl(REFRESH_CONFIG) & ~0x1ffffff);
writel(pll, CPU_PLL_CNTRL);
au_sync_delay(1);
writel(new_refresh, REFRESH_CONFIG);
au_sync_delay(1);
for (i=0; i<4; i++) {
if (readl(UART_BASE + UART_MOD_CNTRL + i*0x00100000) == 3) {
old_clk = readl(UART_BASE + UART_CLK + i*0x00100000);
// baud_rate = baud_base/clk
baud_rate = old_baud_base / old_clk;
/* we won't get an exact baud rate and the error
* could be significant enough that our new
* calculation will result in a clock that will
* give us a baud rate that's too far off from
* what we really want.
*/
if (baud_rate > 100000)
baud_rate = 115200;
else if (baud_rate > 50000)
baud_rate = 57600;
else if(baud_rate > 30000)
baud_rate = 38400;
else if (baud_rate > 17000)
baud_rate = 19200;
else
(baud_rate = 9600);
// new_clk = new_baud_base/baud_rate
new_clk = new_baud_base/baud_rate;
writel(new_clk, UART_BASE + UART_CLK + i*0x00100000);
au_sync_delay(10);
}
}
}
/* We don't want _any_ interrupts other than
* match20. Otherwise our calibrate_delay()
* calculation will be off, potentially a lot.
*/
intc0_mask = save_local_and_disable(0);
intc1_mask = save_local_and_disable(1);
local_enable_irq(AU1000_PC0_MATCH2_INT);
restore_flags(flags);
calibrate_delay();
restore_local_and_enable(0, intc0_mask);
restore_local_and_enable(1, intc1_mask);
return retval;
}
static struct ctl_table pm_table[] =
{
{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},
{ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},
{CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},
{0}
};
static struct ctl_table pm_dir_table[] =
{
{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
{0}
};
/*
* Initialize power interface
*/
static int __init pm_init(void)
{
register_sysctl_table(pm_dir_table, 1);
return 0;
}
__initcall(pm_init);
inline void au1_wait(void)
{
__asm__(".set\tmips3\n\t"
"wait\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set\tmips0");
}
/*
* This is right out of init/main.c
*/
/* This is the number of bits of precision for the loops_per_jiffy. Each
bit takes on average 1.5/HZ seconds. This (like the original) is a little
better than 1% */
#define LPS_PREC 8
static void calibrate_delay(void)
{
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
loops_per_jiffy = (1<<12);
while (loops_per_jiffy <<= 1) {
/* wait for "start of" clock tick */
ticks = jiffies;
while (ticks == jiffies)
/* nothing */;
/* Go .. */
ticks = jiffies;
__delay(loops_per_jiffy);
ticks = jiffies - ticks;
if (ticks)
break;
}
/* Do a binary approximation to get loops_per_jiffy set to equal one clock
(up to lps_precision bits) */
loops_per_jiffy >>= 1;
loopbit = loops_per_jiffy;
while ( lps_precision-- && (loopbit >>= 1) ) {
loops_per_jiffy |= loopbit;
ticks = jiffies;
while (ticks == jiffies);
ticks = jiffies;
__delay(loops_per_jiffy);
if (jiffies != ticks) /* longer than 1 tick */
loops_per_jiffy &= ~loopbit;
}
}
#else /* CONFIG_PM */
void au1_wait(void)
{
__asm__("nop\n\t"
"nop\n\t");
}
#endif /* CONFIG_PM */
Index: Makefile
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/Makefile,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** Makefile 2001/08/25 02:19:27 1.4
--- Makefile 2001/08/28 07:23:54 1.5
***************
*** 20,32 ****
O_TARGET := au1000.o
! obj-y := prom.o dbg_io.o int-handler.o dma.o irq.o puts.o time.o reset.o
obj-$(CONFIG_AU1000_UART) += serial.o
obj-$(CONFIG_AU1000_USB_DEVICE) += usbdev.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
--- 20,28 ----
O_TARGET := au1000.o
! obj-y := prom.o dbg_io.o int-handler.o dma.o irq.o puts.o time.o reset.o power.o clocks.o
obj-$(CONFIG_AU1000_UART) += serial.o
obj-$(CONFIG_AU1000_USB_DEVICE) += usbdev.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
include $(TOPDIR)/Rules.make
Index: irq.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/irq.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** irq.c 2001/08/25 02:19:27 1.4
--- irq.c 2001/08/28 07:23:54 1.5
***************
*** 52,57 ****
#endif
- #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-
#undef DEBUG_IRQ
#ifdef DEBUG_IRQ
--- 52,55 ----
***************
*** 73,81 ****
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];
--- 71,76 ----
extern asmlinkage void au1000_IRQ(void);
extern void set_debug_traps(void);
! extern irq_cpustat_t irq_stat [NR_CPUS];
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
***************
*** 87,143 ****
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);
! }
--- 82,95 ----
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);
! inline void local_enable_irq(unsigned int irq_nr);
! 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);
! #ifdef CONFIG_PM
! extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
! #endif
***************
*** 185,188 ****
--- 137,141 ----
outl(1<<irq_nr, INTC1_SOURCE_SET);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
+ outl(1<<irq_nr, INTC1_WAKEUP_CLEAR);
}
else {
***************
*** 226,231 ****
outl(1<<irq_nr, INTC0_SOURCE_SET);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
! sync();
}
--- 179,185 ----
outl(1<<irq_nr, INTC0_SOURCE_SET);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
+ outl(1<<irq_nr, INTC0_WAKEUP_CLEAR);
}
! au_sync();
}
***************
*** 245,269 ****
! 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();
}
--- 199,227 ----
! inline void local_enable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_SET);
+ outl(1<<irq_nr, INTC1_WAKEUP_SET);
}
else {
outl(1<<irq_nr, INTC0_MASK_SET);
+ outl(1<<irq_nr, INTC0_WAKEUP_SET);
}
! au_sync();
}
! inline void local_disable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_CLEAR);
+ outl(1<<irq_nr, INTC1_WAKEUP_CLEAR);
}
else {
outl(1<<irq_nr, INTC0_MASK_CLEAR);
+ outl(1<<irq_nr, INTC0_WAKEUP_CLEAR);
}
! au_sync();
}
***************
*** 279,283 ****
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
! sync();
}
--- 237,241 ----
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
! au_sync();
}
***************
*** 293,296 ****
--- 251,255 ----
outl(1<<irq_nr, INTC0_MASK_CLEAR);
}
+ au_sync();
}
***************
*** 309,313 ****
#endif
local_disable_irq(irq_nr);
! sync();
return;
}
--- 268,272 ----
#endif
local_disable_irq(irq_nr);
! au_sync();
return;
}
***************
*** 329,336 ****
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",
--- 288,340 ----
local_enable_irq(irq_nr);
else
! printk("warning: end_irq %d did not enable (%x)\n",
! irq_nr, irq_desc[irq_nr].status);
}
+ unsigned long save_local_and_disable(int controller)
+ {
+ int i;
+ unsigned long flags, mask;
+ save_and_cli(flags);
+
+ if (controller) {
+ mask = readl(INTC1_MASK_SET);
+ for (i=0; i<32; i++) {
+ local_disable_irq(i);
+ }
+ }
+ else {
+ mask = readl(INTC0_MASK_SET);
+ for (i=32; i<64; i++) {
+ local_disable_irq(i);
+ }
+ }
+ restore_flags(flags);
+ return mask;
+ }
+ void restore_local_and_enable(int controller, unsigned long mask)
+ {
+ int i;
+ unsigned long flags, new_mask;
+ save_and_cli(flags);
+
+ for (i=0; i<32; i++) {
+ if (mask & (1<<i)) {
+ if (controller)
+ local_enable_irq(i+32);
+ else
+ local_enable_irq(i);
+ }
+ }
+ if (controller)
+ new_mask = readl(INTC1_MASK_SET);
+ else
+ new_mask = readl(INTC0_MASK_SET);
+
+ restore_flags(flags);
+ }
+
+
static struct hw_interrupt_type rise_edge_irq_type = {
"Au1000 Rise Edge",
***************
*** 368,376 ****
};
!
! void enable_cpu_timer(void)
{
! enable_cpu_irq_input(1<<MIPS_TIMER_IP); /* timer interrupt */
}
--- 372,381 ----
};
! #ifdef CONFIG_PM
! void startup_match20_interrupt(void)
{
! local_enable_irq(AU1000_PC0_MATCH2_INT);
}
+ #endif
***************
*** 379,383 ****
int i;
unsigned long cp0_status;
- extern char except_vec0_au1000;
cp0_status = read_32bit_cp0_register(CP0_STATUS);
--- 384,387 ----
***************
*** 386,398 ****
init_generic_irq();
-
- /* overwrite vec0 with our own */
- memcpy((void *)KSEG0, &except_vec0_au1000, 0x80);
- flush_icache_range(KSEG0, KSEG0 + 0x200);
- /*
- * Setup high priority interrupts on int_request0; low priority on
- * int_request1
- */
for (i = 0; i <= NR_IRQS; i++) {
switch (i) {
--- 390,394 ----
***************
*** 423,428 ****
irq_desc[i].handler = &rise_edge_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;
--- 419,431 ----
irq_desc[i].handler = &rise_edge_irq_type;
break;
+ // Careful if you change match 2 request!
+ // The interrupt handler is called directly
+ // from the low level dispatch code.
+ case AU1000_PC0_MATCH2_INT:
+ setup_local_irq(i, INTC_INT_RISE_EDGE, 1);
+ irq_desc[i].handler = &rise_edge_irq_type;
+ break;
default: /* active high, level interrupt */
! setup_local_irq(i, INTC_INT_HIGH_LEVEL, 0);
irq_desc[i].handler = &level_irq_type;
break;
***************
*** 446,464 ****
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;
}
}
--- 449,474 ----
+ /*
+ * Interrupts are nested. Even if an interrupt handler is registered
+ * as "fast", we might get another interrupt before we return from
+ * intcX_reqX_irqdispatch().
+ */
+
void intc0_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
! static unsigned long intc0_req0 = 0;
! intc0_req0 |= inl(INTC0_REQ0_INT);
! if (!intc0_req0) return;
for (i=0; i<32; i++) {
! if ((intc0_req0 & (1<<i))) {
! intc0_req0 &= ~(1<<i);
do_IRQ(irq, regs);
+ return;
}
irq++;
}
}
***************
*** 468,502 ****
{
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;
}
}
--- 478,528 ----
{
int irq = 0, i;
! static unsigned long intc0_req1 = 0;
! intc0_req1 = inl(INTC0_REQ1_INT);
! if (!intc0_req1) return;
for (i=0; i<32; i++) {
! if ((intc0_req1 & (1<<i))) {
! intc0_req1 &= ~(1<<i);
! #ifdef CONFIG_PM
! if (i == AU1000_PC0_MATCH2_INT) {
! mask_and_ack_rise_edge_irq(irq);
! counter0_irq(irq, NULL, regs);
! local_enable_irq(irq);
! }
! else
! #endif
! {
! do_IRQ(irq, regs);
! }
! return;
}
irq++;
}
}
+ /*
+ * Interrupt Controller 1:
+ * interrupts 32 - 63
+ */
void intc1_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
! static unsigned long intc1_req0 = 0;
! intc1_req0 |= inl(INTC1_REQ0_INT);
! if (!intc1_req0) return;
for (i=0; i<32; i++) {
! if ((intc1_req0 & (1<<i))) {
! intc1_req0 &= ~(1<<i);
! do_IRQ(irq+32, regs);
! return;
}
irq++;
}
}
***************
*** 506,521 ****
{
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;
}
}
--- 532,548 ----
{
int irq = 0, i;
! static unsigned long intc1_req1 = 0;
! intc1_req1 |= inl(INTC1_REQ1_INT);
! if (!intc1_req1) return;
for (i=0; i<32; i++) {
! if ((intc1_req1 & (1<<i))) {
! intc1_req1 &= ~(1<<i);
! do_IRQ(irq+32, regs);
! return;
}
irq++;
}
}
Index: prom.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/prom.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** prom.c 2001/08/25 02:19:27 1.3
--- prom.c 2001/08/28 07:23:54 1.4
***************
*** 46,56 ****
char arcs_cmdline[COMMAND_LINE_SIZE];
! int prom_argc;
! char **prom_argv, **prom_envp;
! typedef struct {
! char *name;
! /* char *val; */
! } t_env_var;
--- 46,57 ----
char arcs_cmdline[COMMAND_LINE_SIZE];
! extern int prom_argc;
! extern char **prom_argv, **prom_envp;
! typedef struct
! {
! char *name;
! /* char *val; */
! }t_env_var;
***************
*** 102,106 ****
}
! static inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
--- 103,107 ----
}
! inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
***************
*** 111,120 ****
}
! int __init page_is_ram(unsigned long pagenr)
{
! return 1;
! }
! void prom_free_prom_memory (void)
{
}
--- 112,151 ----
}
! inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
! int i;
! for(i = 0; i < 6; i++) {
! unsigned char num;
!
! if((*str == '.') || (*str == ':'))
! str++;
! num = str2hexnum(*str++) << 4;
! num |= (str2hexnum(*str++));
! ea[i] = num;
! }
! }
!
! int get_ethernet_addr(char *ethernet_addr)
{
+ int i;
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+ #if 0
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ #endif
+
+ return 0;
}
+
+ void prom_free_prom_memory (void) {}
Index: reset.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/reset.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -C2 -d -r1.1.1.1 -r1.2
*** reset.c 2001/06/22 02:29:31 1.1.1.1
--- reset.c 2001/08/28 07:23:54 1.2
***************
*** 37,43 ****
#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();
--- 37,45 ----
#include <asm/system.h>
+ extern int au_sleep(void);
+
void au1000_restart(char *command)
{
! set_cp0_status((ST0_BEV | ST0_ERL));
set_cp0_config(CONF_CM_UNCACHED);
flush_cache_all();
***************
*** 49,56 ****
--- 51,66 ----
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+ #ifdef CONFIG_PM
+ au_sleep();
+
+ /* should not get here */
+ printk(KERN_ERR "Unable to put cpu in sleep mode\n");
+ while(1);
+ #else
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
+ #endif
}
Index: serial.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/serial.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -C2 -d -r1.1.1.1 -r1.2
*** serial.c 2001/06/22 02:29:32 1.1.1.1
--- serial.c 2001/08/28 07:23:54 1.2
***************
*** 135,139 ****
static struct timer_list serial_timer;
! extern unsigned long get_au1000_uart_baud(void);
/* serial subtype definitions */
--- 135,139 ----
static struct timer_list serial_timer;
! extern unsigned long get_au1000_uart_baud_base(void);
/* serial subtype definitions */
***************
*** 756,759 ****
--- 756,760 ----
if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
outl(3, UART_MOD_CNTRL + state->port);
+ au_sync_delay(10);
}
#ifdef SERIAL_DEBUG_OPEN
***************
*** 990,993 ****
--- 991,996 ----
info->flags &= ~ASYNC_INITIALIZED;
+ outl(0, UART_MOD_CNTRL + state->port);
+ au_sync_delay(10);
restore_flags(flags);
}
***************
*** 1041,1045 ****
baud = 9600; /* B0 transition handled in rs_set_termios */
}
! baud_base = info->state->baud_base;
//if (baud == 38400 &&
if (((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
--- 1044,1049 ----
baud = 9600; /* B0 transition handled in rs_set_termios */
}
! baud_base = get_au1000_uart_baud_base();
!
//if (baud == 38400 &&
if (((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
***************
*** 2515,2518 ****
--- 2519,2523 ----
if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
outl(3, UART_MOD_CNTRL + state->port);
+ au_sync_delay(10);
}
***************
*** 2545,2548 ****
--- 2550,2556 ----
(void)serial_in(info, UART_RX);
serial_outp(info, UART_IER, 0);
+
+ outl(0, UART_MOD_CNTRL + state->port);
+ au_sync_delay(10);
restore_flags(flags);
***************
*** 2652,2656 ****
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
! state->baud_base = get_au1000_uart_baud();
state->magic = SSTATE_MAGIC;
state->line = i;
--- 2660,2664 ----
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
! state->baud_base = get_au1000_uart_baud_base();
state->magic = SSTATE_MAGIC;
state->line = i;
***************
*** 3048,3052 ****
info->iomem_base = state->iomem_base;
info->iomem_reg_shift = state->iomem_reg_shift;
! state->baud_base = get_au1000_uart_baud();
quot = state->baud_base / baud;
--- 3056,3060 ----
info->iomem_base = state->iomem_base;
info->iomem_reg_shift = state->iomem_reg_shift;
! state->baud_base = get_au1000_uart_baud_base();
quot = state->baud_base / baud;
Index: time.c
===================================================================
RCS file: /cvsroot/linux-mips/linux/arch/mips/au1000/common/time.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** time.c 2001/08/25 02:19:27 1.4
--- time.c 2001/08/28 07:23:54 1.5
***************
*** 1,3 ****
--- 1,4 ----
/*
+ *
* Copyright (C) 2001 MontaVista Software, pp...@mv...
* Copied and modified Carsten Langgaard's time.c
***************
*** 24,28 ****
--- 25,31 ----
*
* Setting up the clock on the MIPS boards.
+ *
*/
+
#include <linux/config.h>
#include <linux/init.h>
***************
*** 39,45 ****
#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 */
--- 42,51 ----
#include <linux/timex.h>
+ extern void startup_match20_interrupt(void);
+ extern void set_au1000_uart_baud_base(unsigned long new_baud_base);
+ extern void set_au1000_speed(unsigned int new_freq);
+
extern volatile unsigned long wall_jiffies;
unsigned long missed_heart_beats = 0;
static unsigned long r4k_offset; /* Amount to increment compare reg each time */
***************
*** 47,56 ****
extern rwlock_t xtime_lock;
- unsigned int au1000_clock;
-
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi = 0, timerlo = 0;
! #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
static inline void ack_r4ktimer(unsigned long newval)
--- 53,64 ----
extern rwlock_t xtime_lock;
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi = 0, timerlo = 0;
! #ifdef CONFIG_PM
! #define MATCH20_INC 328
! extern void startup_match20_interrupt(void);
! static unsigned long last_pc0, last_match20;
! #endif
static inline void ack_r4ktimer(unsigned long newval)
***************
*** 59,63 ****
}
-
/*
* There are a lot of conceptually broken versions of the MIPS timer interrupt
--- 67,70 ----
***************
*** 68,72 ****
void mips_timer_interrupt(struct pt_regs *regs)
{
! int irq = 7;
if (r4k_offset == 0)
--- 75,86 ----
void mips_timer_interrupt(struct pt_regs *regs)
{
! int irq = 63;
! unsigned long count;
!
! #ifdef CONFIG_PM
! printk(KERN_ERR "Unexpected CP0 interrupt\n");
! regs->cp0_status &= ~IE_IRQ5; /* disable CP0 interrupt */
! return;
! #endif
if (r4k_offset == 0)
***************
*** 74,77 ****
--- 88,95 ----
do {
+ count = read_32bit_cp0_register(CP0_COUNT);
+ timerhi += (count < timerlo); /* Wrap around */
+ timerlo = count;
+
kstat.irqs[0][irq]++;
do_timer(regs);
***************
*** 88,91 ****
--- 106,154 ----
}
+ #ifdef CONFIG_PM
+ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ unsigned long pc0;
+ int time_elapsed;
+ static int jiffie_drift = 0;
+
+ kstat.irqs[0][irq]++;
+ if (readl(PC_COUNTER_CNTRL) & PC_CNTRL_M20) {
+ /* should never happen! */
+ printk(KERN_WARNING "counter 0 w status eror\n");
+ return;
+ }
+
+ pc0 = inl(PC0_COUNTER_READ);
+ if (pc0 < last_match20) {
+ /* counter overflowed */
+ time_elapsed = (0xffffffff - last_match20) + pc0;
+ }
+ else {
+ time_elapsed = pc0 - last_match20;
+ }
+
+ while (time_elapsed > 0) {
+ do_timer(regs);
+ time_elapsed -= MATCH20_INC;
+ last_match20 += MATCH20_INC;
+ jiffie_drift++;
+ }
+
+ last_pc0 = pc0;
+ outl(last_match20 + MATCH20_INC, PC0_MATCH2);
+ au_sync();
+
+ /* our counter ticks at 10.009765625 ms/tick, we we're running
+ * almost 10uS too slow per tick.
+ */
+
+ if (jiffie_drift >= 999) {
+ jiffie_drift -= 999;
+ do_timer(regs); /* increment jiffies by one */
+ }
+ }
+ #endif
+
/*
* Figure out the r4k offset, the amount to increment the compare
***************
*** 96,105 ****
{
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);
--- 159,169 ----
{
unsigned long count;
unsigned long cpu_speed;
unsigned long start, end;
unsigned long counter;
int trim_divide = 16;
+ unsigned long flags;
+
+ save_and_cli(flags);
counter = inl(PC_COUNTER_CNTRL);
***************
*** 127,142 ****
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... ");
--- 191,203 ----
count = read_32bit_cp0_register(CP0_COUNT);
cpu_speed = count * 2;
! set_au1000_uart_baud_base(((cpu_speed) / 4) / 16);
! restore_flags(flags);
return (cpu_speed / HZ);
}
void __init time_init(void)
{
! unsigned int est_freq;
printk("calculating r4koff... ");
***************
*** 150,174 ****
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
! au1000_clock = est_freq;
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)
--- 211,259 ----
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
! set_au1000_speed(est_freq);
r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
! /* no RTC on the pb1000 */
! xtime.tv_sec = 0;
xtime.tv_usec = 0;
!
! #ifdef CONFIG_PM
! /*
! * setup counter 0, since it keeps ticking after a
! * 'wait' instruction has been executed. The CP0 timer and
! * counter 1 do NOT continue running after 'wait'
! *
! * It's too early to call request_irq() here, so we handle
! * counter 0 interrupt as a special irq and it doesn't show
! * up under /proc/interrupts.
! */
! while (readl(PC_COUNTER_CNTRL) & PC_CNTRL_C0S);
! writel(0, PC0_COUNTER_WRITE);
! while (readl(PC_COUNTER_CNTRL) & PC_CNTRL_C0S);
!
! writel(readl(PM_WAKEUP_SOURCE_MASK) | (1<<8), PM_WAKEUP_SOURCE_MASK);
! writel(~0, PM_WAKEUP_CAUSE);
! au_sync();
! while (readl(PC_COUNTER_CNTRL) & PC_CNTRL_M20);
!
! /* setup match20 to interrupt once every 10ms */
! last_pc0 = last_match20 = readl(PC0_COUNTER_READ);
! writel(last_match20 + MATCH20_INC, PC0_MATCH2);
! au_sync();
! while (readl(PC_COUNTER_CNTRL) & PC_CNTRL_M20);
! startup_match20_interrupt();
! #endif
!
! //set_cp0_status(ALLINTS);
! au_sync();
}
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
! #define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
static unsigned long
div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
***************
*** 180,188 ****
- /*
- * 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;
--- 265,290 ----
static unsigned long do_fast_gettimeoffset(void)
{
+ #ifdef CONFIG_PM
+ unsigned long pc0;
+ unsigned long offset;
+
+ pc0 = readl(PC0_COUNTER_READ);
+ if (pc0 < last_pc0) {
+ offset = 0xffffffff - last_pc0 + pc0;
+ printk("offset over: %x\n", (unsigned)offset);
+ }
+ else {
+ offset = (unsigned long)(((pc0 - last_pc0) * 305) / 10);
+ }
+ if ((pc0-last_pc0) > 2*MATCH20_INC) {
+ printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
+ (unsigned)offset, (unsigned)last_pc0,
+ (unsigned)last_match20, (unsigned)pc0);
+ }
+ au_sync();
+ return offset;
+ #else
u32 count;
unsigned long res, tmp;
***************
*** 232,235 ****
--- 334,338 ----
return res;
+ #endif
}
***************
*** 280,292 ****
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;
}
--- 383,385 ----
|