^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* leon_pmc.c: LEON Power-down cpu_idle() handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2011 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/leon_amba.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/cpu_type.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <asm/leon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/processor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /* List of Systems that need fixup instructions around power-down instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static unsigned int pmc_leon_fixup_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) AEROFLEX_UT699,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) GAISLER_GR712RC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) LEON4_NEXTREME1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int pmc_leon_need_fixup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned int systemid = amba_system_id >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned int *id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) id = &pmc_leon_fixup_ids[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) while (*id != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (*id == systemid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * CPU idle callback function for systems that need some extra handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * See .../arch/sparc/kernel/process.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static void pmc_leon_idle_fixup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* Prepare an address to a non-cachable region. APB is always
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * none-cachable. One instruction is executed after the Sleep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * instruction, we make sure to read the bus and throw away the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * value by accessing a non-cachable area, also we make sure the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * MMU does not get a TLB miss here by using the MMU BYPASS ASI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) register unsigned int address = (unsigned int)leon3_irqctrl_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Interrupts need to be enabled to not hang the CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) raw_local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) __asm__ __volatile__ (
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) "wr %%g0, %%asr19\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) "lda [%0] %1, %%g0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) : "r"(address), "i"(ASI_LEON_BYPASS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * CPU idle callback function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * See .../arch/sparc/kernel/process.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static void pmc_leon_idle(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Interrupts need to be enabled to not hang the CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) raw_local_irq_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* For systems without power-down, this will be no-op */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) __asm__ __volatile__ ("wr %g0, %asr19\n\t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Install LEON Power Down function */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int __init leon_pmc_install(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (sparc_cpu_model == sparc_leon) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Assign power management IDLE handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (pmc_leon_need_fixup())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) sparc_idle = pmc_leon_idle_fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) sparc_idle = pmc_leon_idle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) printk(KERN_INFO "leon: power management initialized\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* This driver is not critical to the boot process, don't care
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * if initialized late.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) late_initcall(leon_pmc_install);