summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorWang Dongsheng <dongsheng.wang@freescale.com>2013-08-09 02:23:00 (GMT)
committerZhenhua Luo <zhenhua.luo@freescale.com>2013-08-26 07:47:31 (GMT)
commit4124c6d7744e1bc02ce5c55eb8ce7c009520f5b3 (patch)
treebde922c3142fa61ce8b65c8d717e2bf869df78ab /arch
parent6bfea4daf3ef082e1d401c4a8e3807a6e28bc68a (diff)
downloadlinux-fsl-qoriq-4124c6d7744e1bc02ce5c55eb8ce7c009520f5b3.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.h2
-rw-r--r--arch/powerpc/include/asm/reg_booke.h4
-rw-r--r--arch/powerpc/platforms/85xx/common.c62
3 files changed, 68 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index cad9faa..16fbb66 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);