diff options
author | Wang Dongsheng <dongsheng.wang@freescale.com> | 2013-08-09 02:23:00 (GMT) |
---|---|---|
committer | Rivera Jose-B46482 <Jose.G.Rivera@freescale.com> | 2013-08-14 22:53:03 (GMT) |
commit | 6d66b7c97ddcd39218324dbd5dc80d31ce34f06c (patch) | |
tree | 5243c265d12544fb811834a95ab21cefafe2d11c /arch | |
parent | f6ec6d368cb9d8a3cb4e73a47ddb4438c1ff20db (diff) | |
download | linux-fsl-qoriq-6d66b7c97ddcd39218324dbd5dc80d31ce34f06c.tar.xz |
powerpc/85xx: add hardware automatically enter altivec idle state
Each core's AltiVec unit may be placed into a power savings mode
by turning off power to the unit. Core hardware will automatically
power down the AltiVec unit after no AltiVec instructions have
executed in N cycles. The AltiVec power-control is triggered by hardware.
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Change-Id: I613fba4492d3d65dcf903d13735bc9e45e5d443c
Reviewed-on: http://git.am.freescale.net:8181/3731
Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com>
Reviewed-by: Wood Scott-B07421 <scottwood@freescale.com>
Reviewed-by: Rivera Jose-B46482 <Jose.G.Rivera@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/reg_booke.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/common.c | 62 |
3 files changed, 68 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index f1b79a6..234a850 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -995,6 +995,8 @@ #define PVR_8560 0x80200000 #define PVR_VER_E500V1 0x8020 #define PVR_VER_E500V2 0x8021 +#define PVR_VER_E6500 0x8040 + /* * For the 8xx processors, all of them report the same PVR family for * the PowerPC core. The various versions of these processors must be diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 2bc7704..885ffdb 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -179,6 +179,7 @@ #define SPRN_L2CSR1 0x3FA /* L2 Data Cache Control and Status Register 1 */ #define SPRN_DCCR 0x3FA /* Data Cache Cacheability Register */ #define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */ +#define SPRN_PWRMGTCR0 0x3FB /* Power management control register 0 */ #define SPRN_SVR 0x3FF /* System Version Register */ /* @@ -225,6 +226,9 @@ #define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */ #define CCR1_TCS 0x00000080 /* Timer Clock Select */ +/* Bit definitions for PWRMGTCR0. */ +#define PWRMGTCR0_ALTIVEC_IDLE (1 << 22) /* Altivec idle enable */ + /* Bit definitions for the MCSR. */ #define MCSR_MCS 0x80000000 /* Machine Check Summary */ #define MCSR_IB 0x40000000 /* Instruction PLB Error */ diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index 1269a10..43025d0 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -7,10 +7,22 @@ */ #include <linux/of_platform.h> +#include <asm/time.h> + #include <sysdev/cpm2_pic.h> #include "mpc85xx.h" +#define MAX_BIT 64 + +#define ALTIVEC_COUNT_OFFSET 16 +#define ALTIVEC_IDLE_COUNT_MASK 0x003f0000 + +/* + * FIXME - We don't know the AltiVec application scenarios. + */ +#define ALTIVEC_IDLE_TIME 1000 /* 1ms */ + static struct of_device_id __initdata mpc85xx_common_ids[] = { { .type = "soc", }, { .compatible = "soc", }, @@ -82,3 +94,53 @@ void __init mpc85xx_cpm2_pic_init(void) irq_set_chained_handler(irq, cpm2_cascade); } #endif + +static unsigned int get_idle_ticks_bit(unsigned int us) +{ + unsigned int cycle; + + /* + * The time control by TB turn over bit, so we need + * to be divided by 2. + */ + cycle = (us / 2) * tb_ticks_per_usec; + + return ilog2(cycle) + 1; +} + +static void setup_altivec_idle(void *unused) +{ + u32 altivec_idle, pvr, bit; + + pvr = mfspr(SPRN_PVR); + + /* AltiVec idle feature only exists for E6500 */ + if (PVR_VER(pvr) != PVR_VER_E6500) + return; + + /* Fix erratum, e6500 rev1 not support altivec idle */ + if (PVR_REV(pvr) < 0x20) + return; + + /* Enable Altivec Idle */ + altivec_idle = mfspr(SPRN_PWRMGTCR0); + altivec_idle |= PWRMGTCR0_ALTIVEC_IDLE; + + /* Set Automatic AltiVec Idle Count */ + /* clear count */ + altivec_idle &= ~ALTIVEC_IDLE_COUNT_MASK; + + /* set count */ + bit = get_idle_ticks_bit(ALTIVEC_IDLE_TIME); + altivec_idle |= ((MAX_BIT - bit) << ALTIVEC_COUNT_OFFSET); + + mtspr(SPRN_PWRMGTCR0, altivec_idle); +} + +static int __init setup_idle_hw_governor(void) +{ + on_each_cpu(setup_altivec_idle, NULL, 1); + + return 0; +} +late_initcall(setup_idle_hw_governor); |