Path: blob/master/arch/powerpc/platforms/52xx/lite5200_sleep.S
26481 views
/* SPDX-License-Identifier: GPL-2.0 */1#include <linux/linkage.h>23#include <asm/reg.h>4#include <asm/ppc_asm.h>5#include <asm/processor.h>6#include <asm/cache.h>789#define SDRAM_CTRL 0x10410#define SC_MODE_EN (1<<31)11#define SC_CKE (1<<30)12#define SC_REF_EN (1<<28)13#define SC_SOFT_PRE (1<<1)1415#define GPIOW_GPIOE 0xc0016#define GPIOW_DDR 0xc0817#define GPIOW_DVO 0xc0c1819#define CDM_CE 0x21420#define CDM_SDRAM (1<<3)212223/* helpers... beware: r10 and r4 are overwritten */24#define SAVE_SPRN(reg, addr) \25mfspr r10, SPRN_##reg; \26stw r10, ((addr)*4)(r4);2728#define LOAD_SPRN(reg, addr) \29lwz r10, ((addr)*4)(r4); \30mtspr SPRN_##reg, r10; \31sync; \32isync;333435.data36registers:37.space 0x5c*438.text3940/* ---------------------------------------------------------------------- */41/* low-power mode with help of M68HLC908QT1 */4243.globl lite5200_low_power44lite5200_low_power:4546mr r7, r3 /* save SRAM va */47mr r8, r4 /* save MBAR va */4849/* setup wakeup address for u-boot at physical location 0x0 */50lis r3, CONFIG_KERNEL_START@h51lis r4, lite5200_wakeup@h52ori r4, r4, lite5200_wakeup@l53sub r4, r4, r354stw r4, 0(r3)555657/*58* save stuff BDI overwrites59* 0xf0 (0xe0->0x100 gets overwritten when BDI connected;60* even when CONFIG_BDI_SWITCH is disabled and MMU XLAT commented; heisenbug?))61* WARNING: self-refresh doesn't seem to work when BDI2000 is connected,62* possibly because BDI sets SDRAM registers before wakeup code does63*/64lis r4, registers@h65ori r4, r4, registers@l66lwz r10, 0xf0(r3)67stw r10, (0x1d*4)(r4)6869/* save registers to r4 [destroys r10] */70SAVE_SPRN(LR, 0x1c)71bl save_regs7273/* flush caches [destroys r3, r4] */74bl flush_data_cache757677/* copy code to sram */78mr r4, r779li r3, (sram_code_end - sram_code)/480mtctr r381lis r3, sram_code@h82ori r3, r3, sram_code@l831:84lwz r5, 0(r3)85stw r5, 0(r4)86addi r3, r3, 487addi r4, r4, 488bdnz 1b8990/* get tb_ticks_per_usec */91lis r3, tb_ticks_per_usec@h92lwz r11, tb_ticks_per_usec@l(r3)9394/* disable I and D caches */95mfspr r3, SPRN_HID096ori r3, r3, HID0_ICE | HID0_DCE97xori r3, r3, HID0_ICE | HID0_DCE98sync; isync;99mtspr SPRN_HID0, r3100sync; isync;101102/* jump to sram */103mtlr r7104blrl105/* doesn't return */106107108sram_code:109/* self refresh */110lwz r4, SDRAM_CTRL(r8)111112/* send NOP (precharge) */113oris r4, r4, SC_MODE_EN@h /* mode_en */114stw r4, SDRAM_CTRL(r8)115sync116117ori r4, r4, SC_SOFT_PRE /* soft_pre */118stw r4, SDRAM_CTRL(r8)119sync120xori r4, r4, SC_SOFT_PRE121122xoris r4, r4, SC_MODE_EN@h /* !mode_en */123stw r4, SDRAM_CTRL(r8)124sync125126/* delay (for NOP to finish) */127li r12, 1128bl udelay129130/*131* mode_en must not be set when enabling self-refresh132* send AR with CKE low (self-refresh)133*/134oris r4, r4, (SC_REF_EN | SC_CKE)@h135xoris r4, r4, (SC_CKE)@h /* ref_en !cke */136stw r4, SDRAM_CTRL(r8)137sync138139/* delay (after !CKE there should be two cycles) */140li r12, 1141bl udelay142143/* disable clock */144lwz r4, CDM_CE(r8)145ori r4, r4, CDM_SDRAM146xori r4, r4, CDM_SDRAM147stw r4, CDM_CE(r8)148sync149150/* delay a bit */151li r12, 1152bl udelay153154155/* turn off with QT chip */156li r4, 0x02157stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */158sync159160stb r4, GPIOW_DVO(r8) /* "output" high */161sync162stb r4, GPIOW_DDR(r8) /* output */163sync164stb r4, GPIOW_DVO(r8) /* output high */165sync166167/* 10uS delay */168li r12, 10169bl udelay170171/* turn off */172li r4, 0173stb r4, GPIOW_DVO(r8) /* output low */174sync175176/* wait until we're offline */1771:178b 1b179180181/* local udelay in sram is needed */182SYM_FUNC_START_LOCAL(udelay)183/* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */184mullw r12, r12, r11185mftb r13 /* start */186add r12, r13, r12 /* end */1871:188mftb r13 /* current */189cmp cr0, r13, r12190blt 1b191blr192SYM_FUNC_END(udelay)193194sram_code_end:195196197198/* uboot jumps here on resume */199lite5200_wakeup:200bl restore_regs201202203/* HIDs, MSR */204LOAD_SPRN(HID1, 0x19)205/* FIXME: Should this use HID2_G2_LE? */206LOAD_SPRN(HID2_750FX, 0x1a)207208209/* address translation is tricky (see turn_on_mmu) */210mfmsr r10211ori r10, r10, MSR_DR | MSR_IR212213214mtspr SPRN_SRR1, r10215lis r10, mmu_on@h216ori r10, r10, mmu_on@l217mtspr SPRN_SRR0, r10218sync219rfi220mmu_on:221/* kernel offset (r4 is still set from restore_registers) */222addis r4, r4, CONFIG_KERNEL_START@h223224225/* restore MSR */226lwz r10, (4*0x1b)(r4)227mtmsr r10228sync; isync;229230/* invalidate caches */231mfspr r10, SPRN_HID0232ori r5, r10, HID0_ICFI | HID0_DCI233mtspr SPRN_HID0, r5 /* invalidate caches */234sync; isync;235mtspr SPRN_HID0, r10236sync; isync;237238/* enable caches */239lwz r10, (4*0x18)(r4)240mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */241/* ^ this has to be after address translation set in MSR */242sync243isync244245246/* restore 0xf0 (BDI2000) */247lis r3, CONFIG_KERNEL_START@h248lwz r10, (0x1d*4)(r4)249stw r10, 0xf0(r3)250251LOAD_SPRN(LR, 0x1c)252253254blr255_ASM_NOKPROBE_SYMBOL(lite5200_wakeup)256257258/* ---------------------------------------------------------------------- */259/* boring code: helpers */260261/* save registers */262#define SAVE_BAT(n, addr) \263SAVE_SPRN(DBAT##n##L, addr); \264SAVE_SPRN(DBAT##n##U, addr+1); \265SAVE_SPRN(IBAT##n##L, addr+2); \266SAVE_SPRN(IBAT##n##U, addr+3);267268#define SAVE_SR(n, addr) \269mfsr r10, n; \270stw r10, ((addr)*4)(r4);271272#define SAVE_4SR(n, addr) \273SAVE_SR(n, addr); \274SAVE_SR(n+1, addr+1); \275SAVE_SR(n+2, addr+2); \276SAVE_SR(n+3, addr+3);277278SYM_FUNC_START_LOCAL(save_regs)279stw r0, 0(r4)280stw r1, 0x4(r4)281stw r2, 0x8(r4)282stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */283284SAVE_SPRN(HID0, 0x18)285SAVE_SPRN(HID1, 0x19)286/* FIXME: Should this use HID2_G2_LE? */287SAVE_SPRN(HID2_750FX, 0x1a)288mfmsr r10289stw r10, (4*0x1b)(r4)290/*SAVE_SPRN(LR, 0x1c) have to save it before the call */291/* 0x1d reserved by 0xf0 */292SAVE_SPRN(RPA, 0x1e)293SAVE_SPRN(SDR1, 0x1f)294295/* save MMU regs */296SAVE_BAT(0, 0x20)297SAVE_BAT(1, 0x24)298SAVE_BAT(2, 0x28)299SAVE_BAT(3, 0x2c)300SAVE_BAT(4, 0x30)301SAVE_BAT(5, 0x34)302SAVE_BAT(6, 0x38)303SAVE_BAT(7, 0x3c)304305SAVE_4SR(0, 0x40)306SAVE_4SR(4, 0x44)307SAVE_4SR(8, 0x48)308SAVE_4SR(12, 0x4c)309310SAVE_SPRN(SPRG0, 0x50)311SAVE_SPRN(SPRG1, 0x51)312SAVE_SPRN(SPRG2, 0x52)313SAVE_SPRN(SPRG3, 0x53)314SAVE_SPRN(SPRG4, 0x54)315SAVE_SPRN(SPRG5, 0x55)316SAVE_SPRN(SPRG6, 0x56)317SAVE_SPRN(SPRG7, 0x57)318319SAVE_SPRN(IABR, 0x58)320SAVE_SPRN(DABR, 0x59)321SAVE_SPRN(TBRL, 0x5a)322SAVE_SPRN(TBRU, 0x5b)323324blr325SYM_FUNC_END(save_regs)326327328/* restore registers */329#define LOAD_BAT(n, addr) \330LOAD_SPRN(DBAT##n##L, addr); \331LOAD_SPRN(DBAT##n##U, addr+1); \332LOAD_SPRN(IBAT##n##L, addr+2); \333LOAD_SPRN(IBAT##n##U, addr+3);334335#define LOAD_SR(n, addr) \336lwz r10, ((addr)*4)(r4); \337mtsr n, r10;338339#define LOAD_4SR(n, addr) \340LOAD_SR(n, addr); \341LOAD_SR(n+1, addr+1); \342LOAD_SR(n+2, addr+2); \343LOAD_SR(n+3, addr+3);344345SYM_FUNC_START_LOCAL(restore_regs)346lis r4, registers@h347ori r4, r4, registers@l348349/* MMU is not up yet */350subis r4, r4, CONFIG_KERNEL_START@h351352lwz r0, 0(r4)353lwz r1, 0x4(r4)354lwz r2, 0x8(r4)355lmw r11, 0xc(r4)356357/*358* these are a bit tricky359*360* 0x18 - HID0361* 0x19 - HID1362* 0x1a - HID2363* 0x1b - MSR364* 0x1c - LR365* 0x1d - reserved by 0xf0 (BDI2000)366*/367LOAD_SPRN(RPA, 0x1e);368LOAD_SPRN(SDR1, 0x1f);369370/* restore MMU regs */371LOAD_BAT(0, 0x20)372LOAD_BAT(1, 0x24)373LOAD_BAT(2, 0x28)374LOAD_BAT(3, 0x2c)375LOAD_BAT(4, 0x30)376LOAD_BAT(5, 0x34)377LOAD_BAT(6, 0x38)378LOAD_BAT(7, 0x3c)379380LOAD_4SR(0, 0x40)381LOAD_4SR(4, 0x44)382LOAD_4SR(8, 0x48)383LOAD_4SR(12, 0x4c)384385/* rest of regs */386LOAD_SPRN(SPRG0, 0x50);387LOAD_SPRN(SPRG1, 0x51);388LOAD_SPRN(SPRG2, 0x52);389LOAD_SPRN(SPRG3, 0x53);390LOAD_SPRN(SPRG4, 0x54);391LOAD_SPRN(SPRG5, 0x55);392LOAD_SPRN(SPRG6, 0x56);393LOAD_SPRN(SPRG7, 0x57);394395LOAD_SPRN(IABR, 0x58);396LOAD_SPRN(DABR, 0x59);397LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */398LOAD_SPRN(TBWU, 0x5b);399400blr401_ASM_NOKPROBE_SYMBOL(restore_regs)402SYM_FUNC_END(restore_regs)403404405406/* cache flushing code. copied from arch/ppc/boot/util.S */407#define NUM_CACHE_LINES (128*8)408409/*410* Flush data cache411* Do this by just reading lots of stuff into the cache.412*/413SYM_FUNC_START_LOCAL(flush_data_cache)414lis r3,CONFIG_KERNEL_START@h415ori r3,r3,CONFIG_KERNEL_START@l416li r4,NUM_CACHE_LINES417mtctr r44181:419lwz r4,0(r3)420addi r3,r3,L1_CACHE_BYTES /* Next line, please */421bdnz 1b422blr423SYM_FUNC_END(flush_data_cache)424425426