[PATCH 2/2] ARM: S5PV310: Add support Power Domain

Ben Dooks ben-linux at fluff.org
Fri Oct 29 19:33:10 EDT 2010


On 13/10/10 12:47, Kukjin Kim wrote:
> From: Changhwan Youn <chaos.youn at samsung.com>
> 
> This patch adds support Power Domain for S5PV310 and S5PC210.
> 
> Signed-off-by: Changhwan Youn <chaos.youn at samsung.com>
> Signed-off-by: Kukjin Kim <kgene.kim at samsung.com>
> ---
>  arch/arm/mach-s5pv310/Kconfig                 |    7 +
>  arch/arm/mach-s5pv310/Makefile                |    2 +
>  arch/arm/mach-s5pv310/cpu.c                   |    5 +
>  arch/arm/mach-s5pv310/dev-pd.c                |  249 +++++++++++++++++++++++++
>  arch/arm/mach-s5pv310/include/mach/map.h      |    2 +
>  arch/arm/mach-s5pv310/include/mach/regs-pmu.h |   40 ++++
>  arch/arm/mach-s5pv310/mach-smdkc210.c         |    9 +
>  arch/arm/mach-s5pv310/mach-smdkv310.c         |    9 +
>  arch/arm/plat-s5p/include/plat/map-s5p.h      |    1 +
>  arch/arm/plat-samsung/include/plat/devs.h     |    2 +
>  10 files changed, 326 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-s5pv310/dev-pd.c
>  create mode 100644 arch/arm/mach-s5pv310/include/mach/regs-pmu.h
> 
> diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig
> index 1150b36..3bf72a6 100644
> --- a/arch/arm/mach-s5pv310/Kconfig
> +++ b/arch/arm/mach-s5pv310/Kconfig
> @@ -14,6 +14,11 @@ config CPU_S5PV310
>  	help
>  	  Enable S5PV310 CPU support
>  
> +config S5PV310_DEV_PD
> +	bool
> +	help
> +	  Compile in platform device definitions for Power Domain
> +
>  config S5PV310_SETUP_I2C1
>  	bool
>  	help
> @@ -73,6 +78,7 @@ config MACH_SMDKC210
>  	select S3C_DEV_HSMMC1
>  	select S3C_DEV_HSMMC2
>  	select S3C_DEV_HSMMC3
> +	select S5PV310_DEV_PD
>  	select S5PV310_SETUP_SDHCI
>  	help
>  	  Machine support for Samsung SMDKC210
> @@ -101,6 +107,7 @@ config MACH_SMDKV310
>  	select S3C_DEV_HSMMC1
>  	select S3C_DEV_HSMMC2
>  	select S3C_DEV_HSMMC3
> +	select S5PV310_DEV_PD
>  	select S5PV310_SETUP_SDHCI
>  	help
>  	  Machine support for Samsung SMDKV310
> diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile
> index 97aba6d..74beb47 100644
> --- a/arch/arm/mach-s5pv310/Makefile
> +++ b/arch/arm/mach-s5pv310/Makefile
> @@ -28,6 +28,8 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210)	+= mach-universal_c210.o
>  
>  # device support
>  
> +obj-$(CONFIG_S5PV310_DEV_PD)		+= dev-pd.o
> +
>  obj-$(CONFIG_S5PV310_SETUP_I2C1)	+= setup-i2c1.o
>  obj-$(CONFIG_S5PV310_SETUP_I2C2)	+= setup-i2c2.o
>  obj-$(CONFIG_S5PV310_SETUP_I2C3)	+= setup-i2c3.o
> diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c
> index ffed262..44ddad6 100644
> --- a/arch/arm/mach-s5pv310/cpu.c
> +++ b/arch/arm/mach-s5pv310/cpu.c
> @@ -42,6 +42,11 @@ static struct map_desc s5pv310_iodesc[] __initdata = {
>  		.length		= SZ_128K,
>  		.type		= MT_DEVICE,
>  	}, {
> +		.virtual	= (unsigned long)S5P_VA_PMU,
> +		.pfn		= __phys_to_pfn(S5PV310_PA_PMU),
> +		.length		= SZ_64K,
> +		.type		= MT_DEVICE,
> +	}, {
>  		.virtual	= (unsigned long)S5P_VA_COMBINER_BASE,
>  		.pfn		= __phys_to_pfn(S5PV310_PA_COMBINER),
>  		.length		= SZ_4K,
> diff --git a/arch/arm/mach-s5pv310/dev-pd.c b/arch/arm/mach-s5pv310/dev-pd.c
> new file mode 100644
> index 0000000..ac5a1f8
> --- /dev/null
> +++ b/arch/arm/mach-s5pv310/dev-pd.c
> @@ -0,0 +1,249 @@
> +/* linux/arch/arm/mach-s5pv310/dev-pd.c
> + *
> + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * S5PV310 - Power Domain support
> + *
> + * 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.
> +*/
> +
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/delay.h>
> +
> +#include <mach/regs-pmu.h>
> +
> +#include <plat/pd.h>
> +
> +static int s5pv310_pd_enable(enum s5pv310_pd_block pd)
> +{
> +	void __iomem *status;
> +	u32 timeout;
> +
> +	switch (pd) {
> +	case PD_MFC:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_MFC_CONFIGURATION);
> +		status = S5P_MFC_STATUS;
> +		break;
> +	case PD_G3D:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_G3D_CONFIGURATION);
> +		status = S5P_G3D_STATUS;
> +		break;
> +	case PD_LCD0:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_LCD0_CONFIGURATION);
> +		status = S5P_LCD0_STATUS;
> +		break;
> +	case PD_LCD1:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_LCD1_CONFIGURATION);
> +		status = S5P_LCD1_STATUS;
> +		break;
> +	case PD_CAM:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_CAM_CONFIGURATION);
> +		status = S5P_CAM_STATUS;
> +		break;
> +	case PD_TV:
> +		__raw_writel(S5P_INT_LOCAL_PWR_EN, S5P_TV_CONFIGURATION);
> +		status = S5P_TV_STATUS;
> +		break;
> +	default:
> +		printk(KERN_WARNING "Wrong PD enable request %d\n", pd);
> +		return -EINVAL;
> +	}
> +
> +	/* Wait max 1ms */
> +	timeout = 10;
> +	while ((__raw_readl(status) & S5P_INT_LOCAL_PWR_EN)
> +		!= S5P_INT_LOCAL_PWR_EN) {
> +		if (timeout == 0) {
> +			printk(KERN_ERR "Power domain %d enable failed.\n", pd);
> +			return -ETIMEDOUT;
> +		}
> +		timeout--;
> +		udelay(100);
> +	}
> +
> +	return 0;
> +}
> +
> +static int s5pv310_pd_disable(enum s5pv310_pd_block pd)
> +{
> +	void __iomem *status;
> +	u32 timeout;
> +
> +	switch (pd) {
> +	case PD_MFC:
> +		__raw_writel(0, S5P_MFC_CONFIGURATION);
> +		status = S5P_MFC_STATUS;
> +		break;
> +	case PD_G3D:
> +		__raw_writel(0, S5P_G3D_CONFIGURATION);
> +		status = S5P_G3D_STATUS;
> +		break;
> +	case PD_LCD0:
> +		__raw_writel(0, S5P_LCD0_CONFIGURATION);
> +		status = S5P_LCD0_STATUS;
> +		break;
> +	case PD_LCD1:
> +		__raw_writel(0, S5P_LCD1_CONFIGURATION);
> +		status = S5P_LCD1_STATUS;
> +		break;
> +	case PD_CAM:
> +		__raw_writel(0, S5P_CAM_CONFIGURATION);
> +		status = S5P_CAM_STATUS;
> +		break;
> +	case PD_TV:
> +		__raw_writel(0, S5P_TV_CONFIGURATION);
> +		status = S5P_TV_STATUS;
> +		break;
> +	default:
> +		printk(KERN_WARNING "Wrong PD disable request %d\n", pd);
> +		return -EINVAL;
> +	}
> +
> +	/* Wait max 1ms */
> +	timeout = 10;
> +	while (__raw_readl(status) & S5P_INT_LOCAL_PWR_EN) {
> +		if (timeout == 0) {
> +			printk(KERN_ERR "PD %d disable failed.\n", pd);
> +			return -ETIMEDOUT;
> +		}
> +		timeout--;
> +		udelay(100);
> +	}
> +
> +	return 0;
> +}
> +
> +static int s5pv310_pd_mfc_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_MFC);
> +}
> +
> +static int s5pv310_pd_mfc_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_MFC);
> +}
> +
> +static int s5pv310_pd_g3d_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_G3D);
> +}
> +
> +static int s5pv310_pd_g3d_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_G3D);
> +}
> +
> +static int s5pv310_pd_lcd0_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_LCD0);
> +}
> +
> +static int s5pv310_pd_lcd0_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_LCD0);
> +}
> +
> +static int s5pv310_pd_lcd1_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_LCD1);
> +}
> +
> +static int s5pv310_pd_lcd1_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_LCD1);
> +}
> +
> +static int s5pv310_pd_cam_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_CAM);
> +}
> +
> +static int s5pv310_pd_cam_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_CAM);
> +}
> +
> +static int s5pv310_pd_tv_enable(void)
> +{
> +	return s5pv310_pd_enable(PD_TV);
> +}
> +
> +static int s5pv310_pd_tv_disable(void)
> +{
> +	return s5pv310_pd_disable(PD_TV);
> +}
> +
> +static struct samsung_pd_info s5pv310_pd_mfc_pdata = {
> +	.enable		= s5pv310_pd_mfc_enable,
> +	.disable	= s5pv310_pd_mfc_disable,
> +};
> +
> +static struct samsung_pd_info s5pv310_pd_g3d_pdata = {
> +	.enable		= s5pv310_pd_g3d_enable,
> +	.disable	= s5pv310_pd_g3d_disable,
> +};
> +
> +static struct samsung_pd_info s5pv310_pd_lcd0_pdata = {
> +	.enable		= s5pv310_pd_lcd0_enable,
> +	.disable	= s5pv310_pd_lcd0_disable,
> +};
> +
> +static struct samsung_pd_info s5pv310_pd_lcd1_pdata = {
> +	.enable		= s5pv310_pd_lcd1_enable,
> +	.disable	= s5pv310_pd_lcd1_disable,
> +};
> +
> +static struct samsung_pd_info s5pv310_pd_tv_pdata = {
> +	.enable		= s5pv310_pd_tv_enable,
> +	.disable	= s5pv310_pd_tv_disable,
> +};
> +
> +static struct samsung_pd_info s5pv310_pd_cam_pdata = {
> +	.enable		= s5pv310_pd_cam_enable,
> +	.disable	= s5pv310_pd_cam_disable,
> +};
> +
> +struct platform_device s5pv310_device_pd[] = {
> +	{
> +		.name		= "samsung-pd",
> +		.id		= 0,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_mfc_pdata,
> +		},

how about wrapping each device in a new struct with the pd
base info in it, such as

struct samsung_pd_device {
	struct platform_device	pdev;
	void __iomem            *base;
}

this means you can squash out all the samsung_pd_info structures
and have a single enable/disable function and avoid the switch
statements in them.

you could also simply put the base address in the pdata and
avoid this too. also see Marek's comments about inlining the
platform data setting.


> +	}, {
> +		.name		= "samsung-pd",
> +		.id		= 1,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_g3d_pdata,
> +		},
> +	}, {
> +		.name		= "samsung-pd",
> +		.id		= 2,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_lcd0_pdata,
> +		},
> +	}, {
> +		.name		= "samsung-pd",
> +		.id		= 3,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_lcd1_pdata,
> +		},
> +	}, {
> +		.name		= "samsung-pd",
> +		.id		= 4,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_tv_pdata,
> +		},
> +	}, {
> +		.name		= "samsung-pd",
> +		.id		= 5,
> +		.dev = {
> +			.platform_data = &s5pv310_pd_cam_pdata,
> +		},
> +	},
> +};
> diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h
> index 1429510..9decf02 100644
> --- a/arch/arm/mach-s5pv310/include/mach/map.h
> +++ b/arch/arm/mach-s5pv310/include/mach/map.h
> @@ -37,6 +37,8 @@
>  #define S5PV310_PA_SYSCON		(0x10010000)
>  #define S5P_PA_SYSCON			S5PV310_PA_SYSCON
>  
> +#define S5PV310_PA_PMU			(0x10020000)
> +
>  #define S5PV310_PA_CMU			(0x10030000)
>  
>  #define S5PV310_PA_WATCHDOG		(0x10060000)
> diff --git a/arch/arm/mach-s5pv310/include/mach/regs-pmu.h b/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
> new file mode 100644
> index 0000000..f4b2229
> --- /dev/null
> +++ b/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
> @@ -0,0 +1,40 @@
> +/* linux/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
> + *
> + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * S5PV310 - Power management unit definition
> + *
> + * 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.
> +*/
> +
> +#ifndef __ASM_ARCH_REGS_PMU_H
> +#define __ASM_ARCH_REGS_PMU_H __FILE__
> +
> +#include <mach/map.h>
> +
> +#define S5P_PMUREG(x)				(S5P_VA_PMU + (x))
> +
> +#define S5P_CAM_CONFIGURATION			S5P_PMUREG(0x3C00)
> +#define S5P_CAM_STATUS				S5P_PMUREG(0x3C04)
> +
> +#define S5P_TV_CONFIGURATION			S5P_PMUREG(0x3C20)
> +#define S5P_TV_STATUS				S5P_PMUREG(0x3C24)
> +
> +#define S5P_MFC_CONFIGURATION			S5P_PMUREG(0x3C40)
> +#define S5P_MFC_STATUS				S5P_PMUREG(0x3C44)
> +
> +#define S5P_G3D_CONFIGURATION			S5P_PMUREG(0x3C60)
> +#define S5P_G3D_STATUS				S5P_PMUREG(0x3C64)
> +
> +#define S5P_LCD0_CONFIGURATION			S5P_PMUREG(0x3C80)
> +#define S5P_LCD0_STATUS				S5P_PMUREG(0x3C84)
> +
> +#define S5P_LCD1_CONFIGURATION			S5P_PMUREG(0x3CA0)
> +#define S5P_LCD1_STATUS				S5P_PMUREG(0x3CA4)

give STATUS seems to be CONFIGURATION+0x04, why bother with them?

> +
> +#define S5P_INT_LOCAL_PWR_EN			0x7
> +
> +#endif /* __ASM_ARCH_REGS_PMU_H */
> diff --git a/arch/arm/mach-s5pv310/mach-smdkc210.c b/arch/arm/mach-s5pv310/mach-smdkc210.c
> index d2cf694..390befd 100644
> --- a/arch/arm/mach-s5pv310/mach-smdkc210.c
> +++ b/arch/arm/mach-s5pv310/mach-smdkc210.c
> @@ -22,6 +22,7 @@
>  #include <plat/cpu.h>
>  #include <plat/devs.h>
>  #include <plat/sdhci.h>
> +#include <plat/pd.h>
>  
>  #include <mach/map.h>
>  
> @@ -113,6 +114,12 @@ static struct platform_device *smdkc210_devices[] __initdata = {
>  	&s3c_device_hsmmc3,
>  	&s3c_device_rtc,
>  	&s3c_device_wdt,
> +	&s5pv310_device_pd[PD_MFC],
> +	&s5pv310_device_pd[PD_G3D],
> +	&s5pv310_device_pd[PD_LCD0],
> +	&s5pv310_device_pd[PD_LCD1],
> +	&s5pv310_device_pd[PD_CAM],
> +	&s5pv310_device_pd[PD_TV],
>  };
>  
>  static void __init smdkc210_map_io(void)
> @@ -124,6 +131,8 @@ static void __init smdkc210_map_io(void)
>  
>  static void __init smdkc210_machine_init(void)
>  {
> +	samsung_pd_init();
> +
>  	s3c_sdhci0_set_platdata(&smdkc210_hsmmc0_pdata);
>  	s3c_sdhci1_set_platdata(&smdkc210_hsmmc1_pdata);
>  	s3c_sdhci2_set_platdata(&smdkc210_hsmmc2_pdata);
> diff --git a/arch/arm/mach-s5pv310/mach-smdkv310.c b/arch/arm/mach-s5pv310/mach-smdkv310.c
> index 10f8056..c6690cf 100644
> --- a/arch/arm/mach-s5pv310/mach-smdkv310.c
> +++ b/arch/arm/mach-s5pv310/mach-smdkv310.c
> @@ -22,6 +22,7 @@
>  #include <plat/cpu.h>
>  #include <plat/devs.h>
>  #include <plat/sdhci.h>
> +#include <plat/pd.h>
>  
>  #include <mach/map.h>
>  
> @@ -113,6 +114,12 @@ static struct platform_device *smdkv310_devices[] __initdata = {
>  	&s3c_device_hsmmc3,
>  	&s3c_device_rtc,
>  	&s3c_device_wdt,
> +	&s5pv310_device_pd[PD_MFC],
> +	&s5pv310_device_pd[PD_G3D],
> +	&s5pv310_device_pd[PD_LCD0],
> +	&s5pv310_device_pd[PD_LCD1],
> +	&s5pv310_device_pd[PD_CAM],
> +	&s5pv310_device_pd[PD_TV],
>  };
>  
>  static void __init smdkv310_map_io(void)
> @@ -124,6 +131,8 @@ static void __init smdkv310_map_io(void)
>  
>  static void __init smdkv310_machine_init(void)
>  {
> +	samsung_pd_init();
> +

given the driver will only get called when the devices are
registered, how about making it have its own initcall and
avoid having to splatter these through each machine?

>  	s3c_sdhci0_set_platdata(&smdkv310_hsmmc0_pdata);
>  	s3c_sdhci1_set_platdata(&smdkv310_hsmmc1_pdata);
>  	s3c_sdhci2_set_platdata(&smdkv310_hsmmc2_pdata);
> diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
> index fef353d..d973d39 100644
> --- a/arch/arm/plat-s5p/include/plat/map-s5p.h
> +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
> @@ -15,6 +15,7 @@
>  
>  #define S5P_VA_CHIPID		S3C_ADDR(0x02000000)
>  #define S5P_VA_CMU		S3C_ADDR(0x02100000)
> +#define S5P_VA_PMU		S3C_ADDR(0x02180000)
>  #define S5P_VA_GPIO		S3C_ADDR(0x02200000)
>  #define S5P_VA_GPIO1		S5P_VA_GPIO
>  #define S5P_VA_GPIO2		S3C_ADDR(0x02240000)
> diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
> index 71bcc0f..c483480 100644
> --- a/arch/arm/plat-samsung/include/plat/devs.h
> +++ b/arch/arm/plat-samsung/include/plat/devs.h
> @@ -118,6 +118,8 @@ extern struct platform_device s5p_device_fimc0;
>  extern struct platform_device s5p_device_fimc1;
>  extern struct platform_device s5p_device_fimc2;
>  
> +extern struct platform_device s5pv310_device_pd[];
> +
>  /* s3c2440 specific devices */
>  
>  #ifdef CONFIG_CPU_S3C2440




More information about the linux-arm-kernel mailing list