123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- #include <asm/reg.h>
- #include <asm/ppc_asm.h>
- #include <asm/processor.h>
- #include <asm/cache.h>
- #define SDRAM_CTRL 0x104
- #define SC_MODE_EN (1<<31)
- #define SC_CKE (1<<30)
- #define SC_REF_EN (1<<28)
- #define SC_SOFT_PRE (1<<1)
- #define GPIOW_GPIOE 0xc00
- #define GPIOW_DDR 0xc08
- #define GPIOW_DVO 0xc0c
- #define CDM_CE 0x214
- #define CDM_SDRAM (1<<3)
- /* helpers... beware: r10 and r4 are overwritten */
- #define SAVE_SPRN(reg, addr) \
- mfspr r10, SPRN_##reg; \
- stw r10, ((addr)*4)(r4);
- #define LOAD_SPRN(reg, addr) \
- lwz r10, ((addr)*4)(r4); \
- mtspr SPRN_##reg, r10; \
- sync; \
- isync;
- .data
- registers:
- .space 0x5c*4
- .text
- /* ---------------------------------------------------------------------- */
- /* low-power mode with help of M68HLC908QT1 */
- .globl lite5200_low_power
- lite5200_low_power:
- mr r7, r3 /* save SRAM va */
- mr r8, r4 /* save MBAR va */
- /* setup wakeup address for u-boot at physical location 0x0 */
- lis r3, CONFIG_KERNEL_START@h
- lis r4, lite5200_wakeup@h
- ori r4, r4, lite5200_wakeup@l
- sub r4, r4, r3
- stw r4, 0(r3)
- /*
- * save stuff BDI overwrites
- * 0xf0 (0xe0->0x100 gets overwritten when BDI connected;
- * even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?))
- * WARNING: self-refresh doesn't seem to work when BDI2000 is connected,
- * possibly because BDI sets SDRAM registers before wakeup code does
- */
- lis r4, registers@h
- ori r4, r4, registers@l
- lwz r10, 0xf0(r3)
- stw r10, (0x1d*4)(r4)
- /* save registers to r4 [destroys r10] */
- SAVE_SPRN(LR, 0x1c)
- bl save_regs
- /* flush caches [destroys r3, r4] */
- bl flush_data_cache
- /* copy code to sram */
- mr r4, r7
- li r3, (sram_code_end - sram_code)/4
- mtctr r3
- lis r3, sram_code@h
- ori r3, r3, sram_code@l
- 1:
- lwz r5, 0(r3)
- stw r5, 0(r4)
- addi r3, r3, 4
- addi r4, r4, 4
- bdnz 1b
- /* get tb_ticks_per_usec */
- lis r3, tb_ticks_per_usec@h
- lwz r11, tb_ticks_per_usec@l(r3)
- /* disable I and D caches */
- mfspr r3, SPRN_HID0
- ori r3, r3, HID0_ICE | HID0_DCE
- xori r3, r3, HID0_ICE | HID0_DCE
- sync; isync;
- mtspr SPRN_HID0, r3
- sync; isync;
- /* jump to sram */
- mtlr r7
- blrl
- /* doesn't return */
- sram_code:
- /* self refresh */
- lwz r4, SDRAM_CTRL(r8)
- /* send NOP (precharge) */
- oris r4, r4, SC_MODE_EN@h /* mode_en */
- stw r4, SDRAM_CTRL(r8)
- sync
- ori r4, r4, SC_SOFT_PRE /* soft_pre */
- stw r4, SDRAM_CTRL(r8)
- sync
- xori r4, r4, SC_SOFT_PRE
- xoris r4, r4, SC_MODE_EN@h /* !mode_en */
- stw r4, SDRAM_CTRL(r8)
- sync
- /* delay (for NOP to finish) */
- li r12, 1
- bl udelay
- /*
- * mode_en must not be set when enabling self-refresh
- * send AR with CKE low (self-refresh)
- */
- oris r4, r4, (SC_REF_EN | SC_CKE)@h
- xoris r4, r4, (SC_CKE)@h /* ref_en !cke */
- stw r4, SDRAM_CTRL(r8)
- sync
- /* delay (after !CKE there should be two cycles) */
- li r12, 1
- bl udelay
- /* disable clock */
- lwz r4, CDM_CE(r8)
- ori r4, r4, CDM_SDRAM
- xori r4, r4, CDM_SDRAM
- stw r4, CDM_CE(r8)
- sync
- /* delay a bit */
- li r12, 1
- bl udelay
- /* turn off with QT chip */
- li r4, 0x02
- stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */
- sync
- stb r4, GPIOW_DVO(r8) /* "output" high */
- sync
- stb r4, GPIOW_DDR(r8) /* output */
- sync
- stb r4, GPIOW_DVO(r8) /* output high */
- sync
- /* 10uS delay */
- li r12, 10
- bl udelay
- /* turn off */
- li r4, 0
- stb r4, GPIOW_DVO(r8) /* output low */
- sync
- /* wait until we're offline */
- 1:
- b 1b
- /* local udelay in sram is needed */
- udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */
- mullw r12, r12, r11
- mftb r13 /* start */
- addi r12, r13, r12 /* end */
- 1:
- mftb r13 /* current */
- cmp cr0, r13, r12
- blt 1b
- blr
- sram_code_end:
- /* uboot jumps here on resume */
- lite5200_wakeup:
- bl restore_regs
- /* HIDs, MSR */
- LOAD_SPRN(HID1, 0x19)
- LOAD_SPRN(HID2, 0x1a)
- /* address translation is tricky (see turn_on_mmu) */
- mfmsr r10
- ori r10, r10, MSR_DR | MSR_IR
- mtspr SPRN_SRR1, r10
- lis r10, mmu_on@h
- ori r10, r10, mmu_on@l
- mtspr SPRN_SRR0, r10
- sync
- rfi
- mmu_on:
- /* kernel offset (r4 is still set from restore_registers) */
- addis r4, r4, CONFIG_KERNEL_START@h
- /* restore MSR */
- lwz r10, (4*0x1b)(r4)
- mtmsr r10
- sync; isync;
- /* invalidate caches */
- mfspr r10, SPRN_HID0
- ori r5, r10, HID0_ICFI | HID0_DCI
- mtspr SPRN_HID0, r5 /* invalidate caches */
- sync; isync;
- mtspr SPRN_HID0, r10
- sync; isync;
- /* enable caches */
- lwz r10, (4*0x18)(r4)
- mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */
- /* ^ this has to be after address translation set in MSR */
- sync
- isync
- /* restore 0xf0 (BDI2000) */
- lis r3, CONFIG_KERNEL_START@h
- lwz r10, (0x1d*4)(r4)
- stw r10, 0xf0(r3)
- LOAD_SPRN(LR, 0x1c)
- blr
- /* ---------------------------------------------------------------------- */
- /* boring code: helpers */
- /* save registers */
- #define SAVE_BAT(n, addr) \
- SAVE_SPRN(DBAT##n##L, addr); \
- SAVE_SPRN(DBAT##n##U, addr+1); \
- SAVE_SPRN(IBAT##n##L, addr+2); \
- SAVE_SPRN(IBAT##n##U, addr+3);
- #define SAVE_SR(n, addr) \
- mfsr r10, n; \
- stw r10, ((addr)*4)(r4);
- #define SAVE_4SR(n, addr) \
- SAVE_SR(n, addr); \
- SAVE_SR(n+1, addr+1); \
- SAVE_SR(n+2, addr+2); \
- SAVE_SR(n+3, addr+3);
- save_regs:
- stw r0, 0(r4)
- stw r1, 0x4(r4)
- stw r2, 0x8(r4)
- stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */
- SAVE_SPRN(HID0, 0x18)
- SAVE_SPRN(HID1, 0x19)
- SAVE_SPRN(HID2, 0x1a)
- mfmsr r10
- stw r10, (4*0x1b)(r4)
- /*SAVE_SPRN(LR, 0x1c) have to save it before the call */
- /* 0x1d reserved by 0xf0 */
- SAVE_SPRN(RPA, 0x1e)
- SAVE_SPRN(SDR1, 0x1f)
- /* save MMU regs */
- SAVE_BAT(0, 0x20)
- SAVE_BAT(1, 0x24)
- SAVE_BAT(2, 0x28)
- SAVE_BAT(3, 0x2c)
- SAVE_BAT(4, 0x30)
- SAVE_BAT(5, 0x34)
- SAVE_BAT(6, 0x38)
- SAVE_BAT(7, 0x3c)
- SAVE_4SR(0, 0x40)
- SAVE_4SR(4, 0x44)
- SAVE_4SR(8, 0x48)
- SAVE_4SR(12, 0x4c)
- SAVE_SPRN(SPRG0, 0x50)
- SAVE_SPRN(SPRG1, 0x51)
- SAVE_SPRN(SPRG2, 0x52)
- SAVE_SPRN(SPRG3, 0x53)
- SAVE_SPRN(SPRG4, 0x54)
- SAVE_SPRN(SPRG5, 0x55)
- SAVE_SPRN(SPRG6, 0x56)
- SAVE_SPRN(SPRG7, 0x57)
- SAVE_SPRN(IABR, 0x58)
- SAVE_SPRN(DABR, 0x59)
- SAVE_SPRN(TBRL, 0x5a)
- SAVE_SPRN(TBRU, 0x5b)
- blr
- /* restore registers */
- #define LOAD_BAT(n, addr) \
- LOAD_SPRN(DBAT##n##L, addr); \
- LOAD_SPRN(DBAT##n##U, addr+1); \
- LOAD_SPRN(IBAT##n##L, addr+2); \
- LOAD_SPRN(IBAT##n##U, addr+3);
- #define LOAD_SR(n, addr) \
- lwz r10, ((addr)*4)(r4); \
- mtsr n, r10;
- #define LOAD_4SR(n, addr) \
- LOAD_SR(n, addr); \
- LOAD_SR(n+1, addr+1); \
- LOAD_SR(n+2, addr+2); \
- LOAD_SR(n+3, addr+3);
- restore_regs:
- lis r4, registers@h
- ori r4, r4, registers@l
- /* MMU is not up yet */
- subis r4, r4, CONFIG_KERNEL_START@h
- lwz r0, 0(r4)
- lwz r1, 0x4(r4)
- lwz r2, 0x8(r4)
- lmw r11, 0xc(r4)
- /*
- * these are a bit tricky
- *
- * 0x18 - HID0
- * 0x19 - HID1
- * 0x1a - HID2
- * 0x1b - MSR
- * 0x1c - LR
- * 0x1d - reserved by 0xf0 (BDI2000)
- */
- LOAD_SPRN(RPA, 0x1e);
- LOAD_SPRN(SDR1, 0x1f);
- /* restore MMU regs */
- LOAD_BAT(0, 0x20)
- LOAD_BAT(1, 0x24)
- LOAD_BAT(2, 0x28)
- LOAD_BAT(3, 0x2c)
- LOAD_BAT(4, 0x30)
- LOAD_BAT(5, 0x34)
- LOAD_BAT(6, 0x38)
- LOAD_BAT(7, 0x3c)
- LOAD_4SR(0, 0x40)
- LOAD_4SR(4, 0x44)
- LOAD_4SR(8, 0x48)
- LOAD_4SR(12, 0x4c)
- /* rest of regs */
- LOAD_SPRN(SPRG0, 0x50);
- LOAD_SPRN(SPRG1, 0x51);
- LOAD_SPRN(SPRG2, 0x52);
- LOAD_SPRN(SPRG3, 0x53);
- LOAD_SPRN(SPRG4, 0x54);
- LOAD_SPRN(SPRG5, 0x55);
- LOAD_SPRN(SPRG6, 0x56);
- LOAD_SPRN(SPRG7, 0x57);
- LOAD_SPRN(IABR, 0x58);
- LOAD_SPRN(DABR, 0x59);
- LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */
- LOAD_SPRN(TBWU, 0x5b);
- blr
- /* cache flushing code. copied from arch/ppc/boot/util.S */
- #define NUM_CACHE_LINES (128*8)
- /*
- * Flush data cache
- * Do this by just reading lots of stuff into the cache.
- */
- flush_data_cache:
- lis r3,CONFIG_KERNEL_START@h
- ori r3,r3,CONFIG_KERNEL_START@l
- li r4,NUM_CACHE_LINES
- mtctr r4
- 1:
- lwz r4,0(r3)
- addi r3,r3,L1_CACHE_BYTES /* Next line, please */
- bdnz 1b
- blr
|