From patchwork Wed Mar 26 08:08:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tang yuantian X-Patchwork-Id: 333800 X-Patchwork-Delegate: yorksun@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 780DD14008D for ; Wed, 26 Mar 2014 19:10:37 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D54D14B5EC; Wed, 26 Mar 2014 09:10:35 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id quJRLCjJNudY; Wed, 26 Mar 2014 09:10:35 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 790294B5F5; Wed, 26 Mar 2014 09:10:25 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3A2694B60C for ; Wed, 26 Mar 2014 09:10:21 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pKsmfwmLfDtG for ; Wed, 26 Mar 2014 09:10:18 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from ch1outboundpool.messaging.microsoft.com (ch1ehsobe002.messaging.microsoft.com [216.32.181.182]) by theia.denx.de (Postfix) with ESMTPS id 6D8C04B5F5 for ; Wed, 26 Mar 2014 09:10:08 +0100 (CET) Received: from mail210-ch1-R.bigfish.com (10.43.68.229) by CH1EHSOBE022.bigfish.com (10.43.70.79) with Microsoft SMTP Server id 14.1.225.22; Wed, 26 Mar 2014 08:10:06 +0000 Received: from mail210-ch1 (localhost [127.0.0.1]) by mail210-ch1-R.bigfish.com (Postfix) with ESMTP id 51E14320430 for ; Wed, 26 Mar 2014 08:10:06 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zze0eahzz1f42h2148h208ch1ee6h1de0h1fdah2073h2146h1202h1e76h2189h1d1ah1d2ah21bch1fc6hzz1de098h8275bh1de097hz2dh2a8h839he5bhf0ah1288h12a5h12a9h12bdh12e5h137ah139eh13b6h1441h1504h1537h162dh1631h1758h1898h18e1h1946h19b5h1ad9h1b0ah1b2fh2222h224fh1fb3h1d0ch1d2eh1d3fh1dfeh1dffh1e23h1fe8h1ff5h2218h2216h226dh22d0h24afh2327h2336h2438h2461h2487h24d7h2516h2545h255eh25cch25f6h2605h268bh1155h) Received: from mail210-ch1 (localhost.localdomain [127.0.0.1]) by mail210-ch1 (MessageSwitch) id 1395821403449640_32641; Wed, 26 Mar 2014 08:10:03 +0000 (UTC) Received: from CH1EHSMHS003.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.246]) by mail210-ch1.bigfish.com (Postfix) with ESMTP id 5F25F4E009A; Wed, 26 Mar 2014 08:10:03 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS003.bigfish.com (10.43.70.3) with Microsoft SMTP Server (TLS) id 14.16.227.3; Wed, 26 Mar 2014 08:10:03 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-003.039d.mgd.msft.net (10.84.1.16) with Microsoft SMTP Server (TLS) id 14.3.158.2; Wed, 26 Mar 2014 08:10:02 +0000 Received: from titan.am.freescale.net (b45104-01-010192208233.ap.freescale.net [10.192.208.233]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id s2Q89rHS006210; Wed, 26 Mar 2014 01:09:59 -0700 From: Tang Yuantian To: Date: Wed, 26 Mar 2014 16:08:06 +0800 Message-ID: <1395821286-10855-2-git-send-email-Yuantian.Tang@freescale.com> X-Mailer: git-send-email 1.8.5 In-Reply-To: <1395821286-10855-1-git-send-email-Yuantian.Tang@freescale.com> References: <1395821286-10855-1-git-send-email-Yuantian.Tang@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com X-FOPE-CONNECTOR: Id%0$Dn%*$RO%0$TLS%0$FQDN%$TlsDn% X-FOPE-CONNECTOR: Id%0$Dn%FREESCALE.MAIL.ONMICROSOFT.COM$RO%1$TLS%0$FQDN%$TlsDn% Cc: r64188@freescale.com, u-boot@lists.denx.de, Tang Yuantian Subject: [U-Boot] [PATCH 2/2 v3] mpc85xx/t104x: Add deep sleep framework support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de From: Tang Yuantian When T104x soc wakes up from deep sleep, control is passed to the primary core that starts executing uboot. After re-initialized some IP blocks, like DDRC, kernel will take responsibility to continue to restore environment it leaves before. Signed-off-by: Tang Yuantian --- v3: - fix out-of-tree compile warning v2: - added explaination for CONFIG_DEEP_SLEEP - fixed some issues README | 4 +++ arch/powerpc/cpu/mpc85xx/cpu_init.c | 7 ++++ arch/powerpc/cpu/mpc85xx/fdt.c | 22 ++++++++++++ arch/powerpc/cpu/mpc85xx/liodn.c | 27 ++++++++++---- arch/powerpc/cpu/mpc85xx/start.S | 9 +++++ arch/powerpc/include/asm/global_data.h | 2 ++ arch/powerpc/lib/board.c | 66 +++++++++++++++++++++++++++++++--- drivers/ddr/fsl/mpc85xx_ddr_gen3.c | 42 +++++++++++++++++++--- include/fdt_support.h | 4 +++ include/fsl_ddr_sdram.h | 4 +++ 10 files changed, 171 insertions(+), 16 deletions(-) diff --git a/README b/README index 216f0c7..25ffb90 100644 --- a/README +++ b/README @@ -427,6 +427,10 @@ The following options need to be configured: In this mode, a single differential clock is used to supply clocks to the sysclock, ddrclock and usbclock. + CONFIG_DEEP_SLEEP + Inidcates this SoC supports deep sleep feature. If deep sleep is + supported, core will start to execute uboot when wakes up. + - Generic CPU options: CONFIG_SYS_BIG_ENDIAN, CONFIG_SYS_LITTLE_ENDIAN diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index 81aeadd..1be29f8 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -279,6 +279,7 @@ void cpu_init_f (void) #ifdef CONFIG_MPC8548 ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR); uint svr = get_svr(); + gd = (gd_t *)(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET); /* * CPU2 errata workaround: A core hang possible while executing @@ -330,6 +331,12 @@ void cpu_init_f (void) in_be32(&gur->dcsrcr); #endif +#ifdef CONFIG_DEEP_SLEEP + /* disable the console if boot from deep sleep */ + if (in_be32(&gur->scrtsr[0]) & (1 << 3)) + gd->flags |= GD_FLG_SILENT | + GD_FLG_DEEP_SLEEP | GD_FLG_DISABLE_CONSOLE; +#endif } /* Implement a dummy function for those platforms w/o SERDES */ diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c index 33bc900..9351f63 100644 --- a/arch/powerpc/cpu/mpc85xx/fdt.c +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -35,6 +35,9 @@ void ft_fixup_cpu(void *blob, u64 memory_limit) u32 bootpg = determine_mp_bootpg(NULL); u32 id = get_my_id(); const char *enable_method; +#ifdef CONFIG_DEEP_SLEEP + ulong len; +#endif off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); while (off != -FDT_ERR_NOTFOUND) { @@ -108,6 +111,25 @@ void ft_fixup_cpu(void *blob, u64 memory_limit) printf("Failed to reserve memory for spin table: %s\n", fdt_strerror(off)); } + +#ifdef CONFIG_DEEP_SLEEP + /* + * reserve the memory space for deep sleep. + * This space will be re-used next time when boot from deep sleep. + * The space includes bd_t, gd_t, stack and uboot image. + * Reserve 1K for stack. + */ + len = sizeof(bd_t) + sizeof(gd_t) + (1 << 10); + /* round up to 4K */ + len = (len + (4096 - 1)) & ~(4096 - 1); + + off = fdt_add_mem_rsv(blob, gd->relocaddr - len, + len + ((ulong)&__bss_end - gd->relocaddr)); + if (off < 0) + printf("Failed to reserve memory for deep sleep: %s\n", + fdt_strerror(off)); + +#endif } #endif diff --git a/arch/powerpc/cpu/mpc85xx/liodn.c b/arch/powerpc/cpu/mpc85xx/liodn.c index 19e130e..a166765 100644 --- a/arch/powerpc/cpu/mpc85xx/liodn.c +++ b/arch/powerpc/cpu/mpc85xx/liodn.c @@ -14,6 +14,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + int get_dpaa_liodn(enum fsl_dpaa_dev dpaa_dev, u32 *liodns, int liodn_offset) { liodns[0] = liodn_bases[dpaa_dev].id[0] + liodn_offset; @@ -164,6 +166,8 @@ static void setup_rman_liodn_base(struct liodn_id_table *tbl, int size) void set_liodns(void) { + bool is_deepsleep = false; + /* setup general liodn offsets */ set_liodn(liodn_tbl, liodn_tbl_sz); @@ -179,16 +183,25 @@ void set_liodns(void) } /* setup FMAN block(s) liodn bases & offsets if we have one */ +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) + is_deepsleep = true; +#endif + #ifdef CONFIG_SYS_DPAA_FMAN - set_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz); - setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl, - fman1_liodn_tbl_sz); + if (!is_deepsleep) { + set_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz); + setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl, + fman1_liodn_tbl_sz); + } +#endif #if (CONFIG_SYS_NUM_FMAN == 2) - set_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz); - setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl, - fman2_liodn_tbl_sz); -#endif + if (!is_deepsleep) { + set_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz); + setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl, + fman2_liodn_tbl_sz); + } #endif /* setup PME liodn base */ setup_pme_liodn_base(); diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S index dbbd8e5..4af7a80 100644 --- a/arch/powerpc/cpu/mpc85xx/start.S +++ b/arch/powerpc/cpu/mpc85xx/start.S @@ -1669,6 +1669,15 @@ relocate_code: * Now relocate code */ +#ifdef CONFIG_DEEP_SLEEP + /* don't copy uboot again in warm reset case */ + mr r0, r3 + bl check_warmboot + cmpwi r3, 0 + bne 7f + mr r3, r0 +#endif + cmplw cr1,r3,r4 addi r0,r5,3 srwi. r0,r0,2 diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h index 8e59e8b..219e112 100644 --- a/arch/powerpc/include/asm/global_data.h +++ b/arch/powerpc/include/asm/global_data.h @@ -117,6 +117,8 @@ struct arch_global_data { #include #if 1 +/* Indicates the deep sleep case */ +#define GD_FLG_DEEP_SLEEP 0x10000 #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r2") #else /* We could use plain global data, but the resulting code is bigger */ #define XTRN_DECLARE_GLOBAL_DATA_PTR extern diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index f86c6f3..bf6ad6a 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -319,6 +319,13 @@ static int __fixup_cpu(void) int fixup_cpu(void) __attribute__((weak, alias("__fixup_cpu"))); +#ifdef CONFIG_DEEP_SLEEP +int check_warmboot(void) +{ + return !!(gd->flags & GD_FLG_DEEP_SLEEP); +} +#endif + /* * This is the first part of the initialization sequence that is * implemented in C, but still running from ROM. @@ -459,10 +466,18 @@ void board_init_f(ulong bootflag) /* * reserve memory for malloc() arena + * don't reserve it in deep sleep case */ - addr_sp = addr - TOTAL_MALLOC_LEN; - debug("Reserving %dk for malloc() at: %08lx\n", - TOTAL_MALLOC_LEN >> 10, addr_sp); +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) + addr_sp = addr; + else +#endif + { + addr_sp = addr - TOTAL_MALLOC_LEN; + debug("Reserving %dk for malloc() at: %08lx\n", + TOTAL_MALLOC_LEN >> 10, addr_sp); + } /* * (permanently) allocate a Board Info struct @@ -573,6 +588,14 @@ void board_init_r(gd_t *id, ulong dest_addr) { bd_t *bd; ulong malloc_start; +#ifdef CONFIG_DEEP_SLEEP + u32 start; + int i; + struct ccsr_scfg *scfg = (void *)CONFIG_SYS_MPC85xx_SCFG; + u64 *src, *dst; + typedef void (*func_t)(void); + func_t kernel_resume; +#endif #ifndef CONFIG_SYS_NO_FLASH ulong flash_size; @@ -583,6 +606,24 @@ void board_init_r(gd_t *id, ulong dest_addr) gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ +#ifdef CONFIG_DEEP_SLEEP + /* + * restore 128-byte memory space which corrupted + * by DDRC training. + */ + if (gd->flags & GD_FLG_DEEP_SLEEP) { + src = (u64 *)in_be32(&scfg->sparecr[2]); + dst = (u64 *)(0); + for (i = 0; i < 128/sizeof(u64); i++) { + asm("stw %1, 0(%0); stw %2, 4(%0)" : : "r" (dst), + "r" ((u32)((u64)(uintptr_t)src >> 32)), + "r" ((u32)src) : "memory"); + dst++; + src++; + } + } +#endif + /* The Malloc area is immediately below the monitor copy in DRAM */ malloc_start = dest_addr - TOTAL_MALLOC_LEN; @@ -621,7 +662,10 @@ void board_init_r(gd_t *id, ulong dest_addr) /* * Setup trap handlers */ - trap_init(dest_addr); +#ifdef CONFIG_DEEP_SLEEP + if ((gd->flags & GD_FLG_DEEP_SLEEP) == 0) +#endif + trap_init(dest_addr); #ifdef CONFIG_ADDR_MAP init_addr_map(); @@ -668,7 +712,10 @@ void board_init_r(gd_t *id, ulong dest_addr) asm("sync ; isync"); - mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN); +#ifdef CONFIG_DEEP_SLEEP + if ((gd->flags & GD_FLG_DEEP_SLEEP) == 0) +#endif + mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN); #if !defined(CONFIG_SYS_NO_FLASH) puts("Flash: "); @@ -725,6 +772,15 @@ void board_init_r(gd_t *id, ulong dest_addr) /* initialize higher level parts of CPU like time base and timers */ cpu_init_r(); +#ifdef CONFIG_DEEP_SLEEP + /* Jump to kernel in deep sleep case */ + if (gd->flags & GD_FLG_DEEP_SLEEP) { + start = in_be32(&scfg->sparecr[1]); + kernel_resume = (func_t)start; + kernel_resume(); + } +#endif + WATCHDOG_RESET(); #ifdef CONFIG_SPI diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c index c805086..57ade09 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c @@ -15,6 +15,7 @@ #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL #endif +DECLARE_GLOBAL_DATA_PTR; /* * regs has the to-be-set values for DDR controller registers @@ -119,7 +120,13 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0); out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1); out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2); - out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) + out_be32(&ddr->sdram_cfg_2, + regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT); + else +#endif + out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2); out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode); out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2); out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3); @@ -132,8 +139,16 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval); out_be32(&ddr->sdram_data_init, regs->ddr_data_init); out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl); - out_be32(&ddr->init_addr, regs->ddr_init_addr); - out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) { + out_be32(&ddr->init_addr, 0); + out_be32(&ddr->init_ext_addr, (1 << 31)); + } else +#endif + { + out_be32(&ddr->init_addr, regs->ddr_init_addr); + out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr); + } out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4); out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5); @@ -374,8 +389,22 @@ step2: udelay(500); asm volatile("sync;isync"); +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) { + /* enter self-refresh */ + setbits_be32(&ddr->sdram_cfg_2, (1 << 31)); + /* do board specific memory setup */ + board_mem_sleep_setup(); + } +#endif + /* Let the controller go */ - temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI; +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) + temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) | SDRAM_CFG_BI); + else +#endif + temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI); out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN); asm volatile("sync;isync"); @@ -526,4 +555,9 @@ step2: clrbits_be32(&ddr->sdram_cfg, 0x2); } #endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */ +#ifdef CONFIG_DEEP_SLEEP + if (gd->flags & GD_FLG_DEEP_SLEEP) + /* exit self-refresh */ + clrbits_be32(&ddr->sdram_cfg_2, (1 << 31)); +#endif } diff --git a/include/fdt_support.h b/include/fdt_support.h index 9871e2f..43986dc 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -12,6 +12,10 @@ #include +#ifdef CONFIG_DEEP_SLEEP +extern ulong __bss_end; +#endif + u32 fdt_getprop_u32_default(const void *fdt, const char *path, const char *prop, const u32 dflt); int fdt_chosen(void *fdt, int force); diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h index 2a36431..1629ea9 100644 --- a/include/fsl_ddr_sdram.h +++ b/include/fsl_ddr_sdram.h @@ -357,6 +357,10 @@ static int __board_need_mem_reset(void) int board_need_mem_reset(void) __attribute__((weak, alias("__board_need_mem_reset"))); +void __weak board_mem_sleep_setup(void) +{ +} + /* * The 85xx boards have a common prototype for fixed_sdram so put the * declaration here.