-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 55035 b: refs/heads/master c: 2e1ee1f h: refs/heads/master i: 55033: 195def6 55031: b241d07 v: v3
- Loading branch information
Domen Puncer
authored and
Paul Mackerras
committed
May 7, 2007
1 parent
de7974b
commit cc83e97
Showing
7 changed files
with
402 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: a3481197783c187707090504062488862768260a | ||
refs/heads/master: 2e1ee1f76684c5d4dd8e5a08cbf22d57f88769ed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
#include <linux/init.h> | ||
#include <linux/pm.h> | ||
#include <linux/io.h> | ||
#include <asm/time.h> | ||
#include <asm/cacheflush.h> | ||
#include <asm/mpc52xx.h> | ||
|
||
#include "mpc52xx_pic.h" | ||
|
||
|
||
/* these are defined in mpc52xx_sleep.S, and only used here */ | ||
extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs, | ||
struct mpc52xx_cdm *, struct mpc52xx_intr *); | ||
extern void mpc52xx_ds_sram(void); | ||
extern const long mpc52xx_ds_sram_size; | ||
extern void mpc52xx_ds_cached(void); | ||
extern const long mpc52xx_ds_cached_size; | ||
|
||
static void __iomem *mbar; | ||
static void __iomem *sdram; | ||
static struct mpc52xx_cdm __iomem *cdm; | ||
static struct mpc52xx_intr __iomem *intr; | ||
static struct mpc52xx_gpio_wkup __iomem *gpiow; | ||
static void *sram; | ||
static int sram_size; | ||
|
||
struct mpc52xx_suspend mpc52xx_suspend; | ||
|
||
static int mpc52xx_pm_valid(suspend_state_t state) | ||
{ | ||
switch (state) { | ||
case PM_SUSPEND_STANDBY: | ||
return 1; | ||
default: | ||
return 0; | ||
} | ||
} | ||
|
||
int mpc52xx_set_wakeup_gpio(u8 pin, u8 level) | ||
{ | ||
u16 tmp; | ||
|
||
/* enable gpio */ | ||
out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin)); | ||
/* set as input */ | ||
out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin)); | ||
/* enable deep sleep interrupt */ | ||
out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin)); | ||
/* low/high level creates wakeup interrupt */ | ||
tmp = in_be16(&gpiow->wkup_itype); | ||
tmp &= ~(0x3 << (pin * 2)); | ||
tmp |= (!level + 1) << (pin * 2); | ||
out_be16(&gpiow->wkup_itype, tmp); | ||
/* master enable */ | ||
out_8(&gpiow->wkup_maste, 1); | ||
|
||
return 0; | ||
} | ||
|
||
int mpc52xx_pm_prepare(suspend_state_t state) | ||
{ | ||
if (state != PM_SUSPEND_STANDBY) | ||
return -EINVAL; | ||
|
||
/* map the whole register space */ | ||
mbar = mpc52xx_find_and_map("mpc5200"); | ||
if (!mbar) { | ||
printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); | ||
return -ENOSYS; | ||
} | ||
/* these offsets are from mpc5200 users manual */ | ||
sdram = mbar + 0x100; | ||
cdm = mbar + 0x200; | ||
intr = mbar + 0x500; | ||
gpiow = mbar + 0xc00; | ||
sram = mbar + 0x8000; /* Those will be handled by the */ | ||
sram_size = 0x4000; /* bestcomm driver soon */ | ||
|
||
/* call board suspend code, if applicable */ | ||
if (mpc52xx_suspend.board_suspend_prepare) | ||
mpc52xx_suspend.board_suspend_prepare(mbar); | ||
else { | ||
printk(KERN_ALERT "%s: %i don't know how to wake up the board\n", | ||
__func__, __LINE__); | ||
goto out_unmap; | ||
} | ||
|
||
return 0; | ||
|
||
out_unmap: | ||
iounmap(mbar); | ||
return -ENOSYS; | ||
} | ||
|
||
|
||
char saved_sram[0x4000]; | ||
|
||
int mpc52xx_pm_enter(suspend_state_t state) | ||
{ | ||
u32 clk_enables; | ||
u32 msr, hid0; | ||
u32 intr_main_mask; | ||
void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500; | ||
unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size; | ||
char saved_0x500[mpc52xx_ds_cached_size]; | ||
|
||
/* disable all interrupts in PIC */ | ||
intr_main_mask = in_be32(&intr->main_mask); | ||
out_be32(&intr->main_mask, intr_main_mask | 0x1ffff); | ||
|
||
/* don't let DEC expire any time soon */ | ||
mtspr(SPRN_DEC, 0x7fffffff); | ||
|
||
/* save SRAM */ | ||
memcpy(saved_sram, sram, sram_size); | ||
|
||
/* copy low level suspend code to sram */ | ||
memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size); | ||
|
||
out_8(&cdm->ccs_sleep_enable, 1); | ||
out_8(&cdm->osc_sleep_enable, 1); | ||
out_8(&cdm->ccs_qreq_test, 1); | ||
|
||
/* disable all but SDRAM and bestcomm (SRAM) clocks */ | ||
clk_enables = in_be32(&cdm->clk_enables); | ||
out_be32(&cdm->clk_enables, clk_enables & 0x00088000); | ||
|
||
/* disable power management */ | ||
msr = mfmsr(); | ||
mtmsr(msr & ~MSR_POW); | ||
|
||
/* enable sleep mode, disable others */ | ||
hid0 = mfspr(SPRN_HID0); | ||
mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP); | ||
|
||
/* save original, copy our irq handler, flush from dcache and invalidate icache */ | ||
memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size); | ||
memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size); | ||
flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop); | ||
|
||
/* call low-level sleep code */ | ||
mpc52xx_deep_sleep(sram, sdram, cdm, intr); | ||
|
||
/* restore original irq handler */ | ||
memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size); | ||
flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop); | ||
|
||
/* restore old power mode */ | ||
mtmsr(msr & ~MSR_POW); | ||
mtspr(SPRN_HID0, hid0); | ||
mtmsr(msr); | ||
|
||
out_be32(&cdm->clk_enables, clk_enables); | ||
out_8(&cdm->ccs_sleep_enable, 0); | ||
out_8(&cdm->osc_sleep_enable, 0); | ||
|
||
/* restore SRAM */ | ||
memcpy(sram, saved_sram, sram_size); | ||
|
||
/* restart jiffies */ | ||
wakeup_decrementer(); | ||
|
||
/* reenable interrupts in PIC */ | ||
out_be32(&intr->main_mask, intr_main_mask); | ||
|
||
return 0; | ||
} | ||
|
||
int mpc52xx_pm_finish(suspend_state_t state) | ||
{ | ||
/* call board resume code */ | ||
if (mpc52xx_suspend.board_resume_finish) | ||
mpc52xx_suspend.board_resume_finish(mbar); | ||
|
||
iounmap(mbar); | ||
|
||
return 0; | ||
} | ||
|
||
static struct pm_ops mpc52xx_pm_ops = { | ||
.valid = mpc52xx_pm_valid, | ||
.prepare = mpc52xx_pm_prepare, | ||
.enter = mpc52xx_pm_enter, | ||
.finish = mpc52xx_pm_finish, | ||
}; | ||
|
||
int __init mpc52xx_pm_init(void) | ||
{ | ||
pm_set_ops(&mpc52xx_pm_ops); | ||
return 0; | ||
} |
Oops, something went wrong.