Path: blob/master/arch/powerpc/platforms/52xx/lite5200_sleep.S
10818 views
#include <asm/reg.h>1#include <asm/ppc_asm.h>2#include <asm/processor.h>3#include <asm/cache.h>456#define SDRAM_CTRL 0x1047#define SC_MODE_EN (1<<31)8#define SC_CKE (1<<30)9#define SC_REF_EN (1<<28)10#define SC_SOFT_PRE (1<<1)1112#define GPIOW_GPIOE 0xc0013#define GPIOW_DDR 0xc0814#define GPIOW_DVO 0xc0c1516#define CDM_CE 0x21417#define CDM_SDRAM (1<<3)181920/* helpers... beware: r10 and r4 are overwritten */21#define SAVE_SPRN(reg, addr) \22mfspr r10, SPRN_##reg; \23stw r10, ((addr)*4)(r4);2425#define LOAD_SPRN(reg, addr) \26lwz r10, ((addr)*4)(r4); \27mtspr SPRN_##reg, r10; \28sync; \29isync;303132.data33registers:34.space 0x5c*435.text3637/* ---------------------------------------------------------------------- */38/* low-power mode with help of M68HLC908QT1 */3940.globl lite5200_low_power41lite5200_low_power:4243mr r7, r3 /* save SRAM va */44mr r8, r4 /* save MBAR va */4546/* setup wakeup address for u-boot at physical location 0x0 */47lis r3, CONFIG_KERNEL_START@h48lis r4, lite5200_wakeup@h49ori r4, r4, lite5200_wakeup@l50sub r4, r4, r351stw r4, 0(r3)525354/*55* save stuff BDI overwrites56* 0xf0 (0xe0->0x100 gets overwritten when BDI connected;57* even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?))58* WARNING: self-refresh doesn't seem to work when BDI2000 is connected,59* possibly because BDI sets SDRAM registers before wakeup code does60*/61lis r4, registers@h62ori r4, r4, registers@l63lwz r10, 0xf0(r3)64stw r10, (0x1d*4)(r4)6566/* save registers to r4 [destroys r10] */67SAVE_SPRN(LR, 0x1c)68bl save_regs6970/* flush caches [destroys r3, r4] */71bl flush_data_cache727374/* copy code to sram */75mr r4, r776li r3, (sram_code_end - sram_code)/477mtctr r378lis r3, sram_code@h79ori r3, r3, sram_code@l801:81lwz r5, 0(r3)82stw r5, 0(r4)83addi r3, r3, 484addi r4, r4, 485bdnz 1b8687/* get tb_ticks_per_usec */88lis r3, tb_ticks_per_usec@h89lwz r11, tb_ticks_per_usec@l(r3)9091/* disable I and D caches */92mfspr r3, SPRN_HID093ori r3, r3, HID0_ICE | HID0_DCE94xori r3, r3, HID0_ICE | HID0_DCE95sync; isync;96mtspr SPRN_HID0, r397sync; isync;9899/* jump to sram */100mtlr r7101blrl102/* doesn't return */103104105sram_code:106/* self refresh */107lwz r4, SDRAM_CTRL(r8)108109/* send NOP (precharge) */110oris r4, r4, SC_MODE_EN@h /* mode_en */111stw r4, SDRAM_CTRL(r8)112sync113114ori r4, r4, SC_SOFT_PRE /* soft_pre */115stw r4, SDRAM_CTRL(r8)116sync117xori r4, r4, SC_SOFT_PRE118119xoris r4, r4, SC_MODE_EN@h /* !mode_en */120stw r4, SDRAM_CTRL(r8)121sync122123/* delay (for NOP to finish) */124li r12, 1125bl udelay126127/*128* mode_en must not be set when enabling self-refresh129* send AR with CKE low (self-refresh)130*/131oris r4, r4, (SC_REF_EN | SC_CKE)@h132xoris r4, r4, (SC_CKE)@h /* ref_en !cke */133stw r4, SDRAM_CTRL(r8)134sync135136/* delay (after !CKE there should be two cycles) */137li r12, 1138bl udelay139140/* disable clock */141lwz r4, CDM_CE(r8)142ori r4, r4, CDM_SDRAM143xori r4, r4, CDM_SDRAM144stw r4, CDM_CE(r8)145sync146147/* delay a bit */148li r12, 1149bl udelay150151152/* turn off with QT chip */153li r4, 0x02154stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */155sync156157stb r4, GPIOW_DVO(r8) /* "output" high */158sync159stb r4, GPIOW_DDR(r8) /* output */160sync161stb r4, GPIOW_DVO(r8) /* output high */162sync163164/* 10uS delay */165li r12, 10166bl udelay167168/* turn off */169li r4, 0170stb r4, GPIOW_DVO(r8) /* output low */171sync172173/* wait until we're offline */1741:175b 1b176177178/* local udelay in sram is needed */179udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */180mullw r12, r12, r11181mftb r13 /* start */182addi r12, r13, r12 /* end */1831:184mftb r13 /* current */185cmp cr0, r13, r12186blt 1b187blr188189sram_code_end:190191192193/* uboot jumps here on resume */194lite5200_wakeup:195bl restore_regs196197198/* HIDs, MSR */199LOAD_SPRN(HID1, 0x19)200LOAD_SPRN(HID2, 0x1a)201202203/* address translation is tricky (see turn_on_mmu) */204mfmsr r10205ori r10, r10, MSR_DR | MSR_IR206207208mtspr SPRN_SRR1, r10209lis r10, mmu_on@h210ori r10, r10, mmu_on@l211mtspr SPRN_SRR0, r10212sync213rfi214mmu_on:215/* kernel offset (r4 is still set from restore_registers) */216addis r4, r4, CONFIG_KERNEL_START@h217218219/* restore MSR */220lwz r10, (4*0x1b)(r4)221mtmsr r10222sync; isync;223224/* invalidate caches */225mfspr r10, SPRN_HID0226ori r5, r10, HID0_ICFI | HID0_DCI227mtspr SPRN_HID0, r5 /* invalidate caches */228sync; isync;229mtspr SPRN_HID0, r10230sync; isync;231232/* enable caches */233lwz r10, (4*0x18)(r4)234mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */235/* ^ this has to be after address translation set in MSR */236sync237isync238239240/* restore 0xf0 (BDI2000) */241lis r3, CONFIG_KERNEL_START@h242lwz r10, (0x1d*4)(r4)243stw r10, 0xf0(r3)244245LOAD_SPRN(LR, 0x1c)246247248blr249250251/* ---------------------------------------------------------------------- */252/* boring code: helpers */253254/* save registers */255#define SAVE_BAT(n, addr) \256SAVE_SPRN(DBAT##n##L, addr); \257SAVE_SPRN(DBAT##n##U, addr+1); \258SAVE_SPRN(IBAT##n##L, addr+2); \259SAVE_SPRN(IBAT##n##U, addr+3);260261#define SAVE_SR(n, addr) \262mfsr r10, n; \263stw r10, ((addr)*4)(r4);264265#define SAVE_4SR(n, addr) \266SAVE_SR(n, addr); \267SAVE_SR(n+1, addr+1); \268SAVE_SR(n+2, addr+2); \269SAVE_SR(n+3, addr+3);270271save_regs:272stw r0, 0(r4)273stw r1, 0x4(r4)274stw r2, 0x8(r4)275stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */276277SAVE_SPRN(HID0, 0x18)278SAVE_SPRN(HID1, 0x19)279SAVE_SPRN(HID2, 0x1a)280mfmsr r10281stw r10, (4*0x1b)(r4)282/*SAVE_SPRN(LR, 0x1c) have to save it before the call */283/* 0x1d reserved by 0xf0 */284SAVE_SPRN(RPA, 0x1e)285SAVE_SPRN(SDR1, 0x1f)286287/* save MMU regs */288SAVE_BAT(0, 0x20)289SAVE_BAT(1, 0x24)290SAVE_BAT(2, 0x28)291SAVE_BAT(3, 0x2c)292SAVE_BAT(4, 0x30)293SAVE_BAT(5, 0x34)294SAVE_BAT(6, 0x38)295SAVE_BAT(7, 0x3c)296297SAVE_4SR(0, 0x40)298SAVE_4SR(4, 0x44)299SAVE_4SR(8, 0x48)300SAVE_4SR(12, 0x4c)301302SAVE_SPRN(SPRG0, 0x50)303SAVE_SPRN(SPRG1, 0x51)304SAVE_SPRN(SPRG2, 0x52)305SAVE_SPRN(SPRG3, 0x53)306SAVE_SPRN(SPRG4, 0x54)307SAVE_SPRN(SPRG5, 0x55)308SAVE_SPRN(SPRG6, 0x56)309SAVE_SPRN(SPRG7, 0x57)310311SAVE_SPRN(IABR, 0x58)312SAVE_SPRN(DABR, 0x59)313SAVE_SPRN(TBRL, 0x5a)314SAVE_SPRN(TBRU, 0x5b)315316blr317318319/* restore registers */320#define LOAD_BAT(n, addr) \321LOAD_SPRN(DBAT##n##L, addr); \322LOAD_SPRN(DBAT##n##U, addr+1); \323LOAD_SPRN(IBAT##n##L, addr+2); \324LOAD_SPRN(IBAT##n##U, addr+3);325326#define LOAD_SR(n, addr) \327lwz r10, ((addr)*4)(r4); \328mtsr n, r10;329330#define LOAD_4SR(n, addr) \331LOAD_SR(n, addr); \332LOAD_SR(n+1, addr+1); \333LOAD_SR(n+2, addr+2); \334LOAD_SR(n+3, addr+3);335336restore_regs:337lis r4, registers@h338ori r4, r4, registers@l339340/* MMU is not up yet */341subis r4, r4, CONFIG_KERNEL_START@h342343lwz r0, 0(r4)344lwz r1, 0x4(r4)345lwz r2, 0x8(r4)346lmw r11, 0xc(r4)347348/*349* these are a bit tricky350*351* 0x18 - HID0352* 0x19 - HID1353* 0x1a - HID2354* 0x1b - MSR355* 0x1c - LR356* 0x1d - reserved by 0xf0 (BDI2000)357*/358LOAD_SPRN(RPA, 0x1e);359LOAD_SPRN(SDR1, 0x1f);360361/* restore MMU regs */362LOAD_BAT(0, 0x20)363LOAD_BAT(1, 0x24)364LOAD_BAT(2, 0x28)365LOAD_BAT(3, 0x2c)366LOAD_BAT(4, 0x30)367LOAD_BAT(5, 0x34)368LOAD_BAT(6, 0x38)369LOAD_BAT(7, 0x3c)370371LOAD_4SR(0, 0x40)372LOAD_4SR(4, 0x44)373LOAD_4SR(8, 0x48)374LOAD_4SR(12, 0x4c)375376/* rest of regs */377LOAD_SPRN(SPRG0, 0x50);378LOAD_SPRN(SPRG1, 0x51);379LOAD_SPRN(SPRG2, 0x52);380LOAD_SPRN(SPRG3, 0x53);381LOAD_SPRN(SPRG4, 0x54);382LOAD_SPRN(SPRG5, 0x55);383LOAD_SPRN(SPRG6, 0x56);384LOAD_SPRN(SPRG7, 0x57);385386LOAD_SPRN(IABR, 0x58);387LOAD_SPRN(DABR, 0x59);388LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */389LOAD_SPRN(TBWU, 0x5b);390391blr392393394395/* cache flushing code. copied from arch/ppc/boot/util.S */396#define NUM_CACHE_LINES (128*8)397398/*399* Flush data cache400* Do this by just reading lots of stuff into the cache.401*/402flush_data_cache:403lis r3,CONFIG_KERNEL_START@h404ori r3,r3,CONFIG_KERNEL_START@l405li r4,NUM_CACHE_LINES406mtctr r44071:408lwz r4,0(r3)409addi r3,r3,L1_CACHE_BYTES /* Next line, please */410bdnz 1b411blr412413414