1/* SPDX-License-Identifier: GPL-2.0 */ 2#include <linux/linkage.h> 3#include <asm/blackfin.h> 4#include <asm/dpmc.h> 5 6#include <asm/context.S> 7 8#define PM_STACK (COREA_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12) 9 10.section .l1.text 11ENTRY(_enter_hibernate) 12 /* switch stack to L1 scratch, prepare for ddr srfr */ 13 P0.H = HI(PM_STACK); 14 P0.L = LO(PM_STACK); 15 SP = P0; 16 17 call _bf609_ddr_sr; 18 call _bfin_hibernate_syscontrol; 19 20 P0.H = HI(DPM0_RESTORE4); 21 P0.L = LO(DPM0_RESTORE4); 22 P1.H = _bf609_pm_data; 23 P1.L = _bf609_pm_data; 24 [P0] = P1; 25 26 P0.H = HI(DPM0_CTL); 27 P0.L = LO(DPM0_CTL); 28 R3.H = HI(0x00000010); 29 R3.L = LO(0x00000010); 30 31 bfin_init_pm_bench_cycles; 32 33 [P0] = R3; 34 35 SSYNC; 36ENDPROC(_enter_hibernate) 37 38/* DPM wake up interrupt won't wake up core on bf60x if its core IMASK 39 * is disabled. This behavior differ from bf5xx serial processor. 40 */ 41ENTRY(_dummy_deepsleep) 42 [--sp] = SYSCFG; 43 [--sp] = (R7:0,P5:0); 44 cli r0; 45 46 /* get wake up interrupt ID */ 47 P0.l = LO(SEC_SCI_BASE + SEC_CSID); 48 P0.h = HI(SEC_SCI_BASE + SEC_CSID); 49 R0 = [P0]; 50 51 /* ACK wake up interrupt in SEC */ 52 P1.l = LO(SEC_END); 53 P1.h = HI(SEC_END); 54 55 [P1] = R0; 56 SSYNC; 57 58 /* restore EVT 11 entry */ 59 p0.h = hi(EVT11); 60 p0.l = lo(EVT11); 61 p1.h = _evt_evt11; 62 p1.l = _evt_evt11; 63 64 [p0] = p1; 65 SSYNC; 66 67 (R7:0,P5:0) = [sp++]; 68 SYSCFG = [sp++]; 69 RTI; 70ENDPROC(_dummy_deepsleep) 71 72ENTRY(_enter_deepsleep) 73 LINK 0xC; 74 [--sp] = (R7:0,P5:0); 75 76 /* Change EVT 11 entry to dummy handler for wake up event */ 77 p0.h = hi(EVT11); 78 p0.l = lo(EVT11); 79 p1.h = _dummy_deepsleep; 80 p1.l = _dummy_deepsleep; 81 82 [p0] = p1; 83 84 P0.H = HI(PM_STACK); 85 P0.L = LO(PM_STACK); 86 87 EX_SCRATCH_REG = SP; 88 SP = P0; 89 90 SSYNC; 91 92 /* should put ddr to self refresh mode before sleep */ 93 call _bf609_ddr_sr; 94 95 /* Set DPM controller to deep sleep mode */ 96 P0.H = HI(DPM0_CTL); 97 P0.L = LO(DPM0_CTL); 98 R3.H = HI(0x00000008); 99 R3.L = LO(0x00000008); 100 [P0] = R3; 101 CSYNC; 102 103 /* Enable evt 11 in IMASK before idle, otherwise core doesn't wake up. */ 104 r0.l = 0x800; 105 r0.h = 0; 106 sti r0; 107 SSYNC; 108 109 bfin_init_pm_bench_cycles; 110 111 /* Fall into deep sleep in idle*/ 112 idle; 113 SSYNC; 114 115 /* Restore PLL after wake up from deep sleep */ 116 call _bf609_resume_ccbuf; 117 118 /* turn ddr out of self refresh mode */ 119 call _bf609_ddr_sr_exit; 120 121 SP = EX_SCRATCH_REG; 122 123 (R7:0,P5:0) = [SP++]; 124 UNLINK; 125 RTS; 126ENDPROC(_enter_deepsleep) 127 128.section .text 129ENTRY(_bf609_hibernate) 130 bfin_cpu_reg_save; 131 bfin_core_mmr_save; 132 133 P0.H = _bf609_pm_data; 134 P0.L = _bf609_pm_data; 135 R1.H = 0xDEAD; 136 R1.L = 0xBEEF; 137 R2.H = .Lpm_resume_here; 138 R2.L = .Lpm_resume_here; 139 [P0++] = R1; 140 [P0++] = R2; 141 [P0++] = SP; 142 143 P1.H = _enter_hibernate; 144 P1.L = _enter_hibernate; 145 146 call (P1); 147.Lpm_resume_here: 148 149 bfin_core_mmr_restore; 150 bfin_cpu_reg_restore; 151 152 [--sp] = RETI; /* Clear Global Interrupt Disable */ 153 SP += 4; 154 155 RTS; 156 157ENDPROC(_bf609_hibernate) 158 159