Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/mpc83xx: Power Management support

Basic PM support for 83xx. Standby is implemented as sleep.
Suspend-to-RAM is implemented as "deep sleep" (with the processor
turned off) on 831x.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

authored by

Scott Wood and committed by
Kumar Gala
d49747bd 7e72063c

+1005 -1
+1 -1
arch/powerpc/Kconfig
··· 199 199 200 200 config ARCH_SUSPEND_POSSIBLE 201 201 def_bool y 202 - depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 202 + depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx 203 203 204 204 config PPC_DCR_NATIVE 205 205 bool
+1
arch/powerpc/platforms/83xx/Makefile
··· 3 3 # 4 4 obj-y := misc.o usb.o 5 5 obj-$(CONFIG_PCI) += pci.o 6 + obj-$(CONFIG_SUSPEND) += suspend.o suspend-asm.o 6 7 obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o 7 8 obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o 8 9 obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o
+533
arch/powerpc/platforms/83xx/suspend-asm.S
··· 1 + /* 2 + * Enter and leave deep sleep state on MPC83xx 3 + * 4 + * Copyright (c) 2006-2008 Freescale Semiconductor, Inc. 5 + * Author: Scott Wood <scottwood@freescale.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published 9 + * by the Free Software Foundation. 10 + */ 11 + 12 + #include <asm/page.h> 13 + #include <asm/ppc_asm.h> 14 + #include <asm/reg.h> 15 + #include <asm/asm-offsets.h> 16 + 17 + #define SS_MEMSAVE 0x00 /* First 8 bytes of RAM */ 18 + #define SS_HID 0x08 /* 3 HIDs */ 19 + #define SS_IABR 0x14 /* 2 IABRs */ 20 + #define SS_IBCR 0x1c 21 + #define SS_DABR 0x20 /* 2 DABRs */ 22 + #define SS_DBCR 0x28 23 + #define SS_SP 0x2c 24 + #define SS_SR 0x30 /* 16 segment registers */ 25 + #define SS_R2 0x70 26 + #define SS_MSR 0x74 27 + #define SS_SDR1 0x78 28 + #define SS_LR 0x7c 29 + #define SS_SPRG 0x80 /* 4 SPRGs */ 30 + #define SS_DBAT 0x90 /* 8 DBATs */ 31 + #define SS_IBAT 0xd0 /* 8 IBATs */ 32 + #define SS_TB 0x110 33 + #define SS_CR 0x118 34 + #define SS_GPREG 0x11c /* r12-r31 */ 35 + #define STATE_SAVE_SIZE 0x16c 36 + 37 + .section .data 38 + .align 5 39 + 40 + mpc83xx_sleep_save_area: 41 + .space STATE_SAVE_SIZE 42 + immrbase: 43 + .long 0 44 + 45 + .section .text 46 + .align 5 47 + 48 + /* r3 = physical address of IMMR */ 49 + _GLOBAL(mpc83xx_enter_deep_sleep) 50 + lis r4, immrbase@ha 51 + stw r3, immrbase@l(r4) 52 + 53 + /* The first 2 words of memory are used to communicate with the 54 + * bootloader, to tell it how to resume. 55 + * 56 + * The first word is the magic number 0xf5153ae5, and the second 57 + * is the pointer to mpc83xx_deep_resume. 58 + * 59 + * The original content of these two words is saved in SS_MEMSAVE. 60 + */ 61 + 62 + lis r3, mpc83xx_sleep_save_area@h 63 + ori r3, r3, mpc83xx_sleep_save_area@l 64 + 65 + lis r4, KERNELBASE@h 66 + lwz r5, 0(r4) 67 + lwz r6, 4(r4) 68 + 69 + stw r5, SS_MEMSAVE+0(r3) 70 + stw r6, SS_MEMSAVE+4(r3) 71 + 72 + mfspr r5, SPRN_HID0 73 + mfspr r6, SPRN_HID1 74 + mfspr r7, SPRN_HID2 75 + 76 + stw r5, SS_HID+0(r3) 77 + stw r6, SS_HID+4(r3) 78 + stw r7, SS_HID+8(r3) 79 + 80 + mfspr r4, SPRN_IABR 81 + mfspr r5, SPRN_IABR2 82 + mfspr r6, SPRN_IBCR 83 + mfspr r7, SPRN_DABR 84 + mfspr r8, SPRN_DABR2 85 + mfspr r9, SPRN_DBCR 86 + 87 + stw r4, SS_IABR+0(r3) 88 + stw r5, SS_IABR+4(r3) 89 + stw r6, SS_IBCR(r3) 90 + stw r7, SS_DABR+0(r3) 91 + stw r8, SS_DABR+4(r3) 92 + stw r9, SS_DBCR(r3) 93 + 94 + mfspr r4, SPRN_SPRG0 95 + mfspr r5, SPRN_SPRG1 96 + mfspr r6, SPRN_SPRG2 97 + mfspr r7, SPRN_SPRG3 98 + mfsdr1 r8 99 + 100 + stw r4, SS_SPRG+0(r3) 101 + stw r5, SS_SPRG+4(r3) 102 + stw r6, SS_SPRG+8(r3) 103 + stw r7, SS_SPRG+12(r3) 104 + stw r8, SS_SDR1(r3) 105 + 106 + mfspr r4, SPRN_DBAT0U 107 + mfspr r5, SPRN_DBAT0L 108 + mfspr r6, SPRN_DBAT1U 109 + mfspr r7, SPRN_DBAT1L 110 + 111 + stw r4, SS_DBAT+0x00(r3) 112 + stw r5, SS_DBAT+0x04(r3) 113 + stw r6, SS_DBAT+0x08(r3) 114 + stw r7, SS_DBAT+0x0c(r3) 115 + 116 + mfspr r4, SPRN_DBAT2U 117 + mfspr r5, SPRN_DBAT2L 118 + mfspr r6, SPRN_DBAT3U 119 + mfspr r7, SPRN_DBAT3L 120 + 121 + stw r4, SS_DBAT+0x10(r3) 122 + stw r5, SS_DBAT+0x14(r3) 123 + stw r6, SS_DBAT+0x18(r3) 124 + stw r7, SS_DBAT+0x1c(r3) 125 + 126 + mfspr r4, SPRN_DBAT4U 127 + mfspr r5, SPRN_DBAT4L 128 + mfspr r6, SPRN_DBAT5U 129 + mfspr r7, SPRN_DBAT5L 130 + 131 + stw r4, SS_DBAT+0x20(r3) 132 + stw r5, SS_DBAT+0x24(r3) 133 + stw r6, SS_DBAT+0x28(r3) 134 + stw r7, SS_DBAT+0x2c(r3) 135 + 136 + mfspr r4, SPRN_DBAT6U 137 + mfspr r5, SPRN_DBAT6L 138 + mfspr r6, SPRN_DBAT7U 139 + mfspr r7, SPRN_DBAT7L 140 + 141 + stw r4, SS_DBAT+0x30(r3) 142 + stw r5, SS_DBAT+0x34(r3) 143 + stw r6, SS_DBAT+0x38(r3) 144 + stw r7, SS_DBAT+0x3c(r3) 145 + 146 + mfspr r4, SPRN_IBAT0U 147 + mfspr r5, SPRN_IBAT0L 148 + mfspr r6, SPRN_IBAT1U 149 + mfspr r7, SPRN_IBAT1L 150 + 151 + stw r4, SS_IBAT+0x00(r3) 152 + stw r5, SS_IBAT+0x04(r3) 153 + stw r6, SS_IBAT+0x08(r3) 154 + stw r7, SS_IBAT+0x0c(r3) 155 + 156 + mfspr r4, SPRN_IBAT2U 157 + mfspr r5, SPRN_IBAT2L 158 + mfspr r6, SPRN_IBAT3U 159 + mfspr r7, SPRN_IBAT3L 160 + 161 + stw r4, SS_IBAT+0x10(r3) 162 + stw r5, SS_IBAT+0x14(r3) 163 + stw r6, SS_IBAT+0x18(r3) 164 + stw r7, SS_IBAT+0x1c(r3) 165 + 166 + mfspr r4, SPRN_IBAT4U 167 + mfspr r5, SPRN_IBAT4L 168 + mfspr r6, SPRN_IBAT5U 169 + mfspr r7, SPRN_IBAT5L 170 + 171 + stw r4, SS_IBAT+0x20(r3) 172 + stw r5, SS_IBAT+0x24(r3) 173 + stw r6, SS_IBAT+0x28(r3) 174 + stw r7, SS_IBAT+0x2c(r3) 175 + 176 + mfspr r4, SPRN_IBAT6U 177 + mfspr r5, SPRN_IBAT6L 178 + mfspr r6, SPRN_IBAT7U 179 + mfspr r7, SPRN_IBAT7L 180 + 181 + stw r4, SS_IBAT+0x30(r3) 182 + stw r5, SS_IBAT+0x34(r3) 183 + stw r6, SS_IBAT+0x38(r3) 184 + stw r7, SS_IBAT+0x3c(r3) 185 + 186 + mfmsr r4 187 + mflr r5 188 + mfcr r6 189 + 190 + stw r4, SS_MSR(r3) 191 + stw r5, SS_LR(r3) 192 + stw r6, SS_CR(r3) 193 + stw r1, SS_SP(r3) 194 + stw r2, SS_R2(r3) 195 + 196 + 1: mftbu r4 197 + mftb r5 198 + mftbu r6 199 + cmpw r4, r6 200 + bne 1b 201 + 202 + stw r4, SS_TB+0(r3) 203 + stw r5, SS_TB+4(r3) 204 + 205 + stmw r12, SS_GPREG(r3) 206 + 207 + li r4, 0 208 + addi r6, r3, SS_SR-4 209 + 1: mfsrin r5, r4 210 + stwu r5, 4(r6) 211 + addis r4, r4, 0x1000 212 + cmpwi r4, 0 213 + bne 1b 214 + 215 + /* Disable machine checks and critical exceptions */ 216 + mfmsr r4 217 + rlwinm r4, r4, 0, ~MSR_CE 218 + rlwinm r4, r4, 0, ~MSR_ME 219 + mtmsr r4 220 + isync 221 + 222 + #define TMP_VIRT_IMMR 0xf0000000 223 + #define DEFAULT_IMMR_VALUE 0xff400000 224 + #define IMMRBAR_BASE 0x0000 225 + 226 + lis r4, immrbase@ha 227 + lwz r4, immrbase@l(r4) 228 + 229 + /* Use DBAT0 to address the current IMMR space */ 230 + 231 + ori r4, r4, 0x002a 232 + mtspr SPRN_DBAT0L, r4 233 + lis r8, TMP_VIRT_IMMR@h 234 + ori r4, r8, 0x001e /* 1 MByte accessable from Kernel Space only */ 235 + mtspr SPRN_DBAT0U, r4 236 + isync 237 + 238 + /* Use DBAT1 to address the original IMMR space */ 239 + 240 + lis r4, DEFAULT_IMMR_VALUE@h 241 + ori r4, r4, 0x002a 242 + mtspr SPRN_DBAT1L, r4 243 + lis r9, (TMP_VIRT_IMMR + 0x01000000)@h 244 + ori r4, r9, 0x001e /* 1 MByte accessable from Kernel Space only */ 245 + mtspr SPRN_DBAT1U, r4 246 + isync 247 + 248 + /* Use DBAT2 to address the beginning of RAM. This isn't done 249 + * using the normal virtual mapping, because with page debugging 250 + * enabled it will be read-only. 251 + */ 252 + 253 + li r4, 0x0002 254 + mtspr SPRN_DBAT2L, r4 255 + lis r4, KERNELBASE@h 256 + ori r4, r4, 0x001e /* 1 MByte accessable from Kernel Space only */ 257 + mtspr SPRN_DBAT2U, r4 258 + isync 259 + 260 + /* Flush the cache with our BAT, as there will be TLB misses 261 + * otherwise if page debugging is enabled, and these misses 262 + * will disturb the PLRU algorithm. 263 + */ 264 + 265 + bl __flush_disable_L1 266 + 267 + /* Keep the i-cache enabled, so the hack below for low-boot 268 + * flash will work. 269 + */ 270 + mfspr r3, SPRN_HID0 271 + ori r3, r3, HID0_ICE 272 + mtspr SPRN_HID0, r3 273 + isync 274 + 275 + lis r6, 0xf515 276 + ori r6, r6, 0x3ae5 277 + 278 + lis r7, mpc83xx_deep_resume@h 279 + ori r7, r7, mpc83xx_deep_resume@l 280 + tophys(r7, r7) 281 + 282 + lis r5, KERNELBASE@h 283 + stw r6, 0(r5) 284 + stw r7, 4(r5) 285 + 286 + /* Reset BARs */ 287 + 288 + li r4, 0 289 + stw r4, 0x0024(r8) 290 + stw r4, 0x002c(r8) 291 + stw r4, 0x0034(r8) 292 + stw r4, 0x003c(r8) 293 + stw r4, 0x0064(r8) 294 + stw r4, 0x006c(r8) 295 + 296 + /* Rev 1 of the 8313 has problems with wakeup events that are 297 + * pending during the transition to deep sleep state (such as if 298 + * the PCI host sets the state to D3 and then D0 in rapid 299 + * succession). This check shrinks the race window somewhat. 300 + * 301 + * See erratum PCI23, though the problem is not limited 302 + * to PCI. 303 + */ 304 + 305 + lwz r3, 0x0b04(r8) 306 + andi. r3, r3, 1 307 + bne- mpc83xx_deep_resume 308 + 309 + /* Move IMMR back to the default location, following the 310 + * procedure specified in the MPC8313 manual. 311 + */ 312 + lwz r4, IMMRBAR_BASE(r8) 313 + isync 314 + lis r4, DEFAULT_IMMR_VALUE@h 315 + stw r4, IMMRBAR_BASE(r8) 316 + lis r4, KERNELBASE@h 317 + lwz r4, 0(r4) 318 + isync 319 + lwz r4, IMMRBAR_BASE(r9) 320 + mr r8, r9 321 + isync 322 + 323 + /* Check the Reset Configuration Word to see whether flash needs 324 + * to be mapped at a low address or a high address. 325 + */ 326 + 327 + lwz r4, 0x0904(r8) 328 + andis. r4, r4, 0x0400 329 + li r4, 0 330 + beq boot_low 331 + lis r4, 0xff80 332 + boot_low: 333 + stw r4, 0x0020(r8) 334 + lis r7, 0x8000 335 + ori r7, r7, 0x0016 336 + 337 + mfspr r5, SPRN_HID0 338 + rlwinm r5, r5, 0, ~(HID0_DOZE | HID0_NAP) 339 + oris r5, r5, HID0_SLEEP@h 340 + mtspr SPRN_HID0, r5 341 + isync 342 + 343 + mfmsr r5 344 + oris r5, r5, MSR_POW@h 345 + 346 + /* Enable the flash mapping at the appropriate address. This 347 + * mapping will override the RAM mapping if booting low, so there's 348 + * no need to disable the latter. This must be done inside the same 349 + * cache line as setting MSR_POW, so that no instruction fetches 350 + * from RAM happen after the flash mapping is turned on. 351 + */ 352 + 353 + .align 5 354 + stw r7, 0x0024(r8) 355 + sync 356 + isync 357 + mtmsr r5 358 + isync 359 + 1: b 1b 360 + 361 + mpc83xx_deep_resume: 362 + lis r4, 1f@h 363 + ori r4, r4, 1f@l 364 + tophys(r4, r4) 365 + mtsrr0 r4 366 + 367 + mfmsr r4 368 + rlwinm r4, r4, 0, ~(MSR_IR | MSR_DR) 369 + mtsrr1 r4 370 + 371 + rfi 372 + 373 + 1: tlbia 374 + bl __inval_enable_L1 375 + 376 + lis r3, mpc83xx_sleep_save_area@h 377 + ori r3, r3, mpc83xx_sleep_save_area@l 378 + tophys(r3, r3) 379 + 380 + lwz r5, SS_MEMSAVE+0(r3) 381 + lwz r6, SS_MEMSAVE+4(r3) 382 + 383 + stw r5, 0(0) 384 + stw r6, 4(0) 385 + 386 + lwz r5, SS_HID+0(r3) 387 + lwz r6, SS_HID+4(r3) 388 + lwz r7, SS_HID+8(r3) 389 + 390 + mtspr SPRN_HID0, r5 391 + mtspr SPRN_HID1, r6 392 + mtspr SPRN_HID2, r7 393 + 394 + lwz r4, SS_IABR+0(r3) 395 + lwz r5, SS_IABR+4(r3) 396 + lwz r6, SS_IBCR(r3) 397 + lwz r7, SS_DABR+0(r3) 398 + lwz r8, SS_DABR+4(r3) 399 + lwz r9, SS_DBCR(r3) 400 + 401 + mtspr SPRN_IABR, r4 402 + mtspr SPRN_IABR2, r5 403 + mtspr SPRN_IBCR, r6 404 + mtspr SPRN_DABR, r7 405 + mtspr SPRN_DABR2, r8 406 + mtspr SPRN_DBCR, r9 407 + 408 + li r4, 0 409 + addi r6, r3, SS_SR-4 410 + 1: lwzu r5, 4(r6) 411 + mtsrin r5, r4 412 + addis r4, r4, 0x1000 413 + cmpwi r4, 0 414 + bne 1b 415 + 416 + lwz r4, SS_DBAT+0x00(r3) 417 + lwz r5, SS_DBAT+0x04(r3) 418 + lwz r6, SS_DBAT+0x08(r3) 419 + lwz r7, SS_DBAT+0x0c(r3) 420 + 421 + mtspr SPRN_DBAT0U, r4 422 + mtspr SPRN_DBAT0L, r5 423 + mtspr SPRN_DBAT1U, r6 424 + mtspr SPRN_DBAT1L, r7 425 + 426 + lwz r4, SS_DBAT+0x10(r3) 427 + lwz r5, SS_DBAT+0x14(r3) 428 + lwz r6, SS_DBAT+0x18(r3) 429 + lwz r7, SS_DBAT+0x1c(r3) 430 + 431 + mtspr SPRN_DBAT2U, r4 432 + mtspr SPRN_DBAT2L, r5 433 + mtspr SPRN_DBAT3U, r6 434 + mtspr SPRN_DBAT3L, r7 435 + 436 + lwz r4, SS_DBAT+0x20(r3) 437 + lwz r5, SS_DBAT+0x24(r3) 438 + lwz r6, SS_DBAT+0x28(r3) 439 + lwz r7, SS_DBAT+0x2c(r3) 440 + 441 + mtspr SPRN_DBAT4U, r4 442 + mtspr SPRN_DBAT4L, r5 443 + mtspr SPRN_DBAT5U, r6 444 + mtspr SPRN_DBAT5L, r7 445 + 446 + lwz r4, SS_DBAT+0x30(r3) 447 + lwz r5, SS_DBAT+0x34(r3) 448 + lwz r6, SS_DBAT+0x38(r3) 449 + lwz r7, SS_DBAT+0x3c(r3) 450 + 451 + mtspr SPRN_DBAT6U, r4 452 + mtspr SPRN_DBAT6L, r5 453 + mtspr SPRN_DBAT7U, r6 454 + mtspr SPRN_DBAT7L, r7 455 + 456 + lwz r4, SS_IBAT+0x00(r3) 457 + lwz r5, SS_IBAT+0x04(r3) 458 + lwz r6, SS_IBAT+0x08(r3) 459 + lwz r7, SS_IBAT+0x0c(r3) 460 + 461 + mtspr SPRN_IBAT0U, r4 462 + mtspr SPRN_IBAT0L, r5 463 + mtspr SPRN_IBAT1U, r6 464 + mtspr SPRN_IBAT1L, r7 465 + 466 + lwz r4, SS_IBAT+0x10(r3) 467 + lwz r5, SS_IBAT+0x14(r3) 468 + lwz r6, SS_IBAT+0x18(r3) 469 + lwz r7, SS_IBAT+0x1c(r3) 470 + 471 + mtspr SPRN_IBAT2U, r4 472 + mtspr SPRN_IBAT2L, r5 473 + mtspr SPRN_IBAT3U, r6 474 + mtspr SPRN_IBAT3L, r7 475 + 476 + lwz r4, SS_IBAT+0x20(r3) 477 + lwz r5, SS_IBAT+0x24(r3) 478 + lwz r6, SS_IBAT+0x28(r3) 479 + lwz r7, SS_IBAT+0x2c(r3) 480 + 481 + mtspr SPRN_IBAT4U, r4 482 + mtspr SPRN_IBAT4L, r5 483 + mtspr SPRN_IBAT5U, r6 484 + mtspr SPRN_IBAT5L, r7 485 + 486 + lwz r4, SS_IBAT+0x30(r3) 487 + lwz r5, SS_IBAT+0x34(r3) 488 + lwz r6, SS_IBAT+0x38(r3) 489 + lwz r7, SS_IBAT+0x3c(r3) 490 + 491 + mtspr SPRN_IBAT6U, r4 492 + mtspr SPRN_IBAT6L, r5 493 + mtspr SPRN_IBAT7U, r6 494 + mtspr SPRN_IBAT7L, r7 495 + 496 + lwz r4, SS_SPRG+0(r3) 497 + lwz r5, SS_SPRG+4(r3) 498 + lwz r6, SS_SPRG+8(r3) 499 + lwz r7, SS_SPRG+12(r3) 500 + lwz r8, SS_SDR1(r3) 501 + 502 + mtspr SPRN_SPRG0, r4 503 + mtspr SPRN_SPRG1, r5 504 + mtspr SPRN_SPRG2, r6 505 + mtspr SPRN_SPRG3, r7 506 + mtsdr1 r8 507 + 508 + lwz r4, SS_MSR(r3) 509 + lwz r5, SS_LR(r3) 510 + lwz r6, SS_CR(r3) 511 + lwz r1, SS_SP(r3) 512 + lwz r2, SS_R2(r3) 513 + 514 + mtsrr1 r4 515 + mtsrr0 r5 516 + mtcr r6 517 + 518 + li r4, 0 519 + mtspr SPRN_TBWL, r4 520 + 521 + lwz r4, SS_TB+0(r3) 522 + lwz r5, SS_TB+4(r3) 523 + 524 + mtspr SPRN_TBWU, r4 525 + mtspr SPRN_TBWL, r5 526 + 527 + lmw r12, SS_GPREG(r3) 528 + 529 + /* Kick decrementer */ 530 + li r0, 1 531 + mtdec r0 532 + 533 + rfi
+388
arch/powerpc/platforms/83xx/suspend.c
··· 1 + /* 2 + * MPC83xx suspend support 3 + * 4 + * Author: Scott Wood <scottwood@freescale.com> 5 + * 6 + * Copyright (c) 2006-2007 Freescale Semiconductor, Inc. 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms of the GNU General Public License version 2 as published 10 + * by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/init.h> 14 + #include <linux/pm.h> 15 + #include <linux/types.h> 16 + #include <linux/ioport.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/wait.h> 19 + #include <linux/kthread.h> 20 + #include <linux/freezer.h> 21 + #include <linux/suspend.h> 22 + #include <linux/fsl_devices.h> 23 + #include <linux/of_platform.h> 24 + 25 + #include <asm/reg.h> 26 + #include <asm/io.h> 27 + #include <asm/time.h> 28 + #include <asm/mpc6xx.h> 29 + 30 + #include <sysdev/fsl_soc.h> 31 + 32 + #define PMCCR1_NEXT_STATE 0x0C /* Next state for power management */ 33 + #define PMCCR1_NEXT_STATE_SHIFT 2 34 + #define PMCCR1_CURR_STATE 0x03 /* Current state for power management*/ 35 + #define IMMR_RCW_OFFSET 0x900 36 + #define RCW_PCI_HOST 0x80000000 37 + 38 + void mpc83xx_enter_deep_sleep(phys_addr_t immrbase); 39 + 40 + struct mpc83xx_pmc { 41 + u32 config; 42 + #define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */ 43 + #define PMCCR_SLPEN 1 /* System low power enable */ 44 + 45 + u32 event; 46 + u32 mask; 47 + /* All but PMCI are deep-sleep only */ 48 + #define PMCER_GPIO 0x100 49 + #define PMCER_PCI 0x080 50 + #define PMCER_USB 0x040 51 + #define PMCER_ETSEC1 0x020 52 + #define PMCER_ETSEC2 0x010 53 + #define PMCER_TIMER 0x008 54 + #define PMCER_INT1 0x004 55 + #define PMCER_INT2 0x002 56 + #define PMCER_PMCI 0x001 57 + #define PMCER_ALL 0x1FF 58 + 59 + /* deep-sleep only */ 60 + u32 config1; 61 + #define PMCCR1_USE_STATE 0x80000000 62 + #define PMCCR1_PME_EN 0x00000080 63 + #define PMCCR1_ASSERT_PME 0x00000040 64 + #define PMCCR1_POWER_OFF 0x00000020 65 + 66 + /* deep-sleep only */ 67 + u32 config2; 68 + }; 69 + 70 + struct mpc83xx_rcw { 71 + u32 rcwlr; 72 + u32 rcwhr; 73 + }; 74 + 75 + struct mpc83xx_clock { 76 + u32 spmr; 77 + u32 occr; 78 + u32 sccr; 79 + }; 80 + 81 + struct pmc_type { 82 + int has_deep_sleep; 83 + }; 84 + 85 + static struct of_device *pmc_dev; 86 + static int has_deep_sleep, deep_sleeping; 87 + static int pmc_irq; 88 + static struct mpc83xx_pmc __iomem *pmc_regs; 89 + static struct mpc83xx_clock __iomem *clock_regs; 90 + static int is_pci_agent, wake_from_pci; 91 + static phys_addr_t immrbase; 92 + static int pci_pm_state; 93 + static DECLARE_WAIT_QUEUE_HEAD(agent_wq); 94 + 95 + int fsl_deep_sleep(void) 96 + { 97 + return deep_sleeping; 98 + } 99 + 100 + static int mpc83xx_change_state(void) 101 + { 102 + u32 curr_state; 103 + u32 reg_cfg1 = in_be32(&pmc_regs->config1); 104 + 105 + if (is_pci_agent) { 106 + pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >> 107 + PMCCR1_NEXT_STATE_SHIFT; 108 + curr_state = reg_cfg1 & PMCCR1_CURR_STATE; 109 + 110 + if (curr_state != pci_pm_state) { 111 + reg_cfg1 &= ~PMCCR1_CURR_STATE; 112 + reg_cfg1 |= pci_pm_state; 113 + out_be32(&pmc_regs->config1, reg_cfg1); 114 + 115 + wake_up(&agent_wq); 116 + return 1; 117 + } 118 + } 119 + 120 + return 0; 121 + } 122 + 123 + static irqreturn_t pmc_irq_handler(int irq, void *dev_id) 124 + { 125 + u32 event = in_be32(&pmc_regs->event); 126 + int ret = IRQ_NONE; 127 + 128 + if (mpc83xx_change_state()) 129 + ret = IRQ_HANDLED; 130 + 131 + if (event) { 132 + out_be32(&pmc_regs->event, event); 133 + ret = IRQ_HANDLED; 134 + } 135 + 136 + return ret; 137 + } 138 + 139 + static int mpc83xx_suspend_enter(suspend_state_t state) 140 + { 141 + int ret = -EAGAIN; 142 + 143 + /* Don't go to sleep if there's a race where pci_pm_state changes 144 + * between the agent thread checking it and the PM code disabling 145 + * interrupts. 146 + */ 147 + if (wake_from_pci) { 148 + if (pci_pm_state != (deep_sleeping ? 3 : 2)) 149 + goto out; 150 + 151 + out_be32(&pmc_regs->config1, 152 + in_be32(&pmc_regs->config1) | PMCCR1_PME_EN); 153 + } 154 + 155 + /* Put the system into low-power mode and the RAM 156 + * into self-refresh mode once the core goes to 157 + * sleep. 158 + */ 159 + 160 + out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN); 161 + 162 + /* If it has deep sleep (i.e. it's an 831x or compatible), 163 + * disable power to the core upon entering sleep mode. This will 164 + * require going through the boot firmware upon a wakeup event. 165 + */ 166 + 167 + if (deep_sleeping) { 168 + out_be32(&pmc_regs->mask, PMCER_ALL); 169 + 170 + out_be32(&pmc_regs->config1, 171 + in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF); 172 + 173 + enable_kernel_fp(); 174 + 175 + mpc83xx_enter_deep_sleep(immrbase); 176 + 177 + out_be32(&pmc_regs->config1, 178 + in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF); 179 + 180 + out_be32(&pmc_regs->mask, PMCER_PMCI); 181 + } else { 182 + out_be32(&pmc_regs->mask, PMCER_PMCI); 183 + 184 + mpc6xx_enter_standby(); 185 + } 186 + 187 + ret = 0; 188 + 189 + out: 190 + out_be32(&pmc_regs->config1, 191 + in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN); 192 + 193 + return ret; 194 + } 195 + 196 + static void mpc83xx_suspend_finish(void) 197 + { 198 + deep_sleeping = 0; 199 + } 200 + 201 + static int mpc83xx_suspend_valid(suspend_state_t state) 202 + { 203 + return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM; 204 + } 205 + 206 + static int mpc83xx_suspend_begin(suspend_state_t state) 207 + { 208 + switch (state) { 209 + case PM_SUSPEND_STANDBY: 210 + deep_sleeping = 0; 211 + return 0; 212 + 213 + case PM_SUSPEND_MEM: 214 + if (has_deep_sleep) 215 + deep_sleeping = 1; 216 + 217 + return 0; 218 + 219 + default: 220 + return -EINVAL; 221 + } 222 + } 223 + 224 + static int agent_thread_fn(void *data) 225 + { 226 + while (1) { 227 + wait_event_interruptible(agent_wq, pci_pm_state >= 2); 228 + try_to_freeze(); 229 + 230 + if (signal_pending(current) || pci_pm_state < 2) 231 + continue; 232 + 233 + /* With a preemptible kernel (or SMP), this could race with 234 + * a userspace-driven suspend request. It's probably best 235 + * to avoid mixing the two with such a configuration (or 236 + * else fix it by adding a mutex to state_store that we can 237 + * synchronize with). 238 + */ 239 + 240 + wake_from_pci = 1; 241 + 242 + pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM : 243 + PM_SUSPEND_STANDBY); 244 + 245 + wake_from_pci = 0; 246 + } 247 + 248 + return 0; 249 + } 250 + 251 + static void mpc83xx_set_agent(void) 252 + { 253 + out_be32(&pmc_regs->config1, PMCCR1_USE_STATE); 254 + out_be32(&pmc_regs->mask, PMCER_PMCI); 255 + 256 + kthread_run(agent_thread_fn, NULL, "PCI power mgt"); 257 + } 258 + 259 + static int mpc83xx_is_pci_agent(void) 260 + { 261 + struct mpc83xx_rcw __iomem *rcw_regs; 262 + int ret; 263 + 264 + rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET, 265 + sizeof(struct mpc83xx_rcw)); 266 + 267 + if (!rcw_regs) 268 + return -ENOMEM; 269 + 270 + ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST); 271 + 272 + iounmap(rcw_regs); 273 + return ret; 274 + } 275 + 276 + static struct platform_suspend_ops mpc83xx_suspend_ops = { 277 + .valid = mpc83xx_suspend_valid, 278 + .begin = mpc83xx_suspend_begin, 279 + .enter = mpc83xx_suspend_enter, 280 + .finish = mpc83xx_suspend_finish, 281 + }; 282 + 283 + static int pmc_probe(struct of_device *ofdev, 284 + const struct of_device_id *match) 285 + { 286 + struct device_node *np = ofdev->node; 287 + struct resource res; 288 + struct pmc_type *type = match->data; 289 + int ret = 0; 290 + 291 + if (!of_device_is_available(np)) 292 + return -ENODEV; 293 + 294 + has_deep_sleep = type->has_deep_sleep; 295 + immrbase = get_immrbase(); 296 + pmc_dev = ofdev; 297 + 298 + is_pci_agent = mpc83xx_is_pci_agent(); 299 + if (is_pci_agent < 0) 300 + return is_pci_agent; 301 + 302 + ret = of_address_to_resource(np, 0, &res); 303 + if (ret) 304 + return -ENODEV; 305 + 306 + pmc_irq = irq_of_parse_and_map(np, 0); 307 + if (pmc_irq != NO_IRQ) { 308 + ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED, 309 + "pmc", ofdev); 310 + 311 + if (ret) 312 + return -EBUSY; 313 + } 314 + 315 + pmc_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc)); 316 + 317 + if (!pmc_regs) { 318 + ret = -ENOMEM; 319 + goto out; 320 + } 321 + 322 + ret = of_address_to_resource(np, 1, &res); 323 + if (ret) { 324 + ret = -ENODEV; 325 + goto out_pmc; 326 + } 327 + 328 + clock_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc)); 329 + 330 + if (!clock_regs) { 331 + ret = -ENOMEM; 332 + goto out_pmc; 333 + } 334 + 335 + if (is_pci_agent) 336 + mpc83xx_set_agent(); 337 + 338 + suspend_set_ops(&mpc83xx_suspend_ops); 339 + return 0; 340 + 341 + out_pmc: 342 + iounmap(pmc_regs); 343 + out: 344 + if (pmc_irq != NO_IRQ) 345 + free_irq(pmc_irq, ofdev); 346 + 347 + return ret; 348 + } 349 + 350 + static int pmc_remove(struct of_device *ofdev) 351 + { 352 + return -EPERM; 353 + }; 354 + 355 + static struct pmc_type pmc_types[] = { 356 + { 357 + .has_deep_sleep = 1, 358 + }, 359 + { 360 + .has_deep_sleep = 0, 361 + } 362 + }; 363 + 364 + static struct of_device_id pmc_match[] = { 365 + { 366 + .compatible = "fsl,mpc8313-pmc", 367 + .data = &pmc_types[0], 368 + }, 369 + { 370 + .compatible = "fsl,mpc8349-pmc", 371 + .data = &pmc_types[1], 372 + }, 373 + {} 374 + }; 375 + 376 + static struct of_platform_driver pmc_driver = { 377 + .name = "mpc83xx-pmc", 378 + .match_table = pmc_match, 379 + .probe = pmc_probe, 380 + .remove = pmc_remove 381 + }; 382 + 383 + static int pmc_init(void) 384 + { 385 + return of_register_platform_driver(&pmc_driver); 386 + } 387 + 388 + module_init(pmc_init);
+1
arch/powerpc/sysdev/fsl_soc.h
··· 10 10 extern u32 fsl_get_sys_freq(void); 11 11 12 12 struct spi_board_info; 13 + struct device_node; 13 14 14 15 extern int fsl_spi_init(struct spi_board_info *board_infos, 15 16 unsigned int num_board_infos,
+71
arch/powerpc/sysdev/ipic.c
··· 22 22 #include <linux/device.h> 23 23 #include <linux/bootmem.h> 24 24 #include <linux/spinlock.h> 25 + #include <linux/fsl_devices.h> 25 26 #include <asm/irq.h> 26 27 #include <asm/io.h> 27 28 #include <asm/prom.h> ··· 890 889 return irq_linear_revmap(primary_ipic->irqhost, irq); 891 890 } 892 891 892 + #ifdef CONFIG_PM 893 + static struct { 894 + u32 sicfr; 895 + u32 siprr[2]; 896 + u32 simsr[2]; 897 + u32 sicnr; 898 + u32 smprr[2]; 899 + u32 semsr; 900 + u32 secnr; 901 + u32 sermr; 902 + u32 sercr; 903 + } ipic_saved_state; 904 + 905 + static int ipic_suspend(struct sys_device *sdev, pm_message_t state) 906 + { 907 + struct ipic *ipic = primary_ipic; 908 + 909 + ipic_saved_state.sicfr = ipic_read(ipic->regs, IPIC_SICFR); 910 + ipic_saved_state.siprr[0] = ipic_read(ipic->regs, IPIC_SIPRR_A); 911 + ipic_saved_state.siprr[1] = ipic_read(ipic->regs, IPIC_SIPRR_D); 912 + ipic_saved_state.simsr[0] = ipic_read(ipic->regs, IPIC_SIMSR_H); 913 + ipic_saved_state.simsr[1] = ipic_read(ipic->regs, IPIC_SIMSR_L); 914 + ipic_saved_state.sicnr = ipic_read(ipic->regs, IPIC_SICNR); 915 + ipic_saved_state.smprr[0] = ipic_read(ipic->regs, IPIC_SMPRR_A); 916 + ipic_saved_state.smprr[1] = ipic_read(ipic->regs, IPIC_SMPRR_B); 917 + ipic_saved_state.semsr = ipic_read(ipic->regs, IPIC_SEMSR); 918 + ipic_saved_state.secnr = ipic_read(ipic->regs, IPIC_SECNR); 919 + ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR); 920 + ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR); 921 + 922 + if (fsl_deep_sleep()) { 923 + /* In deep sleep, make sure there can be no 924 + * pending interrupts, as this can cause 925 + * problems on 831x. 926 + */ 927 + ipic_write(ipic->regs, IPIC_SIMSR_H, 0); 928 + ipic_write(ipic->regs, IPIC_SIMSR_L, 0); 929 + ipic_write(ipic->regs, IPIC_SEMSR, 0); 930 + ipic_write(ipic->regs, IPIC_SERMR, 0); 931 + } 932 + 933 + return 0; 934 + } 935 + 936 + static int ipic_resume(struct sys_device *sdev) 937 + { 938 + struct ipic *ipic = primary_ipic; 939 + 940 + ipic_write(ipic->regs, IPIC_SICFR, ipic_saved_state.sicfr); 941 + ipic_write(ipic->regs, IPIC_SIPRR_A, ipic_saved_state.siprr[0]); 942 + ipic_write(ipic->regs, IPIC_SIPRR_D, ipic_saved_state.siprr[1]); 943 + ipic_write(ipic->regs, IPIC_SIMSR_H, ipic_saved_state.simsr[0]); 944 + ipic_write(ipic->regs, IPIC_SIMSR_L, ipic_saved_state.simsr[1]); 945 + ipic_write(ipic->regs, IPIC_SICNR, ipic_saved_state.sicnr); 946 + ipic_write(ipic->regs, IPIC_SMPRR_A, ipic_saved_state.smprr[0]); 947 + ipic_write(ipic->regs, IPIC_SMPRR_B, ipic_saved_state.smprr[1]); 948 + ipic_write(ipic->regs, IPIC_SEMSR, ipic_saved_state.semsr); 949 + ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr); 950 + ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr); 951 + ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr); 952 + 953 + return 0; 954 + } 955 + #else 956 + #define ipic_suspend NULL 957 + #define ipic_resume NULL 958 + #endif 959 + 893 960 static struct sysdev_class ipic_sysclass = { 894 961 .name = "ipic", 962 + .suspend = ipic_suspend, 963 + .resume = ipic_resume, 895 964 }; 896 965 897 966 static struct sys_device device_ipic = {
+4
include/asm-powerpc/reg.h
··· 155 155 #define CTRL_RUNLATCH 0x1 156 156 #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ 157 157 #define DABR_TRANSLATION (1UL << 2) 158 + #define SPRN_DABR2 0x13D /* e300 */ 158 159 #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ 159 160 #define DABRX_USER (1UL << 0) 160 161 #define DABRX_KERNEL (1UL << 1) 161 162 #define SPRN_DAR 0x013 /* Data Address Register */ 163 + #define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ 162 164 #define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ 163 165 #define DSISR_NOHPTE 0x40000000 /* no translation found */ 164 166 #define DSISR_PROTFAULT 0x08000000 /* protection fault */ ··· 266 264 #define HID1_PS (1<<16) /* 750FX PLL selection */ 267 265 #define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */ 268 266 #define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */ 267 + #define SPRN_IABR2 0x3FA /* 83xx */ 268 + #define SPRN_IBCR 0x135 /* 83xx Insn Breakpoint Control Reg */ 269 269 #define SPRN_HID4 0x3F4 /* 970 HID4 */ 270 270 #define SPRN_HID5 0x3F6 /* 970 HID5 */ 271 271 #define SPRN_HID6 0x3F9 /* BE HID 6 */
+6
include/linux/fsl_devices.h
··· 125 125 int(*voltage_set)(int slot, int vcc, int vpp); 126 126 }; 127 127 128 + /* Returns non-zero if the current suspend operation would 129 + * lead to a deep sleep (i.e. power removed from the core, 130 + * instead of just the clock). 131 + */ 132 + int fsl_deep_sleep(void); 133 + 128 134 #endif /* _FSL_DEVICE_H_ */