1/* SPDX-License-Identifier: GPL-2.0 */ 2#include <linux/threads.h> 3#include <asm/processor.h> 4#include <asm/page.h> 5#include <asm/cputable.h> 6#include <asm/thread_info.h> 7#include <asm/ppc_asm.h> 8#include <asm/asm-offsets.h> 9#include <asm/mmu.h> 10#include <asm/feature-fixups.h> 11 12/* 13 * Structure for storing CPU registers on the save area. 14 */ 15#define SL_SP 0 16#define SL_PC 4 17#define SL_MSR 8 18#define SL_SDR1 0xc 19#define SL_SPRG0 0x10 /* 4 sprg's */ 20#define SL_DBAT0 0x20 21#define SL_IBAT0 0x28 22#define SL_DBAT1 0x30 23#define SL_IBAT1 0x38 24#define SL_DBAT2 0x40 25#define SL_IBAT2 0x48 26#define SL_DBAT3 0x50 27#define SL_IBAT3 0x58 28#define SL_TB 0x60 29#define SL_R2 0x68 30#define SL_CR 0x6c 31#define SL_LR 0x70 32#define SL_R12 0x74 /* r12 to r31 */ 33#define SL_SIZE (SL_R12 + 80) 34 35 .section .data 36 .align 5 37 38_GLOBAL(swsusp_save_area) 39 .space SL_SIZE 40 41 42 .section .text 43 .align 5 44 45_GLOBAL(swsusp_arch_suspend) 46 47 lis r11,swsusp_save_area@h 48 ori r11,r11,swsusp_save_area@l 49 50 mflr r0 51 stw r0,SL_LR(r11) 52 mfcr r0 53 stw r0,SL_CR(r11) 54 stw r1,SL_SP(r11) 55 stw r2,SL_R2(r11) 56 stmw r12,SL_R12(r11) 57 58 /* Save MSR & SDR1 */ 59 mfmsr r4 60 stw r4,SL_MSR(r11) 61 mfsdr1 r4 62 stw r4,SL_SDR1(r11) 63 64 /* Get a stable timebase and save it */ 651: mftbu r4 66 stw r4,SL_TB(r11) 67 mftb r5 68 stw r5,SL_TB+4(r11) 69 mftbu r3 70 cmpw r3,r4 71 bne 1b 72 73 /* Save SPRGs */ 74 mfsprg r4,0 75 stw r4,SL_SPRG0(r11) 76 mfsprg r4,1 77 stw r4,SL_SPRG0+4(r11) 78 mfsprg r4,2 79 stw r4,SL_SPRG0+8(r11) 80 mfsprg r4,3 81 stw r4,SL_SPRG0+12(r11) 82 83 /* Save BATs */ 84 mfdbatu r4,0 85 stw r4,SL_DBAT0(r11) 86 mfdbatl r4,0 87 stw r4,SL_DBAT0+4(r11) 88 mfdbatu r4,1 89 stw r4,SL_DBAT1(r11) 90 mfdbatl r4,1 91 stw r4,SL_DBAT1+4(r11) 92 mfdbatu r4,2 93 stw r4,SL_DBAT2(r11) 94 mfdbatl r4,2 95 stw r4,SL_DBAT2+4(r11) 96 mfdbatu r4,3 97 stw r4,SL_DBAT3(r11) 98 mfdbatl r4,3 99 stw r4,SL_DBAT3+4(r11) 100 mfibatu r4,0 101 stw r4,SL_IBAT0(r11) 102 mfibatl r4,0 103 stw r4,SL_IBAT0+4(r11) 104 mfibatu r4,1 105 stw r4,SL_IBAT1(r11) 106 mfibatl r4,1 107 stw r4,SL_IBAT1+4(r11) 108 mfibatu r4,2 109 stw r4,SL_IBAT2(r11) 110 mfibatl r4,2 111 stw r4,SL_IBAT2+4(r11) 112 mfibatu r4,3 113 stw r4,SL_IBAT3(r11) 114 mfibatl r4,3 115 stw r4,SL_IBAT3+4(r11) 116 117#if 0 118 /* Backup various CPU config stuffs */ 119 bl __save_cpu_setup 120#endif 121 /* Call the low level suspend stuff (we should probably have made 122 * a stackframe... 123 */ 124 bl swsusp_save 125 126 /* Restore LR from the save area */ 127 lis r11,swsusp_save_area@h 128 ori r11,r11,swsusp_save_area@l 129 lwz r0,SL_LR(r11) 130 mtlr r0 131 132 blr 133 134 135/* Resume code */ 136_GLOBAL(swsusp_arch_resume) 137 138#ifdef CONFIG_ALTIVEC 139 /* Stop pending alitvec streams and memory accesses */ 140BEGIN_FTR_SECTION 141 DSSALL 142END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 143#endif 144 sync 145 146 /* Disable MSR:DR to make sure we don't take a TLB or 147 * hash miss during the copy, as our hash table will 148 * for a while be unusable. For .text, we assume we are 149 * covered by a BAT. This works only for non-G5 at this 150 * point. G5 will need a better approach, possibly using 151 * a small temporary hash table filled with large mappings, 152 * disabling the MMU completely isn't a good option for 153 * performance reasons. 154 * (Note that 750's may have the same performance issue as 155 * the G5 in this case, we should investigate using moving 156 * BATs for these CPUs) 157 */ 158 mfmsr r0 159 sync 160 rlwinm r0,r0,0,28,26 /* clear MSR_DR */ 161 mtmsr r0 162 sync 163 isync 164 165 /* Load ptr the list of pages to copy in r3 */ 166 lis r11,(restore_pblist - KERNELBASE)@h 167 ori r11,r11,restore_pblist@l 168 lwz r10,0(r11) 169 170 /* Copy the pages. This is a very basic implementation, to 171 * be replaced by something more cache efficient */ 1721: 173 tophys(r3,r10) 174 li r0,256 175 mtctr r0 176 lwz r11,pbe_address(r3) /* source */ 177 tophys(r5,r11) 178 lwz r10,pbe_orig_address(r3) /* destination */ 179 tophys(r6,r10) 1802: 181 lwz r8,0(r5) 182 lwz r9,4(r5) 183 lwz r10,8(r5) 184 lwz r11,12(r5) 185 addi r5,r5,16 186 stw r8,0(r6) 187 stw r9,4(r6) 188 stw r10,8(r6) 189 stw r11,12(r6) 190 addi r6,r6,16 191 bdnz 2b 192 lwz r10,pbe_next(r3) 193 cmpwi 0,r10,0 194 bne 1b 195 196 /* Do a very simple cache flush/inval of the L1 to ensure 197 * coherency of the icache 198 */ 199 lis r3,0x0002 200 mtctr r3 201 li r3, 0 2021: 203 lwz r0,0(r3) 204 addi r3,r3,0x0020 205 bdnz 1b 206 isync 207 sync 208 209 /* Now flush those cache lines */ 210 lis r3,0x0002 211 mtctr r3 212 li r3, 0 2131: 214 dcbf 0,r3 215 addi r3,r3,0x0020 216 bdnz 1b 217 sync 218 219 /* Ok, we are now running with the kernel data of the old 220 * kernel fully restored. We can get to the save area 221 * easily now. As for the rest of the code, it assumes the 222 * loader kernel and the booted one are exactly identical 223 */ 224 lis r11,swsusp_save_area@h 225 ori r11,r11,swsusp_save_area@l 226 tophys(r11,r11) 227 228#if 0 229 /* Restore various CPU config stuffs */ 230 bl __restore_cpu_setup 231#endif 232 /* Restore the BATs, and SDR1. Then we can turn on the MMU. 233 * This is a bit hairy as we are running out of those BATs, 234 * but first, our code is probably in the icache, and we are 235 * writing the same value to the BAT, so that should be fine, 236 * though a better solution will have to be found long-term 237 */ 238 lwz r4,SL_SDR1(r11) 239 mtsdr1 r4 240 lwz r4,SL_SPRG0(r11) 241 mtsprg 0,r4 242 lwz r4,SL_SPRG0+4(r11) 243 mtsprg 1,r4 244 lwz r4,SL_SPRG0+8(r11) 245 mtsprg 2,r4 246 lwz r4,SL_SPRG0+12(r11) 247 mtsprg 3,r4 248 249#if 0 250 lwz r4,SL_DBAT0(r11) 251 mtdbatu 0,r4 252 lwz r4,SL_DBAT0+4(r11) 253 mtdbatl 0,r4 254 lwz r4,SL_DBAT1(r11) 255 mtdbatu 1,r4 256 lwz r4,SL_DBAT1+4(r11) 257 mtdbatl 1,r4 258 lwz r4,SL_DBAT2(r11) 259 mtdbatu 2,r4 260 lwz r4,SL_DBAT2+4(r11) 261 mtdbatl 2,r4 262 lwz r4,SL_DBAT3(r11) 263 mtdbatu 3,r4 264 lwz r4,SL_DBAT3+4(r11) 265 mtdbatl 3,r4 266 lwz r4,SL_IBAT0(r11) 267 mtibatu 0,r4 268 lwz r4,SL_IBAT0+4(r11) 269 mtibatl 0,r4 270 lwz r4,SL_IBAT1(r11) 271 mtibatu 1,r4 272 lwz r4,SL_IBAT1+4(r11) 273 mtibatl 1,r4 274 lwz r4,SL_IBAT2(r11) 275 mtibatu 2,r4 276 lwz r4,SL_IBAT2+4(r11) 277 mtibatl 2,r4 278 lwz r4,SL_IBAT3(r11) 279 mtibatu 3,r4 280 lwz r4,SL_IBAT3+4(r11) 281 mtibatl 3,r4 282#endif 283 284BEGIN_MMU_FTR_SECTION 285 li r4,0 286 mtspr SPRN_DBAT4U,r4 287 mtspr SPRN_DBAT4L,r4 288 mtspr SPRN_DBAT5U,r4 289 mtspr SPRN_DBAT5L,r4 290 mtspr SPRN_DBAT6U,r4 291 mtspr SPRN_DBAT6L,r4 292 mtspr SPRN_DBAT7U,r4 293 mtspr SPRN_DBAT7L,r4 294 mtspr SPRN_IBAT4U,r4 295 mtspr SPRN_IBAT4L,r4 296 mtspr SPRN_IBAT5U,r4 297 mtspr SPRN_IBAT5L,r4 298 mtspr SPRN_IBAT6U,r4 299 mtspr SPRN_IBAT6L,r4 300 mtspr SPRN_IBAT7U,r4 301 mtspr SPRN_IBAT7L,r4 302END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS) 303 304 /* Flush all TLBs */ 305 lis r4,0x1000 3061: addic. r4,r4,-0x1000 307 tlbie r4 308 bgt 1b 309 sync 310 311 /* restore the MSR and turn on the MMU */ 312 lwz r3,SL_MSR(r11) 313 bl turn_on_mmu 314 tovirt(r11,r11) 315 316 /* Restore TB */ 317 li r3,0 318 mttbl r3 319 lwz r3,SL_TB(r11) 320 lwz r4,SL_TB+4(r11) 321 mttbu r3 322 mttbl r4 323 324 /* Kick decrementer */ 325 li r0,1 326 mtdec r0 327 328 /* Restore the callee-saved registers and return */ 329 lwz r0,SL_CR(r11) 330 mtcr r0 331 lwz r2,SL_R2(r11) 332 lmw r12,SL_R12(r11) 333 lwz r1,SL_SP(r11) 334 lwz r0,SL_LR(r11) 335 mtlr r0 336 337 // XXX Note: we don't really need to call swsusp_resume 338 339 li r3,0 340 blr 341 342/* FIXME:This construct is actually not useful since we don't shut 343 * down the instruction MMU, we could just flip back MSR-DR on. 344 */ 345turn_on_mmu: 346 mflr r4 347 mtsrr0 r4 348 mtsrr1 r3 349 sync 350 isync 351 rfi 352 353