diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 14:38:28 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-14 14:38:28 -0800 |
commit | 6a57d104c8cb5b6adad6784b4ce6e2f7f9961a3a (patch) | |
tree | c3ff93b006d7483ccee09799d215b03b1bbc3f1b | |
parent | cebfa85eb86d92bf85d3b041c6b044184517a988 (diff) | |
parent | c91321e8ff338a88a9272dcd938f085955cd5846 (diff) | |
download | linux-6a57d104c8cb5b6adad6784b4ce6e2f7f9961a3a.tar.bz2 |
Merge tag 'soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM Soc updates, take 2, from Olof Johansson:
"This is the second batch of SoC updates for the 3.8 merge window,
containing parts that had dependencies on earlier branches such that
we couldn't include them with the first branch.
These are general updates for Samsung Exynos, Renesas/shmobile and a
topic branch that adds SMP support to Altera's socfpga platform."
Fix up conflicts mostly as per Olof.
* tag 'soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc:
ARM: EXYNOS: Clock settings for SATA and SATA PHY
ARM: EXYNOS: Add ARM down clock support
ARM: EXYNOS: Fix i2c suspend/resume for legacy controller
ARM: EXYNOS: Add aliases for i2c controller
ARM: EXYNOS: Setup legacy i2c controller interrupts
sh: clkfwk: fixup unsed variable warning
Revert "ARM: shmobile: r8a7779: Replace modify_scu_cpu_psr with scu_power_mode"
Revert "ARM: shmobile: sh73a0: Replace modify_scu_cpu_psr with scu_power_mode"
Revert "ARM: shmobile: emev2: Replace modify_scu_cpu_psr with scu_power_mode"
ARM: highbank: use common debug_ll_io_init
ARM: shmobile: sh7372: sh7372_fsiXck_clk become non-global
ARM: shmobile: sh7372: remove fsidivx clock
ARM: socfpga: mark secondary_trampoline as cpuinit
socfpga: map uart into virtual address space so that early_printk() works
ARM: socfpga: fix build break for allyesconfig
ARM: socfpga: Enable SMP for socfpga
ARM: EXYNOS: Add dp clock support for EXYNOS5
ARM: SAMSUNG: call clk_get_rate for debugfs rate files
ARM: SAMSUNG: add clock_tree debugfs file in clock
24 files changed, 544 insertions, 37 deletions
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-reset.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-reset.txt new file mode 100644 index 000000000000..ecdb57d69dbf --- /dev/null +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-reset.txt @@ -0,0 +1,11 @@ +Altera SOCFPGA Reset Manager + +Required properties: +- compatible : "altr,rst-mgr" +- reg : Should contain 1 register ranges(address and length) + +Example: + rstmgr@ffd05000 { + compatible = "altr,rst-mgr"; + reg = <0xffd05000 0x1000>; + }; diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt new file mode 100644 index 000000000000..07c65e3cdcbe --- /dev/null +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt @@ -0,0 +1,11 @@ +Altera SOCFPGA System Manager + +Required properties: +- compatible : "altr,sys-mgr" +- reg : Should contain 1 register ranges(address and length) + +Example: + sysmgr@ffd08000 { + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x1000>; + }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 36d8246ea50e..2e3b6efaf1a2 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -35,6 +35,15 @@ mshc1 = &dwmmc_1; mshc2 = &dwmmc_2; mshc3 = &dwmmc_3; + i2c0 = &i2c_0; + i2c1 = &i2c_1; + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + i2c6 = &i2c_6; + i2c7 = &i2c_7; + i2c8 = &i2c_8; }; gic:interrupt-controller@10481000 { @@ -119,7 +128,7 @@ reg = <0x12170000 0x1ff>; }; - i2c@12C60000 { + i2c_0: i2c@12C60000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C60000 0x100>; interrupts = <0 56 0>; @@ -127,7 +136,7 @@ #size-cells = <0>; }; - i2c@12C70000 { + i2c_1: i2c@12C70000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C70000 0x100>; interrupts = <0 57 0>; @@ -135,7 +144,7 @@ #size-cells = <0>; }; - i2c@12C80000 { + i2c_2: i2c@12C80000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C80000 0x100>; interrupts = <0 58 0>; @@ -143,7 +152,7 @@ #size-cells = <0>; }; - i2c@12C90000 { + i2c_3: i2c@12C90000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C90000 0x100>; interrupts = <0 59 0>; @@ -151,7 +160,7 @@ #size-cells = <0>; }; - i2c@12CA0000 { + i2c_4: i2c@12CA0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CA0000 0x100>; interrupts = <0 60 0>; @@ -159,7 +168,7 @@ #size-cells = <0>; }; - i2c@12CB0000 { + i2c_5: i2c@12CB0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CB0000 0x100>; interrupts = <0 61 0>; @@ -167,7 +176,7 @@ #size-cells = <0>; }; - i2c@12CC0000 { + i2c_6: i2c@12CC0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CC0000 0x100>; interrupts = <0 62 0>; @@ -175,7 +184,7 @@ #size-cells = <0>; }; - i2c@12CD0000 { + i2c_7: i2c@12CD0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CD0000 0x100>; interrupts = <0 63 0>; @@ -183,7 +192,7 @@ #size-cells = <0>; }; - i2c@12CE0000 { + i2c_8: i2c@12CE0000 { compatible = "samsung,s3c2440-hdmiphy-i2c"; reg = <0x12CE0000 0x1000>; interrupts = <0 64 0>; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 0772f5739f59..19aec421bb26 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -143,5 +143,15 @@ reg-shift = <2>; reg-io-width = <4>; }; + + rstmgr@ffd05000 { + compatible = "altr,rst-mgr"; + reg = <0xffd05000 0x1000>; + }; + + sysmgr@ffd08000 { + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 0ac1293dba10..4e1ce211d43f 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -18,9 +18,10 @@ CONFIG_MODULE_UNLOAD=y CONFIG_ARCH_SOCFPGA=y CONFIG_MACH_SOCFPGA_CYCLONE5=y CONFIG_ARM_THUMBEE=y +# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set # CONFIG_CACHE_L2X0 is not set CONFIG_HIGH_RES_TIMERS=y -CONFIG_VMSPLIT_2G=y +CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c index 7652f5d78a56..e9d7b80bae49 100644 --- a/arch/arm/mach-exynos/clock-exynos5.c +++ b/arch/arm/mach-exynos/clock-exynos5.c @@ -80,6 +80,8 @@ static struct sleep_save exynos5_clock_save[] = { SAVE_ITEM(EXYNOS5_VPLL_CON0), SAVE_ITEM(EXYNOS5_VPLL_CON1), SAVE_ITEM(EXYNOS5_VPLL_CON2), + SAVE_ITEM(EXYNOS5_PWR_CTRL1), + SAVE_ITEM(EXYNOS5_PWR_CTRL2), }; #endif @@ -661,15 +663,20 @@ static struct clk exynos5_init_clocks_off[] = { .ctrlbit = (1 << 15), }, { .name = "sata", - .devname = "ahci", + .devname = "exynos5-sata", + .parent = &exynos5_clk_aclk_200.clk, .enable = exynos5_clk_ip_fsys_ctrl, .ctrlbit = (1 << 6), }, { - .name = "sata_phy", + .name = "sata-phy", + .devname = "exynos5-sata-phy", + .parent = &exynos5_clk_aclk_200.clk, .enable = exynos5_clk_ip_fsys_ctrl, .ctrlbit = (1 << 24), }, { - .name = "sata_phy_i2c", + .name = "i2c", + .devname = "exynos5-sata-phy-i2c", + .parent = &exynos5_clk_aclk_200.clk, .enable = exynos5_clk_ip_fsys_ctrl, .ctrlbit = (1 << 25), }, { @@ -693,6 +700,11 @@ static struct clk exynos5_init_clocks_off[] = { .enable = exynos5_clk_ip_disp1_ctrl, .ctrlbit = (1 << 5), }, { + .name = "dp", + .devname = "exynos-dp", + .enable = exynos5_clk_ip_disp1_ctrl, + .ctrlbit = (1 << 4), + }, { .name = "jpeg", .enable = exynos5_clk_ip_gen_ctrl, .ctrlbit = (1 << 2), @@ -1241,6 +1253,16 @@ static struct clksrc_clk exynos5_clksrcs[] = { .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 }, }, { .clk = { + .name = "sclk_sata", + .devname = "exynos5-sata", + .enable = exynos5_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 24), + }, + .sources = &exynos5_clkset_aclk, + .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 24, .size = 1 }, + .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS0, .shift = 20, .size = 4 }, + }, { + .clk = { .name = "sclk_gscl_wrap", .devname = "s5p-mipi-csis.0", .enable = exynos5_clksrc_mask_gscl_ctrl, diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 8e4ec21ef2cf..050924152776 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -21,6 +21,7 @@ #include <asm/suspend.h> #include <asm/unified.h> #include <asm/cpuidle.h> +#include <mach/regs-clock.h> #include <mach/regs-pmu.h> #include <mach/pmu.h> @@ -157,12 +158,47 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev, return exynos4_enter_core0_aftr(dev, drv, new_index); } +static void __init exynos5_core_down_clk(void) +{ + unsigned int tmp; + + /* + * Enable arm clock down (in idle) and set arm divider + * ratios in WFI/WFE state. + */ + tmp = PWR_CTRL1_CORE2_DOWN_RATIO | \ + PWR_CTRL1_CORE1_DOWN_RATIO | \ + PWR_CTRL1_DIV2_DOWN_EN | \ + PWR_CTRL1_DIV1_DOWN_EN | \ + PWR_CTRL1_USE_CORE1_WFE | \ + PWR_CTRL1_USE_CORE0_WFE | \ + PWR_CTRL1_USE_CORE1_WFI | \ + PWR_CTRL1_USE_CORE0_WFI; + __raw_writel(tmp, EXYNOS5_PWR_CTRL1); + + /* + * Enable arm clock up (on exiting idle). Set arm divider + * ratios when not in idle along with the standby duration + * ratios. + */ + tmp = PWR_CTRL2_DIV2_UP_EN | \ + PWR_CTRL2_DIV1_UP_EN | \ + PWR_CTRL2_DUR_STANDBY2_VAL | \ + PWR_CTRL2_DUR_STANDBY1_VAL | \ + PWR_CTRL2_CORE2_UP_RATIO | \ + PWR_CTRL2_CORE1_UP_RATIO; + __raw_writel(tmp, EXYNOS5_PWR_CTRL2); +} + static int __init exynos4_init_cpuidle(void) { int i, max_cpuidle_state, cpu_id; struct cpuidle_device *device; struct cpuidle_driver *drv = &exynos4_idle_driver; + if (soc_is_exynos5250()) + exynos5_core_down_clk(); + /* Setup cpuidle driver */ drv->state_count = (sizeof(exynos4_cpuidle_set) / sizeof(struct cpuidle_state)); diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h index 8c9b38c9c504..d36ad76ad6a4 100644 --- a/arch/arm/mach-exynos/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos/include/mach/regs-clock.h @@ -267,6 +267,9 @@ #define EXYNOS5_CLKDIV_STATCPU0 EXYNOS_CLKREG(0x00600) #define EXYNOS5_CLKDIV_STATCPU1 EXYNOS_CLKREG(0x00604) +#define EXYNOS5_PWR_CTRL1 EXYNOS_CLKREG(0x01020) +#define EXYNOS5_PWR_CTRL2 EXYNOS_CLKREG(0x01024) + #define EXYNOS5_MPLL_CON0 EXYNOS_CLKREG(0x04100) #define EXYNOS5_CLKSRC_CORE1 EXYNOS_CLKREG(0x04204) @@ -344,6 +347,22 @@ #define EXYNOS5_EPLLCON0_LOCKED_SHIFT (29) +#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28) +#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16) +#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) +#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) +#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) +#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) +#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) +#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) + +#define PWR_CTRL2_DIV2_UP_EN (1 << 25) +#define PWR_CTRL2_DIV1_UP_EN (1 << 24) +#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16) +#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8) +#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4) +#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0) + /* Compatibility defines and inclusion */ #include <mach/regs-pmu.h> diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h index 84428e72cf5e..3f30aa1ae354 100644 --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h @@ -15,6 +15,7 @@ #include <mach/map.h> #define S5P_PMUREG(x) (S5P_VA_PMU + (x)) +#define S5P_SYSREG(x) (S3C_VA_SYS + (x)) #define S5P_CENTRAL_SEQ_CONFIGURATION S5P_PMUREG(0x0200) @@ -231,6 +232,8 @@ /* For EXYNOS5 */ +#define EXYNOS5_SYS_I2C_CFG S5P_SYSREG(0x0234) + #define EXYNOS5_AUTO_WDTRESET_DISABLE S5P_PMUREG(0x0408) #define EXYNOS5_MASK_WDTRESET_REQUEST S5P_PMUREG(0x040C) diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 929de766d490..f038c8cadca4 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -13,11 +13,12 @@ #include <linux/of_fdt.h> #include <linux/serial_core.h> #include <linux/memblock.h> -#include <linux/of_fdt.h> +#include <linux/io.h> #include <asm/mach/arch.h> #include <asm/hardware/gic.h> #include <mach/map.h> +#include <mach/regs-pmu.h> #include <plat/cpu.h> #include <plat/regs-serial.h> @@ -124,6 +125,28 @@ static void __init exynos5_dt_map_io(void) static void __init exynos5_dt_machine_init(void) { + struct device_node *i2c_np; + const char *i2c_compat = "samsung,s3c2440-i2c"; + unsigned int tmp; + + /* + * Exynos5's legacy i2c controller and new high speed i2c + * controller have muxed interrupt sources. By default the + * interrupts for 4-channel HS-I2C controller are enabled. + * If node for first four channels of legacy i2c controller + * are available then re-configure the interrupts via the + * system register. + */ + for_each_compatible_node(i2c_np, NULL, i2c_compat) { + if (of_device_is_available(i2c_np)) { + if (of_alias_get_id(i2c_np, "i2c") < 4) { + tmp = readl(EXYNOS5_SYS_I2C_CFG); + writel(tmp & ~(0x1 << of_alias_get_id(i2c_np, "i2c")), + EXYNOS5_SYS_I2C_CFG); + } + } + } + if (of_machine_is_compatible("samsung,exynos5250")) of_platform_populate(NULL, of_default_bus_match_table, exynos5250_auxdata_lookup, NULL); diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 8df6ec547f78..b9b539cac81e 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -62,6 +62,10 @@ static struct sleep_save exynos4_vpll_save[] = { SAVE_ITEM(EXYNOS4_VPLL_CON1), }; +static struct sleep_save exynos5_sys_save[] = { + SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), +}; + static struct sleep_save exynos_core_save[] = { /* SROM side */ SAVE_ITEM(S5P_SROM_BW), @@ -101,6 +105,7 @@ static void exynos_pm_prepare(void) s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); } else { + s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); /* Disable USE_RETENTION of JPEG_MEM_OPTION */ tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); tmp &= ~EXYNOS5_OPTION_USE_RETENTION; @@ -304,6 +309,10 @@ static void exynos_pm_resume(void) __raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); __raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); + if (soc_is_exynos5250()) + s3c_pm_do_restore(exynos5_sys_save, + ARRAY_SIZE(exynos5_sys_save)); + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); if (!soc_is_exynos5250()) { diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 4d57e342537b..3ca6757b129a 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -295,10 +295,10 @@ struct clk sh7372_pllc2_clk = { }; /* External input clock (pin name: FSIACK/FSIBCK ) */ -struct clk sh7372_fsiack_clk = { +static struct clk fsiack_clk = { }; -struct clk sh7372_fsibck_clk = { +static struct clk fsibck_clk = { }; static struct clk *main_clks[] = { @@ -314,8 +314,8 @@ static struct clk *main_clks[] = { &pllc1_clk, &pllc1_div2_clk, &sh7372_pllc2_clk, - &sh7372_fsiack_clk, - &sh7372_fsibck_clk, + &fsiack_clk, + &fsibck_clk, }; static void div4_kick(struct clk *clk) @@ -399,14 +399,14 @@ static struct clk *hdmi_parent[] = { static struct clk *fsiackcr_parent[] = { [0] = &pllc1_div2_clk, [1] = &sh7372_pllc2_clk, - [2] = &sh7372_fsiack_clk, /* external input for FSI A */ + [2] = &fsiack_clk, /* external input for FSI A */ [3] = NULL, /* setting prohibited */ }; static struct clk *fsibckcr_parent[] = { [0] = &pllc1_div2_clk, [1] = &sh7372_pllc2_clk, - [2] = &sh7372_fsibck_clk, /* external input for FSI B */ + [2] = &fsibck_clk, /* external input for FSI B */ [3] = NULL, /* setting prohibited */ }; @@ -507,8 +507,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), CLKDEV_CON_ID("pllc2_clk", &sh7372_pllc2_clk), - CLKDEV_CON_ID("fsidiva", &fsidivs[FSIDIV_A]), - CLKDEV_CON_ID("fsidivb", &fsidivs[FSIDIV_B]), + CLKDEV_CON_ID("fsiack", &fsiack_clk), + CLKDEV_CON_ID("fsibck", &fsibck_clk), /* DIV4 clocks */ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), @@ -606,8 +606,8 @@ static struct clk_lookup lookups[] = { CLKDEV_ICK_ID("spu2", "sh_fsi2", &mstp_clks[MSTP223]), CLKDEV_ICK_ID("diva", "sh_fsi2", &fsidivs[FSIDIV_A]), CLKDEV_ICK_ID("divb", "sh_fsi2", &fsidivs[FSIDIV_B]), - CLKDEV_ICK_ID("xcka", "sh_fsi2", &sh7372_fsiack_clk), - CLKDEV_ICK_ID("xckb", "sh_fsi2", &sh7372_fsibck_clk), + CLKDEV_ICK_ID("xcka", "sh_fsi2", &fsiack_clk), + CLKDEV_ICK_ID("xckb", "sh_fsi2", &fsibck_clk), }; void __init sh7372_clock_init(void) diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 26cd1016fad8..b582facc1cf6 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h @@ -477,8 +477,6 @@ extern struct clk sh7372_extal2_clk; extern struct clk sh7372_dv_clki_clk; extern struct clk sh7372_dv_clki_div2_clk; extern struct clk sh7372_pllc2_clk; -extern struct clk sh7372_fsiack_clk; -extern struct clk sh7372_fsibck_clk; extern void sh7372_intcs_suspend(void); extern void sh7372_intcs_resume(void); diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 535426c306bd..f67456286280 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -32,8 +32,24 @@ #define EMEV2_SCU_BASE 0x1e000000 +static DEFINE_SPINLOCK(scu_lock); static void __iomem *scu_base; +static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) +{ + unsigned long tmp; + + /* we assume this code is running on a different cpu + * than the one that is changing coherency setting */ + spin_lock(&scu_lock); + tmp = readl(scu_base + 8); + tmp &= ~clr; + tmp |= set; + writel(tmp, scu_base + 8); + spin_unlock(&scu_lock); + +} + static unsigned int __init emev2_get_core_count(void) { if (!scu_base) { @@ -79,7 +95,7 @@ static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct * cpu = cpu_logical_map(cpu); /* enable cache coherency */ - scu_power_mode(scu_base, 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); /* Tell ROM loader about our vector (in headsmp.S) */ emev2_set_boot_vector(__pa(shmobile_secondary_vector)); @@ -90,10 +106,12 @@ static int __cpuinit emev2_boot_secondary(unsigned int cpu, struct task_struct * static void __init emev2_smp_prepare_cpus(unsigned int max_cpus) { + int cpu = cpu_logical_map(0); + scu_enable(scu_base); /* enable cache coherency on CPU0 */ - scu_power_mode(scu_base, 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); } static void __init emev2_smp_init_cpus(void) diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 9def0f22bf22..2ce6af9a6a37 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -61,6 +61,9 @@ static void __iomem *scu_base_addr(void) return (void __iomem *)0xf0000000; } +static DEFINE_SPINLOCK(scu_lock); +static unsigned long tmp; + #ifdef CONFIG_HAVE_ARM_TWD static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); @@ -70,6 +73,20 @@ void __init r8a7779_register_twd(void) } #endif +static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) +{ + void __iomem *scu_base = scu_base_addr(); + + spin_lock(&scu_lock); + tmp = __raw_readl(scu_base + 8); + tmp &= ~clr; + tmp |= set; + spin_unlock(&scu_lock); + + /* disable cache coherency after releasing the lock */ + __raw_writel(tmp, scu_base + 8); +} + static unsigned int __init r8a7779_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); @@ -85,7 +102,7 @@ static int r8a7779_platform_cpu_kill(unsigned int cpu) cpu = cpu_logical_map(cpu); /* disable cache coherency */ - scu_power_mode(scu_base_addr(), 3); + modify_scu_cpu_psr(3 << (cpu * 8), 0); if (cpu < ARRAY_SIZE(r8a7779_ch_cpu)) ch = r8a7779_ch_cpu[cpu]; @@ -128,7 +145,7 @@ static int __cpuinit r8a7779_boot_secondary(unsigned int cpu, struct task_struct cpu = cpu_logical_map(cpu); /* enable cache coherency */ - scu_power_mode(scu_base_addr(), 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); if (cpu < ARRAY_SIZE(r8a7779_ch_cpu)) ch = r8a7779_ch_cpu[cpu]; @@ -141,13 +158,15 @@ static int __cpuinit r8a7779_boot_secondary(unsigned int cpu, struct task_struct static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus) { + int cpu = cpu_logical_map(0); + scu_enable(scu_base_addr()); /* Map the reset vector (in headsmp.S) */ __raw_writel(__pa(shmobile_secondary_vector), AVECR); /* enable cache coherency on CPU0 */ - scu_power_mode(scu_base_addr(), 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); r8a7779_pm_init(); diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 96ddb97babbe..624f00f70abf 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -41,6 +41,9 @@ static void __iomem *scu_base_addr(void) return (void __iomem *)0xf0000000; } +static DEFINE_SPINLOCK(scu_lock); +static unsigned long tmp; + #ifdef CONFIG_HAVE_ARM_TWD static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); void __init sh73a0_register_twd(void) @@ -49,6 +52,20 @@ void __init sh73a0_register_twd(void) } #endif +static void modify_scu_cpu_psr(unsigned long set, unsigned long clr) +{ + void __iomem *scu_base = scu_base_addr(); + + spin_lock(&scu_lock); + tmp = __raw_readl(scu_base + 8); + tmp &= ~clr; + tmp |= set; + spin_unlock(&scu_lock); + + /* disable cache coherency after releasing the lock */ + __raw_writel(tmp, scu_base + 8); +} + static unsigned int __init sh73a0_get_core_count(void) { void __iomem *scu_base = scu_base_addr(); @@ -66,7 +83,7 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct cpu = cpu_logical_map(cpu); /* enable cache coherency */ - scu_power_mode(scu_base_addr(), 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3) __raw_writel(1 << cpu, WUPCR); /* wake up */ @@ -78,6 +95,8 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) { + int cpu = cpu_logical_map(0); + scu_enable(scu_base_addr()); /* Map the reset vector (in headsmp.S) */ @@ -85,7 +104,7 @@ static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) __raw_writel(__pa(shmobile_secondary_vector), SBAR); /* enable cache coherency on CPU0 */ - scu_power_mode(scu_base_addr(), 0); + modify_scu_cpu_psr(0, 3 << (cpu * 8)); } static void __init sh73a0_smp_init_cpus(void) diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 803a3281feb5..566e804d4036 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -12,5 +12,6 @@ config ARCH_SOCFPGA select GENERIC_CLOCKEVENTS select GPIO_PL061 if GPIOLIB select HAVE_ARM_SCU + select HAVE_SMP select SPARSE_IRQ select USE_OF diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 4fb93240971d..6dd7a93a90fe 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -3,3 +3,4 @@ # obj-y := socfpga.o +obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h new file mode 100644 index 000000000000..9941caa94931 --- /dev/null +++ b/arch/arm/mach-socfpga/core.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Pavel Machek <pavel@denx.de> + * Copyright (C) 2012 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MACH_CORE_H +#define __MACH_CORE_H + +extern void secondary_startup(void); +extern void __iomem *socfpga_scu_base_addr; + +extern void socfpga_init_clocks(void); +extern void socfpga_sysmgr_init(void); + +extern struct smp_operations socfpga_smp_ops; +extern char secondary_trampoline, secondary_trampoline_end; + +#define SOCFPGA_SCU_VIRT_BASE 0xfffec000 + +#endif diff --git a/arch/arm/mach-socfpga/headsmp.S b/arch/arm/mach-socfpga/headsmp.S new file mode 100644 index 000000000000..f09b1283ffca --- /dev/null +++ b/arch/arm/mach-socfpga/headsmp.S @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2003 ARM Limited + * Copyright (c) u-boot contributors + * Copyright (c) 2012 Pavel Machek <pavel@denx.de> + * + * 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/linkage.h> +#include <linux/init.h> + + __CPUINIT + .arch armv7-a + +#define CPU1_START_ADDR 0xffd08010 + +ENTRY(secondary_trampoline) + movw r0, #:lower16:CPU1_START_ADDR + movt r0, #:upper16:CPU1_START_ADDR + + ldr r1, [r0] + bx r1 + +ENTRY(secondary_trampoline_end) diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c new file mode 100644 index 000000000000..68dd1b69512a --- /dev/null +++ b/arch/arm/mach-socfpga/platsmp.c @@ -0,0 +1,116 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * Copyright 2012 Pavel Machek <pavel@denx.de> + * Based on platsmp.c, Copyright (C) 2002 ARM Ltd. + * Copyright (C) 2012 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/gic.h> +#include <asm/smp_scu.h> +#include <asm/smp_plat.h> + +#include "core.h" + +extern void __iomem *sys_manager_base_addr; +extern void __iomem *rst_manager_base_addr; + +static void __cpuinit socfpga_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); +} + +static int __cpuinit socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; + + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); + + __raw_writel(virt_to_phys(secondary_startup), (sys_manager_base_addr+0x10)); + + flush_cache_all(); + smp_wmb(); + outer_clean_range(0, trampoline_size); + + /* This will release CPU #1 out of reset.*/ + __raw_writel(0, rst_manager_base_addr + 0x10); + + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init socfpga_smp_init_cpus(void) +{ + unsigned int i, ncores; + + ncores = scu_get_core_count(socfpga_scu_base_addr); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + /* sanity check */ + if (ncores > num_possible_cpus()) { + pr_warn("socfpga: no. of cores (%d) greater than configured" + "maximum of %d - clipping\n", ncores, num_possible_cpus()); + ncores = num_possible_cpus(); + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) +{ + scu_enable(socfpga_scu_base_addr); +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +static void socfpga_cpu_die(unsigned int cpu) +{ + cpu_do_idle(); + + /* We should have never returned from idle */ + panic("cpu %d unexpectedly exit from shutdown\n", cpu); +} + +struct smp_operations socfpga_smp_ops __initdata = { + .smp_init_cpus = socfpga_smp_init_cpus, + .smp_prepare_cpus = socfpga_smp_prepare_cpus, + .smp_secondary_init = socfpga_secondary_init, + .smp_boot_secondary = socfpga_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = socfpga_cpu_die, +#endif +}; diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index f01e1ebf5396..6732924a5fee 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -15,23 +15,73 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/dw_apb_timer.h> +#include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/hardware/cache-l2x0.h> #include <asm/hardware/gic.h> #include <asm/mach/arch.h> +#include <asm/mach/map.h> -extern void socfpga_init_clocks(void); +#include "core.h" + +void __iomem *socfpga_scu_base_addr = ((void __iomem *)(SOCFPGA_SCU_VIRT_BASE)); +void __iomem *sys_manager_base_addr; +void __iomem *rst_manager_base_addr; + +static struct map_desc scu_io_desc __initdata = { + .virtual = SOCFPGA_SCU_VIRT_BASE, + .pfn = 0, /* run-time */ + .length = SZ_8K, + .type = MT_DEVICE, +}; + +static struct map_desc uart_io_desc __initdata = { + .virtual = 0xfec02000, + .pfn = __phys_to_pfn(0xffc02000), + .length = SZ_8K, + .type = MT_DEVICE, +}; + +static void __init socfpga_scu_map_io(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); +} + +static void __init socfpga_map_io(void) +{ + socfpga_scu_map_io(); + iotable_init(&uart_io_desc, 1); + early_printk("Early printk initialized\n"); +} const static struct of_device_id irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, {} }; +void __init socfpga_sysmgr_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "altr,sys-mgr"); + sys_manager_base_addr = of_iomap(np, 0); + + np = of_find_compatible_node(NULL, NULL, "altr,rst-mgr"); + rst_manager_base_addr = of_iomap(np, 0); +} + static void __init gic_init_irq(void) { of_irq_init(irq_match); + socfpga_sysmgr_init(); } static void socfpga_cyclone5_restart(char mode, const char *cmd) @@ -53,6 +103,8 @@ static const char *altera_dt_match[] = { }; DT_MACHINE_START(SOCFPGA, "Altera SOCFPGA") + .smp = smp_ops(socfpga_smp_ops), + .map_io = socfpga_map_io, .init_irq = gic_init_irq, .handle_irq = gic_handle_irq, .timer = &dw_apb_timer, diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c index 012bbd0b8d81..47c9fad43f00 100644 --- a/arch/arm/plat-samsung/clock.c +++ b/arch/arm/plat-samsung/clock.c @@ -389,6 +389,72 @@ int __init s3c24xx_register_baseclocks(unsigned long xtal) static struct dentry *clk_debugfs_root; +static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) +{ + struct clk *child; + const char *state; + char buf[255] = { 0 }; + int n = 0; + + if (c->name) + n = snprintf(buf, sizeof(buf) - 1, "%s", c->name); + + if (c->devname) + n += snprintf(buf + n, sizeof(buf) - 1 - n, ":%s", c->devname); + + state = (c->usage > 0) ? "on" : "off"; + + seq_printf(s, "%*s%-*s %-6s %-3d %-10lu\n", + level * 3 + 1, "", + 50 - level * 3, buf, + state, c->usage, clk_get_rate(c)); + + list_for_each_entry(child, &clocks, list) { + if (child->parent != c) + continue; + + clock_tree_show_one(s, child, level + 1); + } +} + +static int clock_tree_show(struct seq_file *s, void *data) +{ + struct clk *c; + unsigned long flags; + + seq_printf(s, " clock state ref rate\n"); + seq_printf(s, "----------------------------------------------------\n"); + + spin_lock_irqsave(&clocks_lock, flags); + + list_for_each_entry(c, &clocks, list) + if (c->parent == NULL) + clock_tree_show_one(s, c, 0); + + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} + +static int clock_tree_open(struct inode *inode, struct file *file) +{ + return single_open(file, clock_tree_show, inode->i_private); +} + +static const struct file_operations clock_tree_fops = { + .open = clock_tree_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int clock_rate_show(void *data, u64 *val) +{ + struct clk *c = data; + *val = clk_get_rate(c); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_rate_show, NULL, "%llu\n"); + static int clk_debugfs_register_one(struct clk *c) { int err; @@ -411,7 +477,7 @@ static int clk_debugfs_register_one(struct clk *c) goto err_out; } - d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); + d = debugfs_create_file("rate", S_IRUGO, c->dent, c, &clock_rate_fops); if (!d) { err = -ENOMEM; goto err_out; @@ -446,13 +512,18 @@ static int __init clk_debugfs_init(void) { struct clk *c; struct dentry *d; - int err; + int err = -ENOMEM; d = debugfs_create_dir("clock", NULL); if (!d) return -ENOMEM; clk_debugfs_root = d; + d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL, + &clock_tree_fops); + if (!d) + goto err_out; + list_for_each_entry(c, &clocks, list) { err = clk_debugfs_register(c); if (err) diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index b3dc44146ca0..5aedcdf4ac5c 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -401,7 +401,6 @@ static int fsidiv_enable(struct clk *clk) static int fsidiv_set_rate(struct clk *clk, unsigned long rate) { - u32 val; int idx; idx = (clk->parent->rate / rate) & 0xffff; |