summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorTang Yuantian <Yuantian.Tang@freescale.com>2014-11-05 04:39:58 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:40:22 (GMT)
commit7b9ae59617188d40735351e2401202ae70d629cd (patch)
treeb49615697ee732ba9e403aff30cf14e0d7fc564a /arch
parent44d42fdd2cb81ec77299e629b30e3d4188b5f75b (diff)
downloadlinux-fsl-qoriq-7b9ae59617188d40735351e2401202ae70d629cd.tar.xz
deep sleep: save/restore LAW and MP register
LAW and MP information need to be backed up, or they will lost when deep sleep wake up. Previously, this is done by uboot. Now moved it to kernel because entry point to kernel when resume is pretty early in uboot. Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com> Change-Id: I4542ddc77bd8d3461cf2e8bf02abeb74fa89e741 Reviewed-on: http://git.am.freescale.net:8181/23147 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Chenhui Zhao <chenhui.zhao@freescale.com> Reviewed-by: Yang Li <LeoLi@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/85xx/deepsleep.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/85xx/deepsleep.c b/arch/powerpc/platforms/85xx/deepsleep.c
index 00e1505..29b253b 100644
--- a/arch/powerpc/platforms/85xx/deepsleep.c
+++ b/arch/powerpc/platforms/85xx/deepsleep.c
@@ -41,6 +41,15 @@
#define CSTTACR0 0xb00
#define CG1CR0 0x31c
+#define CCSR_LAW_BASE 0xC00
+#define DCFG_BRR 0xE4 /* boot release register */
+#define LCC_BSTRH 0x20 /* Boot space translation register high */
+#define LCC_BSTRL 0x24 /* Boot space translation register low */
+#define LCC_BSTAR 0x28 /* Boot space translation attribute register */
+#define RCPM_PCTBENR 0x1A0 /* Physical Core Timebase Enable Register */
+#define RCPM_BASE 0xE2000
+#define DCFG_BASE 0xE0000
+
/* 128 bytes buffer for restoring data broke by DDR training initialization */
#define DDR_BUF_SIZE 128
static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
@@ -48,6 +57,26 @@ static u8 ddr_buff[DDR_BUF_SIZE] __aligned(64);
static void *dcsr_base, *ccsr_base, *pld_base;
static int pld_flag;
+/* for law */
+struct fsl_law {
+ u32 lawbarh; /* LAWn base address high */
+ u32 lawbarl; /* LAWn base address low */
+ u32 lawar; /* LAWn attributes */
+ u32 reserved;
+};
+
+struct fsl_law *saved_law;
+static u32 num_laws;
+
+/* for nonboot cpu */
+struct fsl_bstr {
+ u32 bstrh;
+ u32 bstrl;
+ u32 bstar;
+ u32 cpu_mask;
+};
+static struct fsl_bstr saved_bstr;
+
int fsl_dp_iomap(void)
{
struct device_node *np;
@@ -95,6 +124,25 @@ int fsl_dp_iomap(void)
pld_base = of_iomap(np, 0);
of_node_put(np);
+ np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
+ if (!np) {
+ pr_err("%s: Can't find the node of \"law\"\n", __func__);
+ ret = -EINVAL;
+ goto pld_err;
+ }
+ ret = of_property_read_u32(np, "fsl,num-laws", &num_laws);
+ if (ret) {
+ ret = -EINVAL;
+ goto pld_err;
+ }
+
+ saved_law = kzalloc(sizeof(*saved_law) * num_laws, GFP_KERNEL);
+ if (!saved_law) {
+ ret = -ENOMEM;
+ goto pld_err;
+ }
+ of_node_put(np);
+
return 0;
pld_err:
@@ -148,6 +196,67 @@ static void fsl_dp_ddr_save(void *ccsr_base)
out_be32(ccsr_base + CCSR_SCFG_SPARECR3, ddr_buff_addr);
}
+static void fsl_dp_mp_save(void *ccsr)
+{
+ struct fsl_bstr *dst = &saved_bstr;
+
+ dst->bstrh = in_be32(ccsr + LCC_BSTRH);
+ dst->bstrl = in_be32(ccsr + LCC_BSTRL);
+ dst->bstar = in_be32(ccsr + LCC_BSTAR);
+ dst->cpu_mask = in_be32(ccsr + DCFG_BASE + DCFG_BRR);
+}
+
+static void fsl_dp_mp_restore(void *ccsr)
+{
+ struct fsl_bstr *src = &saved_bstr;
+
+ out_be32(ccsr + LCC_BSTRH, src->bstrh);
+ out_be32(ccsr + LCC_BSTRL, src->bstrl);
+ out_be32(ccsr + LCC_BSTAR, src->bstar);
+
+ /* release the nonboot cpus */
+ out_be32(ccsr + DCFG_BASE + DCFG_BRR, src->cpu_mask);
+
+ /* enable the time base */
+ out_be32(ccsr + RCPM_BASE + RCPM_PCTBENR, src->cpu_mask);
+ /* read back to sync write */
+ in_be32(ccsr + RCPM_BASE + RCPM_PCTBENR);
+}
+
+static void fsl_dp_law_save(void *ccsr)
+{
+ int i;
+ struct fsl_law *dst = saved_law;
+ struct fsl_law *src = (void *)(ccsr + CCSR_LAW_BASE);
+
+ for (i = 0; i < num_laws; i++) {
+ dst->lawbarh = in_be32(&src->lawbarh);
+ dst->lawbarl = in_be32(&src->lawbarl);
+ dst->lawar = in_be32(&src->lawar);
+ dst++;
+ src++;
+ }
+}
+
+static void fsl_dp_law_restore(void *ccsr)
+{
+ int i;
+ struct fsl_law *src = saved_law;
+ struct fsl_law *dst = (void *)(ccsr + CCSR_LAW_BASE);
+
+ for (i = 0; i < num_laws - 1; i++) {
+ out_be32(&dst->lawar, 0);
+ out_be32(&dst->lawbarl, src->lawbarl);
+ out_be32(&dst->lawbarh, src->lawbarh);
+ out_be32(&dst->lawar, src->lawar);
+
+ /* Read back so that we sync the writes */
+ in_be32(&dst->lawar);
+ src++;
+ dst++;
+ }
+}
+
static void fsl_dp_set_resume_pointer(void *ccsr_base)
{
u32 resume_addr;
@@ -171,6 +280,8 @@ int fsl_enter_epu_deepsleep(void)
fsl_dp_set_resume_pointer(ccsr_base);
+ fsl_dp_mp_save(ccsr_base);
+ fsl_dp_law_save(ccsr_base);
/* enable Warm Device Reset request. */
setbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);
@@ -193,6 +304,9 @@ int fsl_enter_epu_deepsleep(void)
fsl_dp_enter_low(ccsr_base, dcsr_base, pld_base, pld_flag);
+ fsl_dp_law_restore(ccsr_base);
+ fsl_dp_mp_restore(ccsr_base);
+
/* disable Warm Device Reset request */
clrbits32(ccsr_base + CCSR_SCFG_DPSLPCR, CCSR_SCFG_DPSLPCR_WDRR_EN);