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 ---- |