Commit 6cd1b450 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] ppc32: pmac sleep support update

This patch updates the PowerMac sleep support.  The ability to sleep is now
broken into 2 different flags, one, "may sleep" is set for all motherboards
that we know how to put to sleep and wakeup.  It gets turned into "can sleep"
upon a call from the video driver indicating the ability to wakeup the video
card.  This doesn't deal with head-less machines, but this can be improved
later.  It also adds better cache flush code, which improves stability with
cpufreq as well as sleep.

This patch actually breaks sleep support until the video drivers for the
affected machines have been updated.  This will come as separate patches.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ee3b1931
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/ppc_asm.h> #include <asm/ppc_asm.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/page.h>
/* Usage: /* Usage:
...@@ -284,7 +285,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_L3CR) ...@@ -284,7 +285,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
/* Tweak some bits */ /* Tweak some bits */
rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */
rlwinm r3,r3,0,22,20 /* Turn off the invalidate bit */ rlwinm r3,r3,0,22,20 /* Turn off the invalidate bit */
rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ rlwinm r3,r3,0,2,31 /* Turn off the enable & PE bits */
rlwinm r3,r3,0,5,3 /* Turn off the clken bit */ rlwinm r3,r3,0,5,3 /* Turn off the clken bit */
/* Check to see if we need to flush */ /* Check to see if we need to flush */
rlwinm. r4,r4,0,0,0 rlwinm. r4,r4,0,0,0
...@@ -379,7 +380,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_L3CR) ...@@ -379,7 +380,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
/* flush_disable_L1() - Flush and disable L1 cache /* flush_disable_L1() - Flush and disable L1 cache
* *
* clobbers r0, r3, ctr, cr0 * clobbers r0, r3, ctr, cr0
* * Must be called with interrupts disabled and MMU enabled.
*/ */
_GLOBAL(__flush_disable_L1) _GLOBAL(__flush_disable_L1)
/* Stop pending alitvec streams and memory accesses */ /* Stop pending alitvec streams and memory accesses */
...@@ -393,7 +394,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) ...@@ -393,7 +394,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
*/ */
li r3,0x4000 /* 512kB / 32B */ li r3,0x4000 /* 512kB / 32B */
mtctr r3 mtctr r3
li r3, 0 lis r3,KERNELBASE@h
1: 1:
lwz r0,0(r3) lwz r0,0(r3)
addi r3,r3,0x0020 /* Go to start of next cache line */ addi r3,r3,0x0020 /* Go to start of next cache line */
...@@ -404,7 +405,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) ...@@ -404,7 +405,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
/* Now flush those cache lines */ /* Now flush those cache lines */
li r3,0x4000 /* 512kB / 32B */ li r3,0x4000 /* 512kB / 32B */
mtctr r3 mtctr r3
li r3, 0 lis r3,KERNELBASE@h
1: 1:
dcbf 0,r3 dcbf 0,r3
addi r3,r3,0x0020 /* Go to start of next cache line */ addi r3,r3,0x0020 /* Go to start of next cache line */
......
...@@ -11,7 +11,7 @@ obj-$(CONFIG_PCI) += apus_pci.o ...@@ -11,7 +11,7 @@ obj-$(CONFIG_PCI) += apus_pci.o
endif endif
obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \
pmac_feature.o pmac_pci.o pmac_sleep.o \ pmac_feature.o pmac_pci.o pmac_sleep.o \
pmac_low_i2c.o pmac_low_i2c.o pmac_cache.o
obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o
obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o
ifeq ($(CONFIG_PPC_PMAC),y) ifeq ($(CONFIG_PPC_PMAC),y)
......
/*
* This file contains low-level cache management functions
* used for sleep and CPU speed changes on Apple machines.
* (In fact the only thing that is Apple-specific is that we assume
* that we can read from ROM at physical address 0xfff00000.)
*
* Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
* Benjamin Herrenschmidt (benh@kernel.crashing.org)
*
* 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/processor.h>
#include <asm/ppc_asm.h>
#include <asm/cputable.h>
/*
* Flush and disable all data caches (dL1, L2, L3). This is used
* when going to sleep, when doing a PMU based cpufreq transition,
* or when "offlining" a CPU on SMP machines. This code is over
* paranoid, but I've had enough issues with various CPU revs and
* bugs that I decided it was worth beeing over cautious
*/
_GLOBAL(flush_disable_caches)
BEGIN_FTR_SECTION
b flush_disable_745x
END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
BEGIN_FTR_SECTION
b flush_disable_75x
END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
b __flush_disable_L1
/* This is the code for G3 and 74[01]0 */
flush_disable_75x:
mflr r10
/* Turn off EE and DR in MSR */
mfmsr r11
rlwinm r0,r11,0,~MSR_EE
rlwinm r0,r0,0,~MSR_DR
sync
mtmsr r0
isync
/* Stop DST streams */
BEGIN_FTR_SECTION
DSSALL
sync
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
/* Stop DPM */
mfspr r8,SPRN_HID0 /* Save HID0 in r8 */
rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */
sync
mtspr SPRN_HID0,r4 /* Disable DPM */
sync
/* disp-flush L1 */
li r4,0x4000
mtctr r4
lis r4,0xfff0
1: lwzx r0,r0,r4
addi r4,r4,32
bdnz 1b
sync
isync
/* disable / invalidate / enable L1 data */
mfspr r3,SPRN_HID0
rlwinm r0,r0,0,~HID0_DCE
mtspr SPRN_HID0,r3
sync
isync
ori r3,r3,HID0_DCE|HID0_DCI
sync
isync
mtspr SPRN_HID0,r3
xori r3,r3,HID0_DCI
mtspr SPRN_HID0,r3
sync
/* Get the current enable bit of the L2CR into r4 */
mfspr r5,L2CR
/* Set to data-only (pre-745x bit) */
oris r3,r5,L2CR_L2DO@h
b 2f
/* When disabling L2, code must be in L1 */
.balign 32
1: mtspr L2CR,r3
3: sync
isync
b 1f
2: b 3f
3: sync
isync
b 1b
1: /* disp-flush L2. The interesting thing here is that the L2 can be
* up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
* but that is probbaly fine. We disp-flush over 4Mb to be safe
*/
lis r4,2
mtctr r4
lis r4,0xfff0
1: lwzx r0,r0,r4
addi r4,r4,32
bdnz 1b
sync
isync
/* now disable L2 */
rlwinm r5,r5,0,~L2CR_L2E
b 2f
/* When disabling L2, code must be in L1 */
.balign 32
1: mtspr L2CR,r5
3: sync
isync
b 1f
2: b 3f
3: sync
isync
b 1b
1: sync
isync
/* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
oris r4,r5,L2CR_L2I@h
mtspr L2CR,r4
sync
isync
xoris r4,r4,L2CR_L2I@h
sync
mtspr L2CR,r4
sync
/* now disable the L1 data cache */
mfspr r0,HID0
rlwinm r0,r0,0,~HID0_DCE
mtspr HID0,r0
sync
isync
/* Restore HID0[DPM] to whatever it was before */
sync
mtspr SPRN_HID0,r8
sync
/* restore DR and EE */
sync
mtmsr r11
isync
mtlr r10
blr
/* This code is for 745x processors */
flush_disable_745x:
/* Turn off EE and DR in MSR */
mfmsr r11
rlwinm r0,r11,0,~MSR_EE
rlwinm r0,r0,0,~MSR_DR
sync
mtmsr r0
isync
/* Stop prefetch streams */
DSSALL
sync
/* Disable L2 prefetching */
mfspr r0,SPRN_MSSCR0
rlwinm r0,r0,0,0,29
mtspr SPRN_MSSCR0,r0
sync
isync
lis r4,0
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
dcbf 0,r4
/* Due to a bug with the HW flush on some CPU revs, we occasionally
* experience data corruption. I'm adding a displacement flush along
* with a dcbf loop over a few Mb to "help". The problem isn't totally
* fixed by this in theory, but at least, in practice, I couldn't reproduce
* it even with a big hammer...
*/
lis r4,0x0002
mtctr r4
li r4,0
1:
lwzx r0,r0,r4
addi r4,r4,32 /* Go to start of next cache line */
bdnz 1b
isync
/* Now, flush the first 4MB of memory */
lis r4,0x0002
mtctr r4
li r4,0
sync
1:
dcbf 0,r4
addi r4,r4,32 /* Go to start of next cache line */
bdnz 1b
/* Flush and disable the L1 data cache */
mfspr r6,SPRN_LDSTCR
lis r3,0xfff0 /* read from ROM for displacement flush */
li r4,0xfe /* start with only way 0 unlocked */
li r5,128 /* 128 lines in each way */
1: mtctr r5
rlwimi r6,r4,0,24,31
mtspr SPRN_LDSTCR,r6
sync
isync
2: lwz r0,0(r3) /* touch each cache line */
addi r3,r3,32
bdnz 2b
rlwinm r4,r4,1,24,30 /* move on to the next way */
ori r4,r4,1
cmpwi r4,0xff /* all done? */
bne 1b
/* now unlock the L1 data cache */
li r4,0
rlwimi r6,r4,0,24,31
sync
mtspr SPRN_LDSTCR,r6
sync
isync
/* Flush the L2 cache using the hardware assist */
mfspr r3,L2CR
cmpwi r3,0 /* check if it is enabled first */
bge 4f
oris r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
b 2f
/* When disabling/locking L2, code must be in L1 */
.balign 32
1: mtspr L2CR,r0 /* lock the L2 cache */
3: sync
isync
b 1f
2: b 3f
3: sync
isync
b 1b
1: sync
isync
ori r0,r3,L2CR_L2HWF_745x
sync
mtspr L2CR,r0 /* set the hardware flush bit */
3: mfspr r0,L2CR /* wait for it to go to 0 */
andi. r0,r0,L2CR_L2HWF_745x
bne 3b
sync
rlwinm r3,r3,0,~L2CR_L2E
b 2f
/* When disabling L2, code must be in L1 */
.balign 32
1: mtspr L2CR,r3 /* disable the L2 cache */
3: sync
isync
b 1f
2: b 3f
3: sync
isync
b 1b
1: sync
isync
oris r4,r3,L2CR_L2I@h
mtspr L2CR,r4
sync
isync
1: mfspr r4,L2CR
andis. r0,r4,L2CR_L2I@h
bne 1b
sync
BEGIN_FTR_SECTION
/* Flush the L3 cache using the hardware assist */
4: mfspr r3,L3CR
cmpwi r3,0 /* check if it is enabled */
bge 6f
oris r0,r3,L3CR_L3IO@h
ori r0,r0,L3CR_L3DO
sync
mtspr L3CR,r0 /* lock the L3 cache */
sync
isync
ori r0,r0,L3CR_L3HWF
sync
mtspr L3CR,r0 /* set the hardware flush bit */
5: mfspr r0,L3CR /* wait for it to go to zero */
andi. r0,r0,L3CR_L3HWF
bne 5b
rlwinm r3,r3,0,~L3CR_L3E
sync
mtspr L3CR,r3 /* disable the L3 cache */
sync
ori r4,r3,L3CR_L3I
mtspr SPRN_L3CR,r4
1: mfspr r4,SPRN_L3CR
andi. r0,r4,L3CR_L3I
bne 1b
sync
END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
6: mfspr r0,HID0 /* now disable the L1 data cache */
rlwinm r0,r0,0,~HID0_DCE
mtspr HID0,r0
sync
isync
mtmsr r11 /* restore DR and EE */
isync
blr
...@@ -154,6 +154,14 @@ static int __pmac dfs_set_cpu_speed(int low_speed) ...@@ -154,6 +154,14 @@ static int __pmac dfs_set_cpu_speed(int low_speed)
return 0; return 0;
} }
static unsigned int __pmac dfs_get_cpu_speed(unsigned int cpu)
{
if (mfspr(HID1) & HID1_DFS)
return low_freq;
else
return hi_freq;
}
/* Switch CPU speed using slewing GPIOs /* Switch CPU speed using slewing GPIOs
*/ */
...@@ -229,10 +237,6 @@ static int __pmac pmu_set_cpu_speed(int low_speed) ...@@ -229,10 +237,6 @@ static int __pmac pmu_set_cpu_speed(int low_speed)
/* Save & disable L2 and L3 caches */ /* Save & disable L2 and L3 caches */
save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ save_l3cr = _get_L3CR(); /* (returns -1 if not available) */
save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
_set_L3CR(save_l3cr & 0x7fffffff);
if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
_set_L2CR(save_l2cr & 0x7fffffff);
/* Send the new speed command. My assumption is that this command /* Send the new speed command. My assumption is that this command
* will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep
...@@ -458,14 +462,13 @@ static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode) ...@@ -458,14 +462,13 @@ static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode)
{ {
struct device_node *volt_gpio_np; struct device_node *volt_gpio_np;
u32 *reg; u32 *reg;
struct cpufreq_driver *driver = &pmac_cpufreq_driver;
/* OF only reports the high frequency */ /* OF only reports the high frequency */
hi_freq = cur_freq; hi_freq = cur_freq;
low_freq = cur_freq/2; low_freq = cur_freq/2;
if (mfspr(HID1) & HID1_DFS) driver->get = dfs_get_cpu_speed;
cur_freq = low_freq; cur_freq = driver->get(0);
else
cur_freq = hi_freq;
volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
if (!volt_gpio_np){ if (!volt_gpio_np){
......
This diff is collapsed.
...@@ -913,8 +913,12 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) ...@@ -913,8 +913,12 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
* (iBook second controller) * (iBook second controller)
*/ */
if (dev->vendor == PCI_VENDOR_ID_APPLE if (dev->vendor == PCI_VENDOR_ID_APPLE
&& dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node) && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
&& !node) {
printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
pci_name(dev));
return -EINVAL; return -EINVAL;
}
if (!node) if (!node)
return 0; return 0;
......
...@@ -161,12 +161,8 @@ _GLOBAL(low_sleep_handler) ...@@ -161,12 +161,8 @@ _GLOBAL(low_sleep_handler)
addi r3,r3,sleep_storage@l addi r3,r3,sleep_storage@l
stw r5,0(r3) stw r5,0(r3)
/* Disable DPM during cache flush */ /* Flush & disable all caches */
mfspr r3, SPRN_HID0 bl flush_disable_caches
rlwinm r3,r3,0,12,10
sync
mtspr SPRN_HID0,r3
sync
/* Turn off data relocation. */ /* Turn off data relocation. */
mfmsr r3 /* Save MSR in r7 */ mfmsr r3 /* Save MSR in r7 */
...@@ -175,8 +171,13 @@ _GLOBAL(low_sleep_handler) ...@@ -175,8 +171,13 @@ _GLOBAL(low_sleep_handler)
mtmsr r3 mtmsr r3
isync isync
/* Flush & disable L1 cache */ BEGIN_FTR_SECTION
bl __flush_disable_L1 /* Flush any pending L2 data prefetches to work around HW bug */
sync
lis r3,0xfff0
lwz r0,0(r3) /* perform cache-inhibited load to ROM */
sync /* (caches are disabled at this point) */
END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
/* /*
* Set the HID0 and MSR for sleep. * Set the HID0 and MSR for sleep.
...@@ -212,17 +213,16 @@ _GLOBAL(low_sleep_handler) ...@@ -212,17 +213,16 @@ _GLOBAL(low_sleep_handler)
* r4 has the physical address of SL_PC(sp) (unused) * r4 has the physical address of SL_PC(sp) (unused)
*/ */
_GLOBAL(core99_wake_up) _GLOBAL(core99_wake_up)
/* Make sure HID0 no longer contains any sleep bit */ /* Make sure HID0 no longer contains any sleep bit and that data cache
* is disabled
*/
mfspr r3,HID0 mfspr r3,HID0
rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */
rlwinm 3,r3,0,18,15 /* clear DCE, ICE */
mtspr HID0,r3 mtspr HID0,r3
sync sync
isync isync
/* Won't that cause problems on CPU that doesn't support it ? */
lis r3, 0
mtspr SPRN_MMCR0, r3
/* sanitize MSR */ /* sanitize MSR */
mfmsr r3 mfmsr r3
ori r3,r3,MSR_EE|MSR_IP ori r3,r3,MSR_EE|MSR_IP
...@@ -246,10 +246,6 @@ _GLOBAL(core99_wake_up) ...@@ -246,10 +246,6 @@ _GLOBAL(core99_wake_up)
*/ */
grackle_wake_up: grackle_wake_up:
/* Invalidate & enable L1 cache, we don't care about
* whatever the ROM may have tried to write to memory
*/
bl __inval_enable_L1
/* Restore the kernel's segment registers before /* Restore the kernel's segment registers before
* we do any r1 memory access as we are not sure they * we do any r1 memory access as we are not sure they
...@@ -271,6 +267,11 @@ grackle_wake_up: ...@@ -271,6 +267,11 @@ grackle_wake_up:
/* Restore various CPU config stuffs */ /* Restore various CPU config stuffs */
bl __restore_cpu_setup bl __restore_cpu_setup
/* Invalidate & enable L1 cache, we don't care about
* whatever the ROM may have tried to write to memory
*/
bl __inval_enable_L1
/* Restore the BATs, and SDR1. Then we can turn on the MMU. */ /* Restore the BATs, and SDR1. Then we can turn on the MMU. */
lwz r4,SL_SDR1(r1) lwz r4,SL_SDR1(r1)
mtsdr1 r4 mtsdr1 r4
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/cpu.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -152,7 +153,6 @@ static int drop_interrupts; ...@@ -152,7 +153,6 @@ static int drop_interrupts;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
static int option_lid_wakeup = 1; static int option_lid_wakeup = 1;
static int sleep_in_progress; static int sleep_in_progress;
static int can_sleep;
#endif /* CONFIG_PMAC_PBOOK */ #endif /* CONFIG_PMAC_PBOOK */
static unsigned long async_req_locks; static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11]; static unsigned int pmu_irq_stats[11];
...@@ -406,8 +406,6 @@ static int __init via_pmu_start(void) ...@@ -406,8 +406,6 @@ static int __init via_pmu_start(void)
bright_req_2.complete = 1; bright_req_2.complete = 1;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
batt_req.complete = 1; batt_req.complete = 1;
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
can_sleep = 1;
#endif #endif
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU", if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
...@@ -885,7 +883,8 @@ proc_read_options(char *page, char **start, off_t off, ...@@ -885,7 +883,8 @@ proc_read_options(char *page, char **start, off_t off,
char *p = page; char *p = page;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup); p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
#endif /* CONFIG_PMAC_PBOOK */ #endif /* CONFIG_PMAC_PBOOK */
if (pmu_kind == PMU_KEYLARGO_BASED) if (pmu_kind == PMU_KEYLARGO_BASED)
...@@ -925,7 +924,8 @@ proc_write_options(struct file *file, const char __user *buffer, ...@@ -925,7 +924,8 @@ proc_write_options(struct file *file, const char __user *buffer,
while(*val == ' ') while(*val == ' ')
val++; val++;
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep) if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
if (!strcmp(label, "lid_wakeup")) if (!strcmp(label, "lid_wakeup"))
option_lid_wakeup = ((*val) == '1'); option_lid_wakeup = ((*val) == '1');
#endif /* CONFIG_PMAC_PBOOK */ #endif /* CONFIG_PMAC_PBOOK */
...@@ -2313,7 +2313,7 @@ static int __pmac ...@@ -2313,7 +2313,7 @@ static int __pmac
pmac_suspend_devices(void) pmac_suspend_devices(void)
{ {
int ret; int ret;
pm_prepare_console(); pm_prepare_console();
/* Notify old-style device drivers & userland */ /* Notify old-style device drivers & userland */
...@@ -2341,13 +2341,13 @@ pmac_suspend_devices(void) ...@@ -2341,13 +2341,13 @@ pmac_suspend_devices(void)
/* Send suspend call to devices, hold the device core's dpm_sem */ /* Send suspend call to devices, hold the device core's dpm_sem */
ret = device_suspend(PM_SUSPEND_MEM); ret = device_suspend(PM_SUSPEND_MEM);
if (ret) { if (ret) {
printk(KERN_ERR "Driver sleep failed\n");
broadcast_wake(); broadcast_wake();
printk(KERN_ERR "Driver sleep failed\n");
return -EBUSY; return -EBUSY;
} }
preempt_disable(); preempt_disable();
/* Make sure the decrementer won't interrupt us */ /* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff)); asm volatile("mtdec %0" : : "r" (0x7fffffff));
/* Make sure any pending DEC interrupt occurring while we did /* Make sure any pending DEC interrupt occurring while we did
...@@ -2404,8 +2404,6 @@ pmac_wakeup_devices(void) ...@@ -2404,8 +2404,6 @@ pmac_wakeup_devices(void)
/* Power back up system devices (including the PIC) */ /* Power back up system devices (including the PIC) */
device_power_up(); device_power_up();
pmu_blink(1);
/* Force a poll of ADB interrupts */ /* Force a poll of ADB interrupts */
adb_int_pending = 1; adb_int_pending = 1;
via_pmu_interrupt(0, NULL, NULL); via_pmu_interrupt(0, NULL, NULL);
...@@ -2416,7 +2414,7 @@ pmac_wakeup_devices(void) ...@@ -2416,7 +2414,7 @@ pmac_wakeup_devices(void)
/* Re-enable local CPU interrupts */ /* Re-enable local CPU interrupts */
local_irq_enable(); local_irq_enable();
pmu_blink(1); mdelay(100);
preempt_enable(); preempt_enable();
...@@ -2464,8 +2462,6 @@ powerbook_sleep_grackle(void) ...@@ -2464,8 +2462,6 @@ powerbook_sleep_grackle(void)
/* For 750, save backside cache setting and disable it */ /* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
_set_L2CR(save_l2cr & 0x7fffffff);
if (!__fake_sleep) { if (!__fake_sleep) {
/* Ask the PMU to put us to sleep */ /* Ask the PMU to put us to sleep */
...@@ -2530,17 +2526,22 @@ powerbook_sleep_Core99(void) ...@@ -2530,17 +2526,22 @@ powerbook_sleep_Core99(void)
struct adb_request req; struct adb_request req;
int ret; int ret;
if (!can_sleep) { if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
printk(KERN_ERR "Sleep mode not supported on this machine\n"); printk(KERN_ERR "Sleep mode not supported on this machine\n");
return -ENOSYS; return -ENOSYS;
} }
if (num_online_cpus() > 1 || cpu_is_offline(0))
return -EAGAIN;
ret = pmac_suspend_devices(); ret = pmac_suspend_devices();
if (ret) { if (ret) {
printk(KERN_ERR "Sleep rejected by devices\n"); printk(KERN_ERR "Sleep rejected by devices\n");
return ret; return ret;
} }
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
/* Tell PMU what events will wake us up */ /* Tell PMU what events will wake us up */
pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
0xff, 0xff); 0xff, 0xff);
...@@ -2550,16 +2551,9 @@ powerbook_sleep_Core99(void) ...@@ -2550,16 +2551,9 @@ powerbook_sleep_Core99(void)
(option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0)); (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
pmu_wait_complete(&req); pmu_wait_complete(&req);
/* Save & disable L2 and L3 caches*/ /* Save the state of the L2 and L3 caches */
save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ save_l3cr = _get_L3CR(); /* (returns -1 if not available) */
save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
_set_L3CR(save_l3cr & 0x7fffffff);
if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
_set_L2CR(save_l2cr & 0x7fffffff);
/* Save the state of PCI config space for some slots */
//pbook_pci_save();
if (!__fake_sleep) { if (!__fake_sleep) {
/* Ask the PMU to put us to sleep */ /* Ask the PMU to put us to sleep */
...@@ -2574,7 +2568,7 @@ powerbook_sleep_Core99(void) ...@@ -2574,7 +2568,7 @@ powerbook_sleep_Core99(void)
* talk to the PMU after this, so I moved it to _after_ sending the * talk to the PMU after this, so I moved it to _after_ sending the
* sleep command to it. Still need to be checked. * sleep command to it. Still need to be checked.
*/ */
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
/* Call low-level ASM sleep handler */ /* Call low-level ASM sleep handler */
if (__fake_sleep) if (__fake_sleep)
...@@ -2583,18 +2577,13 @@ powerbook_sleep_Core99(void) ...@@ -2583,18 +2577,13 @@ powerbook_sleep_Core99(void)
low_sleep_handler(); low_sleep_handler();
/* Restore Apple core ASICs state */ /* Restore Apple core ASICs state */
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
/* Restore VIA */ /* Restore VIA */
restore_via_state(); restore_via_state();
/* Restore PCI config space. This should be overridable by PCI device /* Restore video */
* drivers as some of them may need special restore code. That's yet pmac_call_early_video_resume();
* another issue that should be handled by the common code properly,
* maybe one day ?
*/
/* Don't restore PCI for now, it crashes. Maybe unnecessary on pbook */
//pbook_pci_restore();
/* Restore L2 cache */ /* Restore L2 cache */
if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
...@@ -2613,7 +2602,7 @@ powerbook_sleep_Core99(void) ...@@ -2613,7 +2602,7 @@ powerbook_sleep_Core99(void)
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
pmu_wait_complete(&req); pmu_wait_complete(&req);
pmu_blink(1); printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
pmac_wakeup_devices(); pmac_wakeup_devices();
...@@ -2909,7 +2898,10 @@ pmu_ioctl(struct inode * inode, struct file *filp, ...@@ -2909,7 +2898,10 @@ pmu_ioctl(struct inode * inode, struct file *filp,
sleep_in_progress = 0; sleep_in_progress = 0;
return error; return error;
case PMU_IOC_CAN_SLEEP: case PMU_IOC_CAN_SLEEP:
return put_user((u32)can_sleep, argp); if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
return put_user(0, argp);
else
return put_user(1, argp);
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
/* Backlight should have its own device or go via /* Backlight should have its own device or go via
......
...@@ -1946,6 +1946,8 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c ...@@ -1946,6 +1946,8 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
unsigned long flags; unsigned long flags;
int i; int i;
if (ZS_IS_ASLEEP(uap))
return;
spin_lock_irqsave(&uap->port.lock, flags); spin_lock_irqsave(&uap->port.lock, flags);
/* Turn of interrupts and enable the transmitter. */ /* Turn of interrupts and enable the transmitter. */
......
...@@ -125,6 +125,7 @@ ...@@ -125,6 +125,7 @@
#define PMAC_MB_HAS_FW_POWER 0x00000002 #define PMAC_MB_HAS_FW_POWER 0x00000002
#define PMAC_MB_OLD_CORE99 0x00000004 #define PMAC_MB_OLD_CORE99 0x00000004
#define PMAC_MB_MOBILE 0x00000008 #define PMAC_MB_MOBILE 0x00000008
#define PMAC_MB_MAY_SLEEP 0x00000010
/* /*
* Feature calls supported on pmac * Feature calls supported on pmac
...@@ -238,7 +239,10 @@ static inline long pmac_call_feature(int selector, struct device_node* node, ...@@ -238,7 +239,10 @@ static inline long pmac_call_feature(int selector, struct device_node* node,
/* PMAC_FTR_SLEEP_STATE (struct device_node* node, 0, int value) /* PMAC_FTR_SLEEP_STATE (struct device_node* node, 0, int value)
* set the sleep state of the motherboard. * set the sleep state of the motherboard.
*
* Pass -1 as value to query for sleep capability * Pass -1 as value to query for sleep capability
* Pass 1 to set IOs to sleep
* Pass 0 to set IOs to wake
*/ */
#define PMAC_FTR_SLEEP_STATE PMAC_FTR_DEF(15) #define PMAC_FTR_SLEEP_STATE PMAC_FTR_DEF(15)
...@@ -279,11 +283,22 @@ static inline long pmac_call_feature(int selector, struct device_node* node, ...@@ -279,11 +283,22 @@ static inline long pmac_call_feature(int selector, struct device_node* node,
*/ */
#define PMAC_FTR_AACK_DELAY_ENABLE PMAC_FTR_DEF(20) #define PMAC_FTR_AACK_DELAY_ENABLE PMAC_FTR_DEF(20)
/* PMAC_FTR_DEVICE_CAN_WAKE
*
* Used by video drivers to inform system that they can actually perform
* wakeup from sleep
*/
#define PMAC_FTR_DEVICE_CAN_WAKE PMAC_FTR_DEF(22)
/* Don't use those directly, they are for the sake of pmac_setup.c */ /* Don't use those directly, they are for the sake of pmac_setup.c */
extern long pmac_do_feature_call(unsigned int selector, ...); extern long pmac_do_feature_call(unsigned int selector, ...);
extern void pmac_feature_init(void); extern void pmac_feature_init(void);
/* Video suspend tweak */
extern void pmac_set_early_video_resume(void (*proc)(void *data), void *data);
extern void pmac_call_early_video_resume(void);
#define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x)) #define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
......
...@@ -244,6 +244,10 @@ ...@@ -244,6 +244,10 @@
#define L2CR_L2DF 0x00004000 /* L2 differential clock */ #define L2CR_L2DF 0x00004000 /* L2 differential clock */
#define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */ #define L2CR_L2BYP 0x00002000 /* L2 DLL bypass */
#define L2CR_L2IP 0x00000001 /* L2 GI in progress */ #define L2CR_L2IP 0x00000001 /* L2 GI in progress */
#define L2CR_L2IO_745x 0x00100000 /* L2 instr. only (745x) */
#define L2CR_L2DO_745x 0x00010000 /* L2 data only (745x) */
#define L2CR_L2REP_745x 0x00001000 /* L2 repl. algorithm (745x) */
#define L2CR_L2HWF_745x 0x00000800 /* L2 hardware flush (745x) */
#define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter */ #define SPRN_L3CR 0x3FA /* Level 3 Cache Control Regsiter */
#define L3CR_L3E 0x80000000 /* L3 enable */ #define L3CR_L3E 0x80000000 /* L3 enable */
#define L3CR_L3PE 0x40000000 /* L3 data parity enable */ #define L3CR_L3PE 0x40000000 /* L3 data parity enable */
......
...@@ -148,6 +148,55 @@ ...@@ -148,6 +148,55 @@
#define UNI_N_AACK_DELAY 0x0100 #define UNI_N_AACK_DELAY 0x0100
#define UNI_N_AACK_DELAY_ENABLE 0x00000001 #define UNI_N_AACK_DELAY_ENABLE 0x00000001
/* Clock status for Intrepid */
#define UNI_N_CLOCK_STOP_STATUS0 0x0150
#define UNI_N_CLOCK_STOPPED_EXTAGP 0x00200000
#define UNI_N_CLOCK_STOPPED_AGPDEL 0x00100000
#define UNI_N_CLOCK_STOPPED_I2S0_45_49 0x00080000
#define UNI_N_CLOCK_STOPPED_I2S0_18 0x00040000
#define UNI_N_CLOCK_STOPPED_I2S1_45_49 0x00020000
#define UNI_N_CLOCK_STOPPED_I2S1_18 0x00010000
#define UNI_N_CLOCK_STOPPED_TIMER 0x00008000
#define UNI_N_CLOCK_STOPPED_SCC_RTCLK18 0x00004000
#define UNI_N_CLOCK_STOPPED_SCC_RTCLK32 0x00002000
#define UNI_N_CLOCK_STOPPED_SCC_VIA32 0x00001000
#define UNI_N_CLOCK_STOPPED_SCC_SLOT0 0x00000800
#define UNI_N_CLOCK_STOPPED_SCC_SLOT1 0x00000400
#define UNI_N_CLOCK_STOPPED_SCC_SLOT2 0x00000200
#define UNI_N_CLOCK_STOPPED_PCI_FBCLKO 0x00000100
#define UNI_N_CLOCK_STOPPED_VEO0 0x00000080
#define UNI_N_CLOCK_STOPPED_VEO1 0x00000040
#define UNI_N_CLOCK_STOPPED_USB0 0x00000020
#define UNI_N_CLOCK_STOPPED_USB1 0x00000010
#define UNI_N_CLOCK_STOPPED_USB2 0x00000008
#define UNI_N_CLOCK_STOPPED_32 0x00000004
#define UNI_N_CLOCK_STOPPED_45 0x00000002
#define UNI_N_CLOCK_STOPPED_49 0x00000001
#define UNI_N_CLOCK_STOP_STATUS1 0x0160
#define UNI_N_CLOCK_STOPPED_PLL4REF 0x00080000
#define UNI_N_CLOCK_STOPPED_CPUDEL 0x00040000
#define UNI_N_CLOCK_STOPPED_CPU 0x00020000
#define UNI_N_CLOCK_STOPPED_BUF_REFCKO 0x00010000
#define UNI_N_CLOCK_STOPPED_PCI2 0x00008000
#define UNI_N_CLOCK_STOPPED_FW 0x00004000
#define UNI_N_CLOCK_STOPPED_GB 0x00002000
#define UNI_N_CLOCK_STOPPED_ATA66 0x00001000
#define UNI_N_CLOCK_STOPPED_ATA100 0x00000800
#define UNI_N_CLOCK_STOPPED_MAX 0x00000400
#define UNI_N_CLOCK_STOPPED_PCI1 0x00000200
#define UNI_N_CLOCK_STOPPED_KLPCI 0x00000100
#define UNI_N_CLOCK_STOPPED_USB0PCI 0x00000080
#define UNI_N_CLOCK_STOPPED_USB1PCI 0x00000040
#define UNI_N_CLOCK_STOPPED_USB2PCI 0x00000020
#define UNI_N_CLOCK_STOPPED_7PCI1 0x00000008
#define UNI_N_CLOCK_STOPPED_AGP 0x00000004
#define UNI_N_CLOCK_STOPPED_PCI0 0x00000002
#define UNI_N_CLOCK_STOPPED_18 0x00000001
/* Intrepid registe to OF do-platform-clockspreading */
#define UNI_N_CLOCK_SPREADING 0x190
/* Uninorth 1.5 rev. has additional perf. monitor registers at 0xf00-0xf50 */ /* Uninorth 1.5 rev. has additional perf. monitor registers at 0xf00-0xf50 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment