diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/85xx/deepsleep.c | 114 |
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); |