From 34a419b3fd88a2275ca681c99a5787b937e0f39d Mon Sep 17 00:00:00 2001 From: Yuichi Kusakabe Date: Thu, 18 May 2017 16:47:29 +0900 Subject: [PATCH 02/15] Add Hibernation arch code(Only R-CAR M2W) Signed-off-by: Yuichi Kusakabe --- arch/arm/Kconfig | 5 + arch/arm/include/asm/memory.h | 1 + arch/arm/include/asm/smp.h | 4 + arch/arm/include/asm/suspend.h | 3 + arch/arm/kernel/Makefile | 1 + arch/arm/kernel/hibernate.c | 139 ++++++++++++++ arch/arm/kernel/process.c | 7 +- arch/arm/kernel/sleep.S | 8 + arch/arm/kernel/smp.c | 6 + arch/arm/kernel/suspend.c | 64 ++++--- arch/arm/mach-shmobile/Kconfig | 65 +++++++ arch/arm/mach-shmobile/Makefile | 1 + arch/arm/mach-shmobile/common.h | 8 + arch/arm/mach-shmobile/crc32_word4.c | 299 +++++++++++++++++++++++++++++++ arch/arm/mach-shmobile/crc32_word4.h | 23 +++ arch/arm/mach-shmobile/headsmp.S | 2 - arch/arm/mach-shmobile/hibernation.c | 243 +++++++++++++++++++++++++ arch/arm/mach-shmobile/platsmp-apmu.c | 13 +- arch/arm/mach-shmobile/platsmp-rst.c | 3 +- arch/arm/mach-shmobile/pm-r8a7791.c | 27 +-- arch/arm/mach-shmobile/rcar-gen2.h | 39 ++++ arch/arm/mach-shmobile/setup-r8a7791.c | 10 +- arch/arm/mach-shmobile/setup-rcar-gen2.c | 14 +- arch/arm/mach-shmobile/smp-r8a7791.c | 8 +- arch/arm/mm/proc-v7.S | 31 ++-- 25 files changed, 947 insertions(+), 77 deletions(-) create mode 100644 arch/arm/kernel/hibernate.c create mode 100644 arch/arm/mach-shmobile/crc32_word4.c create mode 100644 arch/arm/mach-shmobile/crc32_word4.h create mode 100644 arch/arm/mach-shmobile/hibernation.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4dd95dd..eb76182 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2232,6 +2232,11 @@ config ARCH_SUSPEND_POSSIBLE config ARM_CPU_SUSPEND def_bool PM_SLEEP +config ARCH_HIBERNATION_POSSIBLE + bool + depends on MMU + default y if ARCH_SUSPEND_POSSIBLE + endmenu source "net/Kconfig" diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 48cb2b3..01158e7 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -241,6 +241,7 @@ static inline void *phys_to_virt(phys_addr_t x) #define __pa(x) __virt_to_phys((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) +#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) /* * Virtual <-> DMA view memory address translations diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index d3a22be..b718040 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -42,6 +42,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs); */ extern void smp_init_cpus(void); +/* + * Provide a function to call machine specific cpu initialization sequence + */ +extern void arch_smp_prepare_cpus(unsigned int max_cpus); /* * Provide a function to raise an IPI cross call on CPUs in callmap. diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index 1c0a551..709afa4 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -3,5 +3,8 @@ extern void cpu_resume(void); extern int cpu_suspend(unsigned long, int (*)(unsigned long)); +extern const void __nosave_begin, __nosave_end; +extern void cpu_resume_restore_nosave(u32, u32, u32); +extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); #endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5f3338e..70f439f 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o +obj-$(CONFIG_HIBERNATION) += hibernate.o obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c new file mode 100644 index 0000000..9380fe2 --- /dev/null +++ b/arch/arm/kernel/hibernate.c @@ -0,0 +1,139 @@ +/* + * Hibernation support specific for ARM + * + * Derived from work on ARM hibernation support by: + * + * Ubuntu project, hibernation support for mach-dove + * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu) + * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.) + * https://lkml.org/lkml/2010/6/18/4 + * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html + * https://patchwork.kernel.org/patch/96442/ + * + * Copyright (C) 2006 Rafael J. Wysocki + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include + +struct swsusp_archdata { + u32 nosave_backup_phys; + u32 nosave_begin_phys; + u32 nosave_end_phys; + /* Function pointer */ + u32 cpu_resume_restore_nosave; +}; + +static struct swsusp_archdata __archdata; + +void swsusp_arch_add_info(char *archdata) +{ + memcpy((void *)archdata, (void *)&__archdata, + sizeof(struct swsusp_archdata)); +} + +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = virt_to_pfn(&__nosave_begin); + unsigned long nosave_end_pfn = virt_to_pfn(&__nosave_end - 1); + + return (pfn >= nosave_begin_pfn) && (pfn <= nosave_end_pfn); +} + +void notrace save_processor_state(void) +{ + WARN_ON(num_online_cpus() != 1); + local_fiq_disable(); +} + +void notrace restore_processor_state(void) +{ + local_fiq_enable(); +} + +/* + * Snapshot kernel memory and reset the system. + * + * swsusp_save() is executed in the suspend finisher so that the CPU + * context pointer and memory are part of the saved image, which is + * required by the resume kernel image to restart execution from + * swsusp_arch_suspend(). + * + * soft_restart is not technically needed, but is used to get success + * returned from cpu_suspend. + * + * When soft reboot completes, the hibernation snapshot is written out. + */ +static int notrace arch_save_image(unsigned long unused) +{ + int ret; + ret = swsusp_save(); + if (ret == 0) + soft_restart(virt_to_phys(cpu_resume)); + return ret; +} + +/* + * Save the current CPU state before suspend / poweroff. + */ +int notrace swsusp_arch_suspend(void) +{ + return cpu_suspend(0, arch_save_image); +} + +/* + * Restore page contents for physical pages that were in use during loading + * hibernation image. Switch to idmap_pgd so the physical page tables + * are overwritten with the same contents. + */ +static void notrace arch_restore_image(void *unused) +{ + struct pbe *pbe; + + + cpu_switch_mm(idmap_pgd, &init_mm); + for (pbe = restore_pblist; pbe; pbe = pbe->next) + copy_page(pbe->orig_address, pbe->address); + + soft_restart(virt_to_phys(cpu_resume)); +} +static u64 resume_stack[PAGE_SIZE/2/sizeof(u64)] __nosavedata; + +/* + * Resume from the hibernation image. + * Due to the kernel heap / data restore, stack contents change underneath + * and that would make function calls impossible; switch to a temporary + * stack within the nosave region to avoid that problem. + */ +int swsusp_arch_resume(void) +{ + call_with_stack(arch_restore_image, 0, + resume_stack + ARRAY_SIZE(resume_stack)); + return 0; +} + +static int __init swsusp_arch_init(void) +{ + char *backup; + size_t len; + + len = &__nosave_end - &__nosave_begin; + backup = kmalloc(len, GFP_KERNEL); + if (backup) + memcpy(backup, &__nosave_begin, len); + + __archdata.nosave_backup_phys = virt_to_phys(backup); + __archdata.nosave_begin_phys = virt_to_phys(&__nosave_begin); + __archdata.nosave_end_phys = virt_to_phys(&__nosave_end); + __archdata.cpu_resume_restore_nosave = + virt_to_phys(cpu_resume_restore_nosave); + + return 0; +} +late_initcall(swsusp_arch_init); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 7927629..ae56f0b 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -98,7 +98,7 @@ void soft_restart(unsigned long addr) u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); /* Disable interrupts first */ - local_irq_disable(); + raw_local_irq_disable(); local_fiq_disable(); /* Disable the L2 if we're the last man standing. */ @@ -284,12 +284,17 @@ void __show_regs(struct pt_regs *regs) buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; buf[4] = '\0'; +#ifndef CONFIG_CPU_V7M printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", buf, interrupts_enabled(regs) ? "n" : "ff", fast_interrupts_enabled(regs) ? "n" : "ff", processor_modes[processor_mode(regs)], isa_modes[isa_mode(regs)], get_fs() == get_ds() ? "kernel" : "user"); +#else + printk("xPSR: %08lx\n", regs->ARM_cpsr); +#endif + #ifdef CONFIG_CPU_CP15 { unsigned int ctrl; diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 987dcf3..e4d092f 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -98,6 +98,14 @@ THUMB( mov sp, r2 ) THUMB( bx r3 ) ENDPROC(cpu_resume) + .align +ENTRY(cpu_resume_restore_nosave) +1: ldmia r0!, {r3-r10} + stmia r1!, {r3-r10} + cmp r1, r2 + bne 1b + b cpu_resume + sleep_save_sp: .rept CONFIG_NR_CPUS .long 0 @ preserve stack phys ptr here diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 5919eb4..c9a2991 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -125,6 +125,12 @@ void __init smp_init_cpus(void) smp_ops.smp_init_cpus(); } +void arch_smp_prepare_cpus(unsigned int max_cpus) +{ + if (smp_ops.smp_prepare_cpus) + smp_ops.smp_prepare_cpus(max_cpus); +} + int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) { if (smp_ops.smp_boot_secondary) diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index c59c97e..38a5067 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -10,6 +10,42 @@ extern int __cpu_suspend(unsigned long, int (*)(unsigned long)); extern void cpu_resume_mmu(void); +#ifdef CONFIG_MMU +/* + * Hide the first two arguments to __cpu_suspend - these are an implementation + * detail which platform code shouldn't have to know about. + */ +int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) +{ + struct mm_struct *mm = current->active_mm; + int ret; + + if (!idmap_pgd) + return -EINVAL; + + /* + * Provide a temporary page table with an identity mapping for + * the MMU-enable code, required for resuming. On successful + * resume (indicated by a zero return code), we need to switch + * back to the correct page tables. + */ + ret = __cpu_suspend(arg, fn); + if (ret == 0) { + cpu_switch_mm(mm->pgd, mm); + local_flush_bp_all(); + local_flush_tlb_all(); + } + + return ret; +} +#else +int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) +{ + return __cpu_suspend(arg, fn); +} +#define idmap_pgd NULL +#endif + /* * This is called by __cpu_suspend() to save the state, and do whatever * flushing is required to ensure that when the CPU goes to sleep we have @@ -46,31 +82,3 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) outer_clean_range(virt_to_phys(save_ptr), virt_to_phys(save_ptr) + sizeof(*save_ptr)); } - -/* - * Hide the first two arguments to __cpu_suspend - these are an implementation - * detail which platform code shouldn't have to know about. - */ -int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) -{ - struct mm_struct *mm = current->active_mm; - int ret; - - if (!idmap_pgd) - return -EINVAL; - - /* - * Provide a temporary page table with an identity mapping for - * the MMU-enable code, required for resuming. On successful - * resume (indicated by a zero return code), we need to switch - * back to the correct page tables. - */ - ret = __cpu_suspend(arg, fn); - if (ret == 0) { - cpu_switch_mm(mm->pgd, mm); - local_flush_bp_all(); - local_flush_tlb_all(); - } - - return ret; -} diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 7c15245..73371de 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -64,6 +64,25 @@ config MACH_KOELSCH select MICREL_PHY if SH_ETH select SND_SOC_AK4642 if SND_SIMPLE_CARD +config MACH_KOELSCH_FTEN + bool "FTEN spf development environment" + depends on MACH_KOELSCH + +config MACH_FTEN + bool + +config MACH_FTEN_DT + bool + +config MACH_FTEN_M2W + bool "FTEN R-Car M2W board" + depends on ARCH_R8A7791 + select MACH_FTEN + select MACH_FTEN_DT + select HAVE_IDE + select FIQ + select SND_SOC_DIRANA3 if SND_SIMPLE_CARD + config MACH_LAGER bool "Lager board" depends on ARCH_R8A7790 @@ -76,6 +95,15 @@ config MACH_GOSE select MICREL_PHY if SH_ETH select SND_SOC_AK4642 if SND_SIMPLE_CARD +config MACH_FTEN_M2N + bool "FTEN R-Car M2N board" + depends on ARCH_R8A7793 + select MACH_FTEN + select MACH_FTEN_DT + select HAVE_IDE + select FIQ + select SND_SOC_DIRANA3 if SND_SIMPLE_CARD + config MACH_ALT bool "Alt board" depends on ARCH_R8A7794 @@ -287,6 +315,19 @@ config MACH_KOELSCH select USE_OF select MICREL_PHY if SH_ETH +config MACH_FTEN + bool "FTEN strawberry board" + depends on ARCH_R8A7791 + select USE_OF + select HAVE_IDE + +config MACH_FTEN_DT + bool "FTEN strawberry board - Device Tree Implementation" + depends on ARCH_R8A7791 + select USE_OF + select HAVE_IDE + select SND_SOC_DIRANA3 if SND_SIMPLE_CARD + config MACH_KZM9G bool "KZM-A9-GT board" depends on ARCH_SH73A0 @@ -360,4 +401,28 @@ config EM_TIMER_STI endmenu +if HIBERNATION + +menu "Hibernation area parameters" + +config SWSUSP_AREA + hex "RAM hibernation area address" + default "0x44000000" + depends on HIBERNATION + ---help--- + RAM hibernation area address, this is required for CRC + calculation of final compressed hibernation image + +config SWSUSP_AREA_SIZE + hex "RAM hibernation area size" + default "0x4000000" + depends on HIBERNATION + ---help--- + RAM hibernation area size, this is required for CRC + calculation of final compressed hibernation image + +endmenu + +endif + endif diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 43b4025..71cfcfa 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -55,6 +55,7 @@ smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o # PM objects obj-$(CONFIG_SUSPEND) += suspend.o +obj-$(CONFIG_HIBERNATION) += hibernation.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o pm-rmobile.o diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h index 95a77a0..37c7f87 100644 --- a/arch/arm/mach-shmobile/common.h +++ b/arch/arm/mach-shmobile/common.h @@ -25,6 +25,7 @@ struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); extern struct platform_suspend_ops shmobile_suspend_ops; +extern const struct platform_hibernation_ops shmobile_hibernation_ops; struct cpuidle_driver; extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv); extern void shmobile_smp_apmu_enter_cpuidle(void); @@ -37,6 +38,12 @@ static inline int shmobile_suspend_init(void) { return 0; } static inline void shmobile_smp_apmu_suspend_init(void) { } #endif +#ifdef CONFIG_HIBERNATION +int shmobile_hibernation_init(void); +#else +static inline int shmobile_hibernation_init(void) { return 0; } +#endif + #ifdef CONFIG_CPU_IDLE int shmobile_cpuidle_init(void); #else @@ -59,6 +66,7 @@ extern unsigned int l2actlr_value; static inline void __init shmobile_init_late(void) { shmobile_suspend_init(); + shmobile_hibernation_init(); shmobile_cpuidle_init(); shmobile_cpufreq_init(); } diff --git a/arch/arm/mach-shmobile/crc32_word4.c b/arch/arm/mach-shmobile/crc32_word4.c new file mode 100644 index 0000000..8aaefc6 --- /dev/null +++ b/arch/arm/mach-shmobile/crc32_word4.c @@ -0,0 +1,299 @@ +/************************************************************************* + * crc32_word4.c: rapid CRC32 + * Coptright (C) FUJITSUTEN Limited, 2015 All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *************************************************************************/ +#ifdef OWNTEST +#include +#include +#include +#include +typedef unsigned int u_int32_t; +#else +#endif + +#include "crc32_word4.h" + +#define CRC_INIT_VALUE (-1) +#define CRC_FIX(_crc32) (~(_crc32)) + +/* #define HWDPLS_ENABLE */ +#define __HWDTPLS_OUT() +#define MEASURE(msg) + +/**** calc_crc32.c *****/ + +/* + * CRC32は、ISO 3309 で規程され + * そのサンプルは + * RFC 2083 :PNG(Poratble Network Graphics + * で公になっています。本プログラムは、RFC2083 で掲示された + * CRC32を独自に最適化したプログラムです。 + */ +const static u_int32_t CRC_Table[256] = { + 0x00000000 , 0x77073096 , 0xee0e612c , 0x990951ba , 0x076dc419 , 0x706af48f , 0xe963a535 , 0x9e6495a3 , + 0x0edb8832 , 0x79dcb8a4 , 0xe0d5e91e , 0x97d2d988 , 0x09b64c2b , 0x7eb17cbd , 0xe7b82d07 , 0x90bf1d91 , + 0x1db71064 , 0x6ab020f2 , 0xf3b97148 , 0x84be41de , 0x1adad47d , 0x6ddde4eb , 0xf4d4b551 , 0x83d385c7 , + 0x136c9856 , 0x646ba8c0 , 0xfd62f97a , 0x8a65c9ec , 0x14015c4f , 0x63066cd9 , 0xfa0f3d63 , 0x8d080df5 , + 0x3b6e20c8 , 0x4c69105e , 0xd56041e4 , 0xa2677172 , 0x3c03e4d1 , 0x4b04d447 , 0xd20d85fd , 0xa50ab56b , + 0x35b5a8fa , 0x42b2986c , 0xdbbbc9d6 , 0xacbcf940 , 0x32d86ce3 , 0x45df5c75 , 0xdcd60dcf , 0xabd13d59 , + 0x26d930ac , 0x51de003a , 0xc8d75180 , 0xbfd06116 , 0x21b4f4b5 , 0x56b3c423 , 0xcfba9599 , 0xb8bda50f , + 0x2802b89e , 0x5f058808 , 0xc60cd9b2 , 0xb10be924 , 0x2f6f7c87 , 0x58684c11 , 0xc1611dab , 0xb6662d3d , + 0x76dc4190 , 0x01db7106 , 0x98d220bc , 0xefd5102a , 0x71b18589 , 0x06b6b51f , 0x9fbfe4a5 , 0xe8b8d433 , + 0x7807c9a2 , 0x0f00f934 , 0x9609a88e , 0xe10e9818 , 0x7f6a0dbb , 0x086d3d2d , 0x91646c97 , 0xe6635c01 , + 0x6b6b51f4 , 0x1c6c6162 , 0x856530d8 , 0xf262004e , 0x6c0695ed , 0x1b01a57b , 0x8208f4c1 , 0xf50fc457 , + 0x65b0d9c6 , 0x12b7e950 , 0x8bbeb8ea , 0xfcb9887c , 0x62dd1ddf , 0x15da2d49 , 0x8cd37cf3 , 0xfbd44c65 , + 0x4db26158 , 0x3ab551ce , 0xa3bc0074 , 0xd4bb30e2 , 0x4adfa541 , 0x3dd895d7 , 0xa4d1c46d , 0xd3d6f4fb , + 0x4369e96a , 0x346ed9fc , 0xad678846 , 0xda60b8d0 , 0x44042d73 , 0x33031de5 , 0xaa0a4c5f , 0xdd0d7cc9 , + 0x5005713c , 0x270241aa , 0xbe0b1010 , 0xc90c2086 , 0x5768b525 , 0x206f85b3 , 0xb966d409 , 0xce61e49f , + 0x5edef90e , 0x29d9c998 , 0xb0d09822 , 0xc7d7a8b4 , 0x59b33d17 , 0x2eb40d81 , 0xb7bd5c3b , 0xc0ba6cad , + 0xedb88320 , 0x9abfb3b6 , 0x03b6e20c , 0x74b1d29a , 0xead54739 , 0x9dd277af , 0x04db2615 , 0x73dc1683 , + 0xe3630b12 , 0x94643b84 , 0x0d6d6a3e , 0x7a6a5aa8 , 0xe40ecf0b , 0x9309ff9d , 0x0a00ae27 , 0x7d079eb1 , + 0xf00f9344 , 0x8708a3d2 , 0x1e01f268 , 0x6906c2fe , 0xf762575d , 0x806567cb , 0x196c3671 , 0x6e6b06e7 , + 0xfed41b76 , 0x89d32be0 , 0x10da7a5a , 0x67dd4acc , 0xf9b9df6f , 0x8ebeeff9 , 0x17b7be43 , 0x60b08ed5 , + 0xd6d6a3e8 , 0xa1d1937e , 0x38d8c2c4 , 0x4fdff252 , 0xd1bb67f1 , 0xa6bc5767 , 0x3fb506dd , 0x48b2364b , + 0xd80d2bda , 0xaf0a1b4c , 0x36034af6 , 0x41047a60 , 0xdf60efc3 , 0xa867df55 , 0x316e8eef , 0x4669be79 , + 0xcb61b38c , 0xbc66831a , 0x256fd2a0 , 0x5268e236 , 0xcc0c7795 , 0xbb0b4703 , 0x220216b9 , 0x5505262f , + 0xc5ba3bbe , 0xb2bd0b28 , 0x2bb45a92 , 0x5cb36a04 , 0xc2d7ffa7 , 0xb5d0cf31 , 0x2cd99e8b , 0x5bdeae1d , + 0x9b64c2b0 , 0xec63f226 , 0x756aa39c , 0x026d930a , 0x9c0906a9 , 0xeb0e363f , 0x72076785 , 0x05005713 , + 0x95bf4a82 , 0xe2b87a14 , 0x7bb12bae , 0x0cb61b38 , 0x92d28e9b , 0xe5d5be0d , 0x7cdcefb7 , 0x0bdbdf21 , + 0x86d3d2d4 , 0xf1d4e242 , 0x68ddb3f8 , 0x1fda836e , 0x81be16cd , 0xf6b9265b , 0x6fb077e1 , 0x18b74777 , + 0x88085ae6 , 0xff0f6a70 , 0x66063bca , 0x11010b5c , 0x8f659eff , 0xf862ae69 , 0x616bffd3 , 0x166ccf45 , + 0xa00ae278 , 0xd70dd2ee , 0x4e048354 , 0x3903b3c2 , 0xa7672661 , 0xd06016f7 , 0x4969474d , 0x3e6e77db , + 0xaed16a4a , 0xd9d65adc , 0x40df0b66 , 0x37d83bf0 , 0xa9bcae53 , 0xdebb9ec5 , 0x47b2cf7f , 0x30b5ffe9 , + 0xbdbdf21c , 0xcabac28a , 0x53b39330 , 0x24b4a3a6 , 0xbad03605 , 0xcdd70693 , 0x54de5729 , 0x23d967bf , + 0xb3667a2e , 0xc4614ab8 , 0x5d681b02 , 0x2a6f2b94 , 0xb40bbe37 , 0xc30c8ea1 , 0x5a05df1b , 0x2d02ef8d , +}; + +/*** + * CRC Table creater. + * +void make_crc_table(void) { + u_int32_t c; + u_int32_t n, k; + for (n = 0; n < 256; n++) + { + c = (u_int32_t) n; + for (k = 0; k < 8; k++) + { + if (c & 1) + c = 0xedb88320L ^ (c >> 1); + else + c = c >> 1; + } + CRC_Table[n] = c; + } +} +***/ +#define NEXT_PTR (4) + +static __inline__ +u_int32_t _update_crc(u_int32_t crc, unsigned char *buf, size_t len) +{ + u_int32_t c = crc; + size_t n; + for (n = 0; n < len; n++) + c = CRC_Table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + return c; +} +/********************************************************************* + * update_crc4x4()() + * calc_crc32() をベースに、4 ワード毎に個別に CRC32 を計算する方法 + * + * +0 +1 +2 +3 + * +0x00 AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + * +0x04 EEEEEEEE FFFFFFFF 00000000 11111111 + * : : : : + * CRC32 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx + * + *********************************************************************/ + +static __inline__ +void update_crc4x4(u_int32_t crc[4], unsigned char *buf) +{ + u_int32_t c1, c2, c3, c4; + u_int32_t *p = (void *)buf; + + c1 = crc[0] ^ p[0]; + c2 = crc[1] ^ p[1]; + c3 = crc[2] ^ p[2]; + c4 = crc[3] ^ p[3]; + + c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8); + c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8); + c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8); + c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8); + + c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8); + c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8); + c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8); + c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8); + + c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8); + c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8); + c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8); + c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8); + + c1 = CRC_Table[c1 & 0xff] ^ (c1 >> 8); + c2 = CRC_Table[c2 & 0xff] ^ (c2 >> 8); + c3 = CRC_Table[c3 & 0xff] ^ (c3 >> 8); + c4 = CRC_Table[c4 & 0xff] ^ (c4 >> 8); + + crc[0] = c1; + crc[1] = c2; + crc[2] = c3; + crc[3] = c4; +} + + +void calc_crc32x4(unsigned char *buf, size_t len, CRC32_WORD4_t *result) +{ + unsigned int crc_tmp[4] = {CRC_INIT_VALUE, CRC_INIT_VALUE, CRC_INIT_VALUE, CRC_INIT_VALUE}; + u_int32_t i; + int res; + u_int32_t n4; + int xlen = len; +#ifdef HWDPLS_ENABLE + unsigned long plstout = 60; + unsigned long plsstart = 0; + if ((unsigned long)CONFIG_SYS_HZ > 100000) + plstout *= (unsigned long)CONFIG_SYS_HZ / 1000; + else + plstout = DIV_ROUND_UP(plstout * (unsigned long)CONFIG_SYS_HZ, 1000); +#endif + + /** + * 4バイト境界に合わない開始アドレスの場合 + * 境界までのCRCを crc_tmp[0] に求める。 + */ + if ((unsigned long)buf & 3) { + crc_tmp[0] = _update_crc(crc_tmp[0], buf, (unsigned long)buf & 3); + buf = (unsigned char *)((unsigned long)buf & ~3); + xlen -= (unsigned long)buf & 3; + } + + n4 = xlen/(NEXT_PTR*4); + /** + * 4バイト境界に合わない開始アドレスの場合 + * 境界までのCRCを crc_tmp[0] に求める。 + */ +#ifdef HWDPLS_ENABLE + reset_timer(); + plsstart = get_timer(0); +#endif + for (i = 0; i < n4; i++) { + update_crc4x4(crc_tmp, buf); + buf += NEXT_PTR * 4; +#ifdef HWDPLS_ENABLE + /** + * WDを考慮 + */ + if (__builtin_expect((int)((i & 0x1f) == 0), 0)) { + if ((get_timer(plsstart)) > plstout) { + __HWDTPLS_OUT(); + MEASURE("crc plsout") + plsstart += plstout; + } + } +#endif /*HWPLS_ENABLE*/ + } + + res = xlen % (NEXT_PTR * 4); + if (res > 0) + crc_tmp[3] = _update_crc(crc_tmp[3], buf, res); + + result->crc_w[0] = CRC_FIX(crc_tmp[0]); + result->crc_w[1] = CRC_FIX(crc_tmp[1]); + result->crc_w[2] = CRC_FIX(crc_tmp[2]); + result->crc_w[3] = CRC_FIX(crc_tmp[3]); + + MEASURE("calc_crc32x4 finish") +} + +#if defined(OWNTEST) +#define BUFSIZE (2 * 1024 * 1024) +#include +#include + +int main() +{ + unsigned char *buf, *buf2; + struct timeval start, end; + unsigned long long diff; + int i; + + CRC32_WORD4_t result = { .crc_w = {0, 0, 0, 0 } }; + CRC32_WORD4_t result2 = { .crc_w = {0, 0, 0, 0 } }; + + buf = malloc(BUFSIZE); + if (!buf) { + perror("malloc"); + return 1; + } + printf("Generate %dMB random data..\n", BUFSIZE / 1024 / 1024); + srand(0); + for (i = 0; i < BUFSIZE / 4; i++) + ((int *)buf)[i] = rand(); + + /* Memory dup */ + buf2 = memalign(NEXT_PTR, BUFSIZE); + if (!buf2) { + perror("malloc"); + return 1; + } + memcpy(buf2, buf, BUFSIZE); + + + gettimeofday(&start, NULL); + calc_crc32x4(buf, BUFSIZE, &result); + gettimeofday(&end, NULL); + + diff = (end.tv_sec - start.tv_sec) * 1000000; + diff += end.tv_usec - start.tv_usec; + + printf("time=%lluus\n", diff); + printf(" result.word[0] = %x\n", result.crc_w[0]); + printf(" result.word[1] = %x\n", result.crc_w[1]); + printf(" result.word[2] = %x\n", result.crc_w[2]); + printf(" result.word[3] = %x\n", result.crc_w[3]); + + /* Broken test */ +#if 0 /* Destory test */ + buf[rand() % BUFSIZE] ^= 1 << (rand()%7); +#endif + for (i = 0; i < BUFSIZE; i++) { + if (buf[i] != buf2[i]) + printf("buf[%d] %02x : %02x\n", i, buf[i], buf2[i]); + } + + gettimeofday(&start, NULL); + calc_crc32x4(buf, BUFSIZE, &result2); + gettimeofday(&end, NULL); + + diff = (end.tv_sec - start.tv_sec) * 1000000; + diff += end.tv_usec - start.tv_usec; + + printf("time=%lluus\n", diff); + printf(" result.word[0] = %x:%s\n", result2.crc_w[0] , + result.crc_w[0] == result2.crc_w[0] ? "OK" : "NG"); + printf(" result.word[1] = %x:%s\n", result2.crc_w[1] , + result.crc_w[1] == result2.crc_w[1] ? "OK" : "NG"); + printf(" result.word[2] = %x:%s\n", result2.crc_w[2] , + result.crc_w[2] == result2.crc_w[2] ? "OK" : "NG"); + printf(" result.word[3] = %x:%s\n", result2.crc_w[3] , + result.crc_w[3] == result2.crc_w[3] ? "OK" : "NG"); + return 0; +} +#endif /* TEST */ diff --git a/arch/arm/mach-shmobile/crc32_word4.h b/arch/arm/mach-shmobile/crc32_word4.h new file mode 100644 index 0000000..6c04878 --- /dev/null +++ b/arch/arm/mach-shmobile/crc32_word4.h @@ -0,0 +1,23 @@ +/************************************************************************* + * Coptright (C) FUJITSUTEN Limited, 2012 All Rights Reserved. + * + *************************************************************************/ +#ifndef __CRC32_WORD4_H__ +#define __CRC32_WORD4_H__ + +typedef struct { + unsigned int crc_w[4]; +} CRC32_WORD4_t; + +void calc_crc32x4(unsigned char *buf, size_t len, CRC32_WORD4_t *result); + +typedef struct { + unsigned int size; + CRC32_WORD4_t chksum; + unsigned int dummy[3]; +} CRC32_WORD4_TICKET_t; + +#define IS_CRC_WORD4_OK(_res1, _res2) (!memcmp(_res1, _res2, sizeof(CRC32_WORD4_t))) +#define IS_CRC_WORD4_ZERO(_w4) (((_w4)->crc_w[0] == 0) && ((_w4)->crc_w[1] == 0) && ((_w4)->crc_w[2] == 0) && ((_w4)->crc_w[3] == 0)) +#define IS_CRC_WORD4_ALL_F(_w4) (((_w4)->crc_w[0] == 0xffffffff) && ((_w4)->crc_w[1] == 0xffffffff) && ((_w4)->crc_w[2] == 0xffffffff) && ((_w4)->crc_w[3] == 0xffffffff)) +#endif diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S index debf271..f99f8b2 100644 --- a/arch/arm/mach-shmobile/headsmp.S +++ b/arch/arm/mach-shmobile/headsmp.S @@ -16,8 +16,6 @@ #include #include - __CPUINIT - #ifdef CONFIG_SMP ENTRY(shmobile_invalidate_start) bl v7_invalidate_l1 diff --git a/arch/arm/mach-shmobile/hibernation.c b/arch/arm/mach-shmobile/hibernation.c new file mode 100644 index 0000000..94fa78b --- /dev/null +++ b/arch/arm/mach-shmobile/hibernation.c @@ -0,0 +1,243 @@ +/* + * Suspend-to-RAM support code for SH-Mobile ARM + * + * Copyright (C) 2011 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" +#include "rcar-gen2.h" + +#include + +#include "crc32_word4.c" +#include "pm-rcar.h" + + +struct swsusp_header { + char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int) - + sizeof(u32) - sizeof(CRC32_WORD4_t) - sizeof(u32)]; + CRC32_WORD4_t comp_crc32; + u32 img_size; /* add. see. kernel/power/swap.c */ + u32 crc32; + sector_t image; + unsigned int flags; /* Flags to pass to the "boot" kernel */ + char orig_sig[10]; + char sig[10]; +} __packed; +static unsigned long swsusp_area = CONFIG_SWSUSP_AREA; +static unsigned long swsusp_area_size = CONFIG_SWSUSP_AREA_SIZE; + +enum { + MSTP00, MSTP01, MSTP02, MSTP03, MSTP04, MSTP05, + MSTP07, MSTP08, MSTP09, MSTP10, MSTP11, + MSTP_NR, +}; + +static struct { + u32 s_offset; + u32 s_val; + u32 r_offset; + u32 r_val; +} mstp_regs[] = { + [MSTP00] = { SMSTPCR0, 0, + RMSTPCR0, 0}, + [MSTP01] = { SMSTPCR1, 0, + RMSTPCR1, 0}, + [MSTP02] = { SMSTPCR2, 0, + RMSTPCR2, 0}, + [MSTP03] = { SMSTPCR3, 0, + RMSTPCR3, 0}, + [MSTP04] = { SMSTPCR4, 0, + RMSTPCR4, 0}, + [MSTP05] = { SMSTPCR5, 0, + RMSTPCR5, 0}, + [MSTP07] = { SMSTPCR7, 0, + RMSTPCR7, 0}, + [MSTP08] = { SMSTPCR8, 0, + RMSTPCR8, 0}, + [MSTP09] = { SMSTPCR9, 0, + RMSTPCR9, 0}, + [MSTP10] = { SMSTPCR10, 0, + RMSTPCR10, 0}, + [MSTP11] = { SMSTPCR11, 0, + RMSTPCR11, 0}, +}; + +static void save_mstp_regs(void) +{ + int i; + void *m = ioremap(CPG_BASE, CPG_LEN); + for (i = MSTP00; i < MSTP_NR; i++) { + mstp_regs[i].s_val = ioread32(m +mstp_regs[i].s_offset); + mstp_regs[i].r_val = ioread32(m +mstp_regs[i].r_offset); + } + iounmap(m); +} + +static void restore_mstp_regs(void) +{ + int i; + void *m = ioremap(CPG_BASE, CPG_LEN); + for (i = MSTP00; i < MSTP_NR; i++) { + iowrite32(mstp_regs[i].s_val, m +mstp_regs[i].s_offset); + iowrite32(mstp_regs[i].r_val, m +mstp_regs[i].r_offset); + } + iounmap(m); +} + +static int shmobile_hibernation_begin(void) +{ + save_mstp_regs(); + return 0; +} + +static void shmobile_hibernation_end(void) +{ +} + +static int shmobile_hibernation_pre_snapshot(void) +{ + return 0; +} + + +static void shmobile_hibernation_finish(void) +{ +} + +static int shmobile_hibernation_prepare(void) +{ + return 0; +} + +static int shmobile_hibernation_enter(void) +{ + void *m, *l; + struct swsusp_header *h; + unsigned int calc_sz; + if (swsusp_area_size > 0) { + h = m = ioremap(swsusp_area, swsusp_area_size); + if (h) { + if ((h->img_size > PAGE_SIZE) + && (h->img_size < (swsusp_area_size - PAGE_SIZE))) + calc_sz = h->img_size; + else + calc_sz = swsusp_area_size - PAGE_SIZE; + memset(&h->comp_crc32, 0, sizeof(h->comp_crc32)); + calc_crc32x4(m + PAGE_SIZE, calc_sz, &h->comp_crc32); + mb(); + iounmap(m); + } + } + /* Resetting FDP0 */ + l = ioremap(0xfe940000, 0x4000); + writel(1, l + 0x1c); + mb(); + iounmap(l); + /* Resetting FDP1 */ + l = ioremap(0xfe944000, 0x4000); + writel(1, l + 0x1c); + mb(); + iounmap(l); + /* Doing board reset */ + l = ioremap(0xe6300200, 4); + writel(0xa1b20001, l); + mb(); + iounmap(l); + + return 0; +} + +char *clks[] = { + "ehci", "hsusb", "dmal", "dmah", "sys-dmac1", + "sys-dmac0", "ssp", "ssp_dev", "ipmmu_gp", + "audmac0", "audmac1", +}; + +static int shmobile_hibernation_pre_restore(void) +{ + return 0; +} + + +static void shmobile_hibernation_restore_cleanup(void) +{ +} + +extern int in_suspend; + +static void shmobile_hibernation_leave(void) +{ + int restore_highmem(void); + struct clk *clk; + unsigned int i; + + if (!in_suspend) { +#ifdef CONFIG_SMP + if (is_smp()) + arch_smp_prepare_cpus(setup_max_cpus); +#endif + +#ifdef CONFIG_HIGHMEM + restore_highmem(); +#endif + restore_mstp_regs(); + } + + for (i = 0; i < ARRAY_SIZE(clks); ++i) { + clk = clk_get(NULL, clks[i]); + if (!IS_ERR(clk)) { + clk_prepare_enable(clk); + clk_put(clk); + } + } +} + +const struct platform_hibernation_ops shmobile_hibernation_ops = { + .leave = shmobile_hibernation_leave, + .begin = shmobile_hibernation_begin, + .end = shmobile_hibernation_end, + .pre_snapshot = shmobile_hibernation_pre_snapshot, + .finish = shmobile_hibernation_finish, + .prepare = shmobile_hibernation_prepare, + .enter = shmobile_hibernation_enter, + .pre_restore = shmobile_hibernation_pre_restore, + .restore_cleanup = shmobile_hibernation_restore_cleanup, +}; + +int __init shmobile_hibernation_init(void) +{ + hibernation_set_ops(&shmobile_hibernation_ops); + return 0; +} +static int setup_swsusp_area(char *s) +{ + long tmp = 0; + char *p; + if (!kstrtol(s, 0, &tmp) && tmp > 0) + swsusp_area = tmp; + p = strchr(s, ','); + if (!p) + goto out; + if (!kstrtol(p, 0, &tmp) && tmp > 0) + swsusp_area_size = tmp; +out: + return 1; +} +__setup("swsusp_area=", setup_swsusp_area); + diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index cff7a25..e382e26 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -33,7 +33,10 @@ /* only enable the cluster that includes the boot CPU by default */ static bool enable_multicluster = false; +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \ +defined(CONFIG_CPU_IDLE) static bool is_last_cpu; +#endif static __init int apmu_setup(char *opt) { @@ -71,12 +74,15 @@ static int __maybe_unused apmu_power_on(void __iomem *p, int bit) return 0; } +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \ +defined(CONFIG_CPU_IDLE) static int apmu_power_off(void __iomem *p, int bit) { /* request Core Standby for next WFI */ writel_relaxed(3, p + CPUNCR_OFFS(bit)); return 0; } +#endif static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit) { @@ -92,12 +98,15 @@ static int __maybe_unused apmu_power_off_poll(void __iomem *p, int bit) return 0; } +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND) || \ +defined(CONFIG_CPU_IDLE) || defined(CONFIG_SMP) static int apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu)) { void __iomem *p = apmu_cpus[cpu].iomem; return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL; } +#endif static void apmu_init_cpu(struct resource *res, int cpu, int bit) { @@ -141,7 +150,7 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit), } } -void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, +void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, struct rcar_apmu_config *apmu_config, int num) { @@ -328,7 +337,7 @@ static int __cpuinit shmobile_smp_apmu_enter_suspend(suspend_state_t state) return 0; } -void __init shmobile_smp_apmu_suspend_init(void) +void shmobile_smp_apmu_suspend_init(void) { cpucmcr_ca7 = ioremap_nocache(CPUCMCR_CA7, 0x4); cpucmcr_ca15 = ioremap_nocache(CPUCMCR_CA15, 0x4); diff --git a/arch/arm/mach-shmobile/platsmp-rst.c b/arch/arm/mach-shmobile/platsmp-rst.c index 70a2b6c..7ba9eeb 100644 --- a/arch/arm/mach-shmobile/platsmp-rst.c +++ b/arch/arm/mach-shmobile/platsmp-rst.c @@ -11,8 +11,7 @@ #include #include #include - -#define RST 0xe6160000 +#include "rcar-gen2.h" #define r8a779x_clst_id(cpu) (cpu_logical_map((cpu)) >> 8) #define r8a779x_cpu_id(cpu) (cpu_logical_map((cpu)) & 0xff) diff --git a/arch/arm/mach-shmobile/pm-r8a7791.c b/arch/arm/mach-shmobile/pm-r8a7791.c index f0ed98c..a13da84 100644 --- a/arch/arm/mach-shmobile/pm-r8a7791.c +++ b/arch/arm/mach-shmobile/pm-r8a7791.c @@ -21,16 +21,9 @@ #include #include "common.h" #include "pm-rcar.h" +#include "rcar-gen2.h" #include "r8a7791.h" -#define RST 0xe6160000 -#define CA15BAR 0x0020 -#define RAM 0xe63c0000 - -/* SYSC */ -#define SYSCIER 0x0c -#define SYSCIMR 0x10 - struct r8a7791_pm_domain { struct generic_pm_domain genpd; struct rcar_sysc_ch ch; @@ -43,13 +36,14 @@ static inline struct rcar_sysc_ch *to_r8a7791_ch(struct generic_pm_domain *d) #if defined(CONFIG_PM) || defined(CONFIG_SMP) -static void __init r8a7791_sysc_init(void) +static void r8a7791_sysc_init(void) { - void __iomem *base = rcar_sysc_init(0xe6180000); + void __iomem *base = rcar_sysc_init(SYSC_BASE); /* enable all interrupt sources, but do not use interrupt handler */ iowrite32(0x0131000e, base + SYSCIER); - iowrite32(0, base + SYSCIMR); + /* keep reserved bits as they are in TRM */ + iowrite32(0x012001ec, base + SYSCIMR); } #else /* CONFIG_PM || CONFIG_SMP */ @@ -60,9 +54,6 @@ static inline void r8a7791_sysc_init(void) {} #ifdef CONFIG_PM -#define CPG_BASE 0xe6150000 -#define CPG_LEN 0x1000 - /* Software Reset */ #define SRCR0 0x00a0 #define SRCR1 0x00a8 @@ -243,14 +234,10 @@ static struct notifier_block platform_nb = { #endif /* CONFIG_PM */ -void __init r8a7791_pm_init(void) +void r8a7791_pm_init(void) { void __iomem *p; u32 bar; - static int once; - - if (once++) - return; /* RAM for jump stub, because BAR requires 256KB aligned address */ p = ioremap_nocache(RAM, shmobile_boot_size); @@ -258,7 +245,7 @@ void __init r8a7791_pm_init(void) iounmap(p); /* setup reset vectors */ - p = ioremap_nocache(RST, 0x63); + p = ioremap_nocache(RST, RST_LEN); bar = (RAM >> 8) & 0xfffffc00; writel_relaxed(bar, p + CA15BAR); writel_relaxed(bar | 0x10, p + CA15BAR); diff --git a/arch/arm/mach-shmobile/rcar-gen2.h b/arch/arm/mach-shmobile/rcar-gen2.h index ce53cb5..df7201a 100644 --- a/arch/arm/mach-shmobile/rcar-gen2.h +++ b/arch/arm/mach-shmobile/rcar-gen2.h @@ -1,6 +1,45 @@ #ifndef __ASM_RCAR_GEN2_H__ #define __ASM_RCAR_GEN2_H__ +#define CPG_BASE 0xe6150000 +#define CPG_LEN 0x1000 +#define RMSTPCR0 0x110 +#define RMSTPCR1 0x114 +#define RMSTPCR2 0x118 +#define RMSTPCR3 0x11c +#define RMSTPCR4 0x120 +#define RMSTPCR5 0x124 +#define RMSTPCR7 0x12c +#define RMSTPCR8 0x980 +#define RMSTPCR9 0x984 +#define RMSTPCR10 0x988 +#define RMSTPCR11 0x98c +#define SMSTPCR0 0x130 +#define SMSTPCR1 0x134 +#define SMSTPCR2 0x138 +#define SMSTPCR3 0x13c +#define SMSTPCR4 0x140 +#define SMSTPCR5 0x144 +#define SMSTPCR7 0x14c +#define SMSTPCR8 0x990 +#define SMSTPCR9 0x994 +#define SMSTPCR10 0x998 +#define SMSTPCR11 0x99c + +#define SYSC_BASE 0xe6180000 +#define SYSCIER 0x0c +#define SYSCIMR 0x10 + +#define RST 0xe6160000 +#define RST_LEN 0x64 + +#define CA15BAR 0x0020 +#define CA7BAR 0x0030 +#define RAM 0xe63c0000 + +#define CNTCR 0 +#define CNTFID0 0x20 + void rcar_gen2_timer_init(void); #define MD(nr) BIT(nr) u32 rcar_gen2_read_mode_pins(void); diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c index 2aa431a..c48c6a9 100644 --- a/arch/arm/mach-shmobile/setup-r8a7791.c +++ b/arch/arm/mach-shmobile/setup-r8a7791.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "common.h" #include "dma-register.h" @@ -243,8 +244,6 @@ static const struct resource powervr_resources[] __initconst = { powervr_resources, \ ARRAY_SIZE(powervr_resources)) -#define CPG_BASE 0xe6150000 -#define CPG_LEN 0x1000 #define RGXCR 0x0B4 void __init r8a7791_register_pvrsrvkm(void) @@ -271,7 +270,12 @@ void __init r8a7791_register_ssp(void) void __init r8a7791_add_dt_devices(void) { - r8a7791_pm_init(); +#ifdef CONFIG_SMP + /* In case of SMP config pm_init already called from smp_prepare_cpus. + * It is still needed to call pm_init if 'nosmp' was given */ + if (!setup_max_cpus) +#endif + r8a7791_pm_init(); r8a7791_init_pm_domains(); r8a7791_register_cmt(00); r8a7791_register_pvrsrvkm(); diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index da16ebd..641ee1d 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -47,9 +47,6 @@ u32 rcar_gen2_read_mode_pins(void) return mode; } -#define CNTCR 0 -#define CNTFID0 0x20 - void __init rcar_gen2_timer_init(void) { #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK) @@ -58,7 +55,7 @@ void __init rcar_gen2_timer_init(void) #ifdef CONFIG_ARM_ARCH_TIMER void __iomem *base; int extal_mhz = 0; - u32 freq; + u32 rcar_gen2_archtimer_freq; /* At Linux boot time the r8a7790 arch timer comes up * with the counter disabled. Moreover, it may also report @@ -83,7 +80,7 @@ void __init rcar_gen2_timer_init(void) } /* The arch timer frequency equals EXTAL / 2 */ - freq = extal_mhz * (1000000 / 2); + rcar_gen2_archtimer_freq = extal_mhz * (1000000 / 2); /* Remap "armgcnt address map" space */ base = ioremap(0xe6080000, PAGE_SIZE); @@ -96,10 +93,11 @@ void __init rcar_gen2_timer_init(void) */ if ((ioread32(base + CNTCR) & 1) == 0 || - ioread32(base + CNTFID0) != freq) { + ioread32(base + CNTFID0) != rcar_gen2_archtimer_freq) { /* Update registers with correct frequency */ - iowrite32(freq, base + CNTFID0); - asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq)); + iowrite32(rcar_gen2_archtimer_freq, base + CNTFID0); + asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" + (rcar_gen2_archtimer_freq)); /* make sure arch timer is started by setting bit 0 of CNTCR */ iowrite32(1, base + CNTCR); diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index 24cad9f..4583cb6 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -33,6 +33,11 @@ #define CA15RESCNT 0x0040 +static struct rcar_sysc_ch r8a7791_ca15_scu = { + .chan_offs = 0x180, /* PWRSR5 .. PWRER5 */ + .isr_bit = 12, /* CA15-SCU */ +}; + static struct rcar_apmu_config r8a7791_apmu_config[] = { { .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), @@ -47,7 +52,7 @@ static struct rcar_rst_config r8a7791_rst_config[] = { } }; -static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) +static void r8a7791_smp_prepare_cpus(unsigned int max_cpus) { void __iomem *p; u32 val; @@ -67,6 +72,7 @@ static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) } r8a7791_pm_init(); + rcar_sysc_power_up(&r8a7791_ca15_scu); /* keep secondary CPU cores in reset */ r8a779x_init_reset(r8a7791_rst_config); diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 19da841..35c9048 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -92,48 +92,59 @@ ENDPROC(cpu_v7_dcache_clean_area) /* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */ .globl cpu_v7_suspend_size -.equ cpu_v7_suspend_size, 4 * 8 +.equ cpu_v7_suspend_size, 4 * 9 #ifdef CONFIG_ARM_CPU_SUSPEND ENTRY(cpu_v7_do_suspend) stmfd sp!, {r4 - r10, lr} mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID stmia r0!, {r4 - r5} +#ifdef CONFIG_MMU mrc p15, 0, r6, c3, c0, 0 @ Domain ID +#ifdef CONFIG_ARM_LPAE + mrrc p15, 1, r5, r7, c2 @ TTB 1 +#else mrc p15, 0, r7, c2, c0, 1 @ TTB 1 +#endif mrc p15, 0, r11, c2, c0, 2 @ TTB control register +#endif mrc p15, 0, r8, c1, c0, 0 @ Control register mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control - stmia r0, {r6 - r11} + stmia r0, {r5 - r11} ldmfd sp!, {r4 - r10, pc} ENDPROC(cpu_v7_do_suspend) ENTRY(cpu_v7_do_resume) mov ip, #0 - mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID ldmia r0!, {r4 - r5} mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID - ldmia r0, {r6 - r11} + ldmia r0, {r5 - r11} +#ifdef CONFIG_MMU + mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs mcr p15, 0, r6, c3, c0, 0 @ Domain ID -#ifndef CONFIG_ARM_LPAE +#ifdef CONFIG_ARM_LPAE + mcrr p15, 0, r1, ip, c2 @ TTB 0 + mcrr p15, 1, r5, r7, c2 @ TTB 1 +#else ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP) ALT_UP(orr r1, r1, #TTB_FLAGS_UP) -#endif mcr p15, 0, r1, c2, c0, 0 @ TTB 0 mcr p15, 0, r7, c2, c0, 1 @ TTB 1 +#endif mcr p15, 0, r11, c2, c0, 2 @ TTB control register - mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register - teq r4, r9 @ Is it already set? - mcrne p15, 0, r9, c1, c0, 1 @ No, so write it - mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control ldr r4, =PRRR @ PRRR ldr r5, =NMRR @ NMRR mcr p15, 0, r4, c10, c2, 0 @ write PRRR mcr p15, 0, r5, c10, c2, 1 @ write NMRR +#endif /* CONFIG_MMU */ + mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register + teq r4, r9 @ Is it already set? + mcrne p15, 0, r9, c1, c0, 1 @ No, so write it + mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control isb dsb mov r0, r8 @ control register -- 1.8.3.1