[PATCH 1/2] ARM: EXYNOS: Add initial support of PMU for Exynos5260

Tomasz Figa t.figa at samsung.com
Wed Dec 18 11:35:22 EST 2013


Hi Vikas, Pankaj,

On Wednesday 11 of December 2013 16:25:15 Vikas Sajjan wrote:
> Adds initial PMU support for Exynos5260
> 
> Following are the changes done
> ------------------------------
> 
> 1) Added initial PMU support for exynos5260
> 
> 2) Added exynos5260_iodesc for mapping 5260 specific SFRs. We modified
> exynos5_map_io so that in case of exynos5260 only exynos5260_iodesc can
> be initialized.
> 
> 3) Added new macros for WAKEUP MASK for 5260, and modified exynos_pm_drvinit
> accrodingly.
> 
> Change-Id: Ie585d47a499c17813cfe0e5a668072ca7b13ffb5

This line should be removed.

> Signed-off-by: Pankaj Dubey <pankaj.dubey at samsung.com>
> Signed-off-by: Vikas Sajjan <vikas.sajjan at samsung.com>
> ---
>  arch/arm/mach-exynos/common.c                |  89 ++++++++++-
>  arch/arm/mach-exynos/common.h                |   5 +
>  arch/arm/mach-exynos/include/mach/map.h      |  17 +++
>  arch/arm/mach-exynos/include/mach/regs-pmu.h | 221 +++++++++++++++++++++++++++
>  arch/arm/mach-exynos/pm.c                    |  33 +++-
>  arch/arm/mach-exynos/pmu.c                   | 140 +++++++++++++++++
>  arch/arm/plat-samsung/include/plat/map-s5p.h |  14 ++
>  7 files changed, 508 insertions(+), 11 deletions(-)
[snip]
> +	}, {
> +		.virtual	= (unsigned long)S5P_VA_SROMC,
> +		.pfn		= __phys_to_pfn(EXYNOS5260_PA_SROMC),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	}, {
> +		.virtual	= (unsigned long)S5P_VA_SYSRAM,
> +		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSRAM),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	}, {
>  		.virtual	= (unsigned long)S5P_VA_SYSRAM_NS,
>  		.pfn		= __phys_to_pfn(EXYNOS5260_PA_SYSRAM_NS),
>  		.length		= SZ_4K,
>  		.type		= MT_DEVICE,
> +	}, {
> +		.virtual	= (unsigned long)S5P_VA_PMU,
> +		.pfn		= __phys_to_pfn(EXYNOS5260_PA_PMU),
> +		.length		= SZ_64K,
> +		.type		= MT_DEVICE,
>  	},

Do you really need all these static mappings above? Why can't you create
a mapping dynamically?

>  };
>  
[snip]
>  struct bus_type exynos_subsys = {
> diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
> index ff9b6a9..e2cabfe 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -47,6 +47,11 @@ enum sys_powerdown {
>  	NUM_SYS_POWERDOWN,
>  };
>  
> +enum running_cpu {
> +	KFC,
> +	ARM,
> +};

This isn't too meaningful. You should write a comment saying how this enum
is used and describing its values.

Also the name is too generic. It should be prefixed with exynos5260_
probably.

> +
>  extern unsigned long l2x0_regs_phys;
>  struct exynos_pmu_conf {
>  	void __iomem *reg;
> diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
> index bd6fa02..cc190b9 100644
> --- a/arch/arm/mach-exynos/include/mach/map.h
> +++ b/arch/arm/mach-exynos/include/mach/map.h
> @@ -31,6 +31,23 @@
>  #define EXYNOS5250_PA_SYSRAM_NS		0x0204F000
>  #define EXYNOS5260_PA_SYSRAM_NS		0x02073000
>  
> +#define EXYNOS5260_PA_PMU				0x10D50000
> +#define EXYNOS5260_PA_SROMC				0x12180000
> +#define EXYNOS5260_PA_PWM				0x12D90000
> +
> +#define EXYNOS5260_PA_SYS_PERI				0x10220000
> +#define EXYNOS5260_PA_SYS_MIF				0x10D00000
> +#define EXYNOS5260_PA_SYS_MFC				0x110A0000
> +#define EXYNOS5260_PA_SYS_KFC				0x10710000
> +#define EXYNOS5260_PA_SYS_ISP				0x133E0000
> +#define EXYNOS5260_PA_SYS_GSCL				0x13F20000
> +#define EXYNOS5260_PA_SYS_G3D				0x11850000
> +#define EXYNOS5260_PA_SYS_G2D				0x10A20000
> +#define EXYNOS5260_PA_SYS_FSYS				0x122F0000
> +#define EXYNOS5260_PA_SYS_EGL				0x10610000
> +#define EXYNOS5260_PA_SYS_DISP				0x14540000
> +#define EXYNOS5260_PA_SYS_AUD				0x128F0000
> +

Do you really need all the static addresses above?

>  #define EXYNOS_PA_CHIPID		0x10000000
>  
>  #define EXYNOS4_PA_SYSCON		0x10010000
> diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
> index 09ae29a..ac53f85 100644
> --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
> +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
> @@ -125,6 +125,25 @@
>  #define S5P_ARM_CORE1_STATUS			S5P_PMUREG(0x2084)
>  #define S5P_ARM_CORE1_OPTION			S5P_PMUREG(0x2088)
[snip]
> +#define EXYNOS5260_CORE_LOCAL_PWR_EN				0xf
> +#define EXYNOS5260_CPUS_PER_CLUSTER				4
> +#define EXYNOS5260_USE_DELAYED_RESET_ASSERTION			(1 << 12)
> +
> +#define EXYNOS5260_WAKEUP_STAT2			S5P_PMUREG(0x0604)
> +#define EXYNOS5260_WAKEUP_STAT3			S5P_PMUREG(0x0608)
> +#define EXYNOS5260_EINT_WAKEUP_MASK		S5P_PMUREG(0x060C)
> +#define EXYNOS5260_WAKEUP_MASK			S5P_PMUREG(0x0610)
> +#define EXYNOS5260_WAKEUP_MASK2			S5P_PMUREG(0x0614)
> +#define EXYNOS5260_WAKEUP_MASK3			S5P_PMUREG(0x0618)
> +
> +
> +/* Exynos5260 specific PMU SYS_PWR_REGs */
> +#define	EXYNOS5260_A15_EGL0_SYS_PWR_REG			S5P_PMUREG(0x1000)

CodingStyle: There should be just one space between #define and definiton
name. The same for a lot of definitons below.

> +#define	EXYNOS5260_DIS_IRQ_A15_EGL0_LOCAL_SYS_PWR_REG	S5P_PMUREG(0x1004)
> +#define	EXYNOS5260_DIS_IRQ_A15_EGL0_CNTRL_SYS_PWR_REG	S5P_PMUREG(0x1008)
> +#define	EXYNOS5260_DIS_IRQ_A15_EGL0_EGLSEQ_SYS_PWR_REG	S5P_PMUREG(0x100C)
> +#define	EXYNOS5260_A15_EGL1_SYS_PWR_REG			S5P_PMUREG(0x1010)
[snip]
> +/* CENTRAL_SEQ_OPTION */
> +#define EXYNOS5260_ARM_USE_STANDBY_WFI0			(1 << 16)
> +#define EXYNOS5260_ARM_USE_STANDBY_WFI1			(1 << 17)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFI0			(1 << 20)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFI1			(1 << 21)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFI2			(1 << 22)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFI3			(1 << 23)
> +#define EXYNOS5260_ARM_USE_STANDBY_WFE0			(1 << 24)
> +#define EXYNOS5260_ARM_USE_STANDBY_WFE1			(1 << 25)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFE0			(1 << 28)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFE1			(1 << 29)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFE2			(1 << 30)
> +#define EXYNOS5260_KFC_USE_STANDBY_WFE3			(1 << 31)
> +
> +#define EXYNOS5260_USE_STANDBY_WFI_ALL	(EXYNOS5260_ARM_USE_STANDBY_WFI0  \
> +					| EXYNOS5260_ARM_USE_STANDBY_WFI1  \
> +					| EXYNOS5260_KFC_USE_STANDBY_WFI0  \
> +					| EXYNOS5260_KFC_USE_STANDBY_WFI1  \
> +					| EXYNOS5260_KFC_USE_STANDBY_WFI2  \
> +					| EXYNOS5260_KFC_USE_STANDBY_WFI3)

This is not a definition of registers, so should be present in the file
using it as a convenience macro.

> +
> +
>  #endif /* __ASM_ARCH_REGS_PMU_H */
> diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
> index 78a22bf..c6def953 100644
> --- a/arch/arm/mach-exynos/pm.c
> +++ b/arch/arm/mach-exynos/pm.c
> @@ -58,7 +58,7 @@ static int exynos_cpu_suspend(unsigned long arg)
>  	outer_flush_all();
>  #endif
[snip]
>  	/* Setting SEQ_OPTION register */
> +	if (soc_is_exynos5250()) {
> +		tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
> +		__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
> +	} else if (soc_is_exynos5260()) {
> +		cluster_id = (read_cpuid(CPUID_MPIDR) >> 8) & 0xf;
> +		if (!cluster_id)
> +			__raw_writel(EXYNOS5260_ARM_USE_STANDBY_WFI0,
> +				     S5P_CENTRAL_SEQ_OPTION);
> +		else
> +			__raw_writel(EXYNOS5260_KFC_USE_STANDBY_WFI0,
> +				     S5P_CENTRAL_SEQ_OPTION);

Hmm, this seems strange. Shouldn't just a single particular CPU (CPU0 most
likely) be allowed to enter standby such as the code for other Exynos SoCs
is doing?

>  
> -	tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
> -	__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
> +	}
>  
> -	if (!soc_is_exynos5250()) {
> +	if (!soc_is_exynos5250() || !soc_is_exynos5260()) {

Is this condition really correct? It doesn't make much sense.

>  		/* Save Power control register */
>  		asm ("mrc p15, 0, %0, c15, c0, 0"
>  		     : "=r" (tmp) : : "cc");
> @@ -174,7 +191,7 @@ static void exynos_pm_resume(void)
>  		/* No need to perform below restore code */
>  		goto early_wakeup;
>  	}
> -	if (!soc_is_exynos5250()) {
> +	if (!soc_is_exynos5250() || !soc_is_exynos5260()) {

Ditto.

>  		/* Restore Power control register */
>  		tmp = save_arm_register[0];
>  		asm volatile ("mcr p15, 0, %0, c15, c0, 0"
> diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
> index 97d6885..c828d07 100644
> --- a/arch/arm/mach-exynos/pmu.c
> +++ b/arch/arm/mach-exynos/pmu.c
> @@ -317,6 +317,99 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = {
>  	{ PMU_TABLE_END,},
>  };
[snip]
> +static void exynos5260_reset_assert_ctrl(bool on, enum running_cpu cluster)
> +{
> +	unsigned int i;
> +	unsigned int option;
> +	unsigned int cpu_s, cpu_f;
> +
> +	if (cluster == KFC) {
> +		cpu_s = EXYNOS5260_CPUS_PER_CLUSTER;
> +		cpu_f = cpu_s + EXYNOS5260_CPUS_PER_CLUSTER;
> +	} else {
> +		cpu_s = 0;
> +		cpu_f = 2;

Hmm, a magic number. I wonder what it means. It doesn't seem to be the
Answer to the Ultimate Question of Life, The Universe, and Everything,
though. ;)

[1] http://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker's_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life.2C_the_Universe.2C_and_Everything_.2842.29

> +	}
> +
> +	for (i = cpu_s; i < cpu_f; i++) {
> +		option = __raw_readl(EXYNOS_ARM_CORE_OPTION(i));
> +		option = on ?
> +		(option | EXYNOS5260_USE_DELAYED_RESET_ASSERTION) :
> +			(option & ~EXYNOS5260_USE_DELAYED_RESET_ASSERTION);

Readability of this is quite poor. I'd recommend rewriting this to
a simple

		if (on)
			option |= EXYNOS5260_USE_DELAYED_RESET_ASSERTION;
		else
			option &= ~EXYNOS5260_USE_DELAYED_RESET_ASSERTION;

> +		__raw_writel(option, EXYNOS_ARM_CORE_OPTION(i));
> +	}
> +}
> +
> +
>  static int __init exynos_pmu_init(void)
>  {
>  	unsigned int value;
> @@ -415,6 +532,29 @@ static int __init exynos_pmu_init(void)
>  
>  		exynos_pmu_config = exynos5250_pmu_config;
>  		pr_info("EXYNOS5250 PMU Initialize\n");
> +	} else if (soc_is_exynos5260()) {
> +		/* Enable USE_STANDBY_WFI for all CORE */
> +		__raw_writel(EXYNOS5260_USE_STANDBY_WFI_ALL,
> +			S5P_CENTRAL_SEQ_OPTION);
> +		/*
> +		 * Set PSHOLD port for output high
> +		 */
> +		value = __raw_readl(EXYNOS_PS_HOLD_CONTROL);
> +		value |= EXYNOS_PS_HOLD_OUTPUT_HIGH;
> +		__raw_writel(value, EXYNOS_PS_HOLD_CONTROL);
> +
> +		/*
> +		 * Enable signal for PSHOLD port
> +		 */
> +		value = __raw_readl(EXYNOS_PS_HOLD_CONTROL);
> +		value |= EXYNOS_PS_HOLD_EN;
> +		__raw_writel(value, EXYNOS_PS_HOLD_CONTROL);

Hmm, do you really need this? What about boards with different polarity
of power hold signal in used PMIC? I believe this should be set correctly
by the bootloader and never changed later, except in power off callback.

Best regards,
Tomasz




More information about the linux-arm-kernel mailing list