diff options
author | Mike Turquette <mturquette@linaro.org> | 2014-07-31 09:32:18 -0700 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-07-31 09:32:18 -0700 |
commit | d7d3d26fa5446fc74e2c52504d827bda89b7b03e (patch) | |
tree | 209f3a0fe71af5a97ece45cee40c7e1a4f5495f3 /drivers/clk | |
parent | abeab450bfe823079c8a3abf5123f41a0da62392 (diff) | |
parent | f65d518942325d4bfa74b5c9d42ea5a89e4f6943 (diff) | |
download | lwn-d7d3d26fa5446fc74e2c52504d827bda89b7b03e.tar.gz lwn-d7d3d26fa5446fc74e2c52504d827bda89b7b03e.zip |
Merge tag 'for_3.17/samsung-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tfiga/samsung-clk into clk-next-samsung
Samsung clock patches for 3.17
1) non-critical fixes (without need to push to stable):
d5e136a clk: samsung: Register clk provider only after registering its all clocks
305cfab clk: samsung: Make of_device_id array const
e9d5295 clk: samsung: exynos5420: Setup clocks before system suspend
f65d518 clk: samsung: trivial: Correct typo in author's name
2) Exynos CLKOUT driver:
800c979 clk: samsung: exynos4: Add missing CPU/DMC clock hierarchy
01f7ec2 clk: samsung: exynos4: Add CLKOUT clock hierarchy
1e832e5 clk: samsung: Add driver to control CLKOUT line on Exynos SoCs
d19bb39 ARM: dts: exynos: Update PMU node with CLKOUT related data
3) Clock hierarchy extensions:
17d3f1d clk: exynos4: Add PPMU IP block source clocks.
ca5b402 clk: samsung: register exynos5420 apll/kpll configuration data
4) ARM CLKDOWN functionality enablement for Exynos4 and 3250:
42773b2 clk: samsung: exynos4: Enable ARMCLK down feature
45c5b0a clk: samsung: exynos3250: Enable ARMCLK down feature
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/samsung/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos-clkout.c | 153 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos3250.c | 43 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos4.c | 231 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5250.c | 4 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5260.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5410.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5420.c | 61 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5440.c | 4 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c2410.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c2412.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c2443.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c64xx.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.c | 21 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.h | 4 |
15 files changed, 519 insertions, 15 deletions
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 69e81773164e..2949a556af8f 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o +obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c new file mode 100644 index 000000000000..3a7cb2506731 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Tomasz Figa <t.figa@samsung.com> + * + * 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. + * + * Clock driver for Exynos clock output + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/syscore_ops.h> + +#define EXYNOS_CLKOUT_NR_CLKS 1 +#define EXYNOS_CLKOUT_PARENTS 32 + +#define EXYNOS_PMU_DEBUG_REG 0xa00 +#define EXYNOS_CLKOUT_DISABLE_SHIFT 0 +#define EXYNOS_CLKOUT_MUX_SHIFT 8 +#define EXYNOS4_CLKOUT_MUX_MASK 0xf +#define EXYNOS5_CLKOUT_MUX_MASK 0x1f + +struct exynos_clkout { + struct clk_gate gate; + struct clk_mux mux; + spinlock_t slock; + struct clk_onecell_data data; + struct clk *clk_table[EXYNOS_CLKOUT_NR_CLKS]; + void __iomem *reg; + u32 pmu_debug_save; +}; + +static struct exynos_clkout *clkout; + +static int exynos_clkout_suspend(void) +{ + clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG); + + return 0; +} + +static void exynos_clkout_resume(void) +{ + writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG); +} + +static struct syscore_ops exynos_clkout_syscore_ops = { + .suspend = exynos_clkout_suspend, + .resume = exynos_clkout_resume, +}; + +static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask) +{ + const char *parent_names[EXYNOS_CLKOUT_PARENTS]; + struct clk *parents[EXYNOS_CLKOUT_PARENTS]; + int parent_count; + int ret; + int i; + + clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); + if (!clkout) + return; + + spin_lock_init(&clkout->slock); + + parent_count = 0; + for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i) { + char name[] = "clkoutXX"; + + snprintf(name, sizeof(name), "clkout%d", i); + parents[i] = of_clk_get_by_name(node, name); + if (IS_ERR(parents[i])) { + parent_names[i] = "none"; + continue; + } + + parent_names[i] = __clk_get_name(parents[i]); + parent_count = i + 1; + } + + if (!parent_count) + goto free_clkout; + + clkout->reg = of_iomap(node, 0); + if (!clkout->reg) + goto clks_put; + + clkout->gate.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG; + clkout->gate.bit_idx = EXYNOS_CLKOUT_DISABLE_SHIFT; + clkout->gate.flags = CLK_GATE_SET_TO_DISABLE; + clkout->gate.lock = &clkout->slock; + + clkout->mux.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG; + clkout->mux.mask = mux_mask; + clkout->mux.shift = EXYNOS_CLKOUT_MUX_SHIFT; + clkout->mux.lock = &clkout->slock; + + clkout->clk_table[0] = clk_register_composite(NULL, "clkout", + parent_names, parent_count, &clkout->mux.hw, + &clk_mux_ops, NULL, NULL, &clkout->gate.hw, + &clk_gate_ops, CLK_SET_RATE_PARENT + | CLK_SET_RATE_NO_REPARENT); + if (IS_ERR(clkout->clk_table[0])) + goto err_unmap; + + clkout->data.clks = clkout->clk_table; + clkout->data.clk_num = EXYNOS_CLKOUT_NR_CLKS; + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &clkout->data); + if (ret) + goto err_clk_unreg; + + register_syscore_ops(&exynos_clkout_syscore_ops); + + return; + +err_clk_unreg: + clk_unregister(clkout->clk_table[0]); +err_unmap: + iounmap(clkout->reg); +clks_put: + for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i) + if (!IS_ERR(parents[i])) + clk_put(parents[i]); +free_clkout: + kfree(clkout); + + pr_err("%s: failed to register clkout clock\n", __func__); +} + +static void __init exynos4_clkout_init(struct device_node *node) +{ + exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK); +} +CLK_OF_DECLARE(exynos4210_clkout, "samsung,exynos4210-pmu", + exynos4_clkout_init); +CLK_OF_DECLARE(exynos4212_clkout, "samsung,exynos4212-pmu", + exynos4_clkout_init); +CLK_OF_DECLARE(exynos4412_clkout, "samsung,exynos4412-pmu", + exynos4_clkout_init); + +static void __init exynos5_clkout_init(struct device_node *node) +{ + exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK); +} +CLK_OF_DECLARE(exynos5250_clkout, "samsung,exynos5250-pmu", + exynos5_clkout_init); +CLK_OF_DECLARE(exynos5420_clkout, "samsung,exynos5420-pmu", + exynos5_clkout_init); diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 7a17bd40d1dd..dc85f8e7a2d7 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -87,6 +87,22 @@ #define SRC_CPU 0x14200 #define DIV_CPU0 0x14500 #define DIV_CPU1 0x14504 +#define PWR_CTRL1 0x15020 +#define PWR_CTRL2 0x15024 + +/* Below definitions are used for PWR_CTRL settings */ +#define PWR_CTRL1_CORE2_DOWN_RATIO(x) (((x) & 0x7) << 28) +#define PWR_CTRL1_CORE1_DOWN_RATIO(x) (((x) & 0x7) << 16) +#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) +#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) +#define PWR_CTRL1_USE_CORE3_WFE (1 << 7) +#define PWR_CTRL1_USE_CORE2_WFE (1 << 6) +#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) +#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) +#define PWR_CTRL1_USE_CORE3_WFI (1 << 3) +#define PWR_CTRL1_USE_CORE2_WFI (1 << 2) +#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) +#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) /* list of PLLs to be registered */ enum exynos3250_plls { @@ -168,6 +184,8 @@ static unsigned long exynos3250_cmu_clk_regs[] __initdata = { SRC_CPU, DIV_CPU0, DIV_CPU1, + PWR_CTRL1, + PWR_CTRL2, }; static int exynos3250_clk_suspend(void) @@ -748,6 +766,27 @@ static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = { UPLL_LOCK, UPLL_CON0, NULL), }; +static void __init exynos3_core_down_clock(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(7) | PWR_CTRL1_CORE1_DOWN_RATIO(7) | + 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, reg_base + PWR_CTRL1); + + /* + * Disable the clock up feature on Exynos4x12, in case it was + * enabled by bootloader. + */ + __raw_writel(0x0, reg_base + PWR_CTRL2); +} + static void __init exynos3250_cmu_init(struct device_node *np) { struct samsung_clk_provider *ctx; @@ -775,6 +814,10 @@ static void __init exynos3250_cmu_init(struct device_node *np) samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks)); samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks)); + exynos3_core_down_clock(); + exynos3250_clk_sleep_init(); + + samsung_clk_of_add_provider(np, ctx); } CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 7f4a473a7ad7..ac163d7f5bc3 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -25,10 +25,12 @@ #define DIV_LEFTBUS 0x4500 #define GATE_IP_LEFTBUS 0x4800 #define E4X12_GATE_IP_IMAGE 0x4930 +#define CLKOUT_CMU_LEFTBUS 0x4a00 #define SRC_RIGHTBUS 0x8200 #define DIV_RIGHTBUS 0x8500 #define GATE_IP_RIGHTBUS 0x8800 #define E4X12_GATE_IP_PERIR 0x8960 +#define CLKOUT_CMU_RIGHTBUS 0x8a00 #define EPLL_LOCK 0xc010 #define VPLL_LOCK 0xc020 #define EPLL_CON0 0xc110 @@ -98,6 +100,7 @@ #define GATE_IP_PERIL 0xc950 #define E4210_GATE_IP_PERIR 0xc960 #define GATE_BLOCK 0xc970 +#define CLKOUT_CMU_TOP 0xca00 #define E4X12_MPLL_LOCK 0x10008 #define E4X12_MPLL_CON0 0x10108 #define SRC_DMC 0x10200 @@ -105,6 +108,7 @@ #define DIV_DMC0 0x10500 #define DIV_DMC1 0x10504 #define GATE_IP_DMC 0x10900 +#define CLKOUT_CMU_DMC 0x10a00 #define APLL_LOCK 0x14000 #define E4210_MPLL_LOCK 0x14008 #define APLL_CON0 0x14100 @@ -114,11 +118,28 @@ #define DIV_CPU1 0x14504 #define GATE_SCLK_CPU 0x14800 #define GATE_IP_CPU 0x14900 +#define CLKOUT_CMU_CPU 0x14a00 +#define PWR_CTRL1 0x15020 +#define E4X12_PWR_CTRL2 0x15024 #define E4X12_DIV_ISP0 0x18300 #define E4X12_DIV_ISP1 0x18304 #define E4X12_GATE_ISP0 0x18800 #define E4X12_GATE_ISP1 0x18804 +/* Below definitions are used for PWR_CTRL settings */ +#define PWR_CTRL1_CORE2_DOWN_RATIO(x) (((x) & 0x7) << 28) +#define PWR_CTRL1_CORE1_DOWN_RATIO(x) (((x) & 0x7) << 16) +#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) +#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) +#define PWR_CTRL1_USE_CORE3_WFE (1 << 7) +#define PWR_CTRL1_USE_CORE2_WFE (1 << 6) +#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) +#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) +#define PWR_CTRL1_USE_CORE3_WFI (1 << 3) +#define PWR_CTRL1_USE_CORE2_WFI (1 << 2) +#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) +#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) + /* the exynos4 soc type */ enum exynos4_soc { EXYNOS4210, @@ -155,6 +176,7 @@ static unsigned long exynos4210_clk_save[] __initdata = { E4210_GATE_IP_LCD1, E4210_GATE_IP_PERIR, E4210_MPLL_CON0, + PWR_CTRL1, }; static unsigned long exynos4x12_clk_save[] __initdata = { @@ -164,6 +186,8 @@ static unsigned long exynos4x12_clk_save[] __initdata = { E4X12_DIV_ISP, E4X12_DIV_CAM1, E4X12_MPLL_CON0, + PWR_CTRL1, + E4X12_PWR_CTRL2, }; static unsigned long exynos4_clk_pll_regs[] __initdata = { @@ -242,6 +266,11 @@ static unsigned long exynos4_clk_regs[] __initdata = { DIV_CPU1, GATE_SCLK_CPU, GATE_IP_CPU, + CLKOUT_CMU_LEFTBUS, + CLKOUT_CMU_RIGHTBUS, + CLKOUT_CMU_TOP, + CLKOUT_CMU_DMC, + CLKOUT_CMU_CPU, }; static const struct samsung_clk_reg_dump src_mask_suspend[] = { @@ -397,10 +426,32 @@ PNAME(mout_audio2_p4210) = { "cdclk2", "none", "sclk_hdmi24m", "sclk_epll", "sclk_vpll", }; PNAME(mout_mixer_p4210) = { "sclk_dac", "sclk_hdmi", }; PNAME(mout_dac_p4210) = { "sclk_vpll", "sclk_hdmiphy", }; +PNAME(mout_pwi_p4210) = { "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0", + "sclk_usbphy1", "sclk_hdmiphy", "none", + "sclk_epll", "sclk_vpll" }; +PNAME(clkout_left_p4210) = { "sclk_mpll_div_2", "sclk_apll_div_2", + "div_gdl", "div_gpl" }; +PNAME(clkout_right_p4210) = { "sclk_mpll_div_2", "sclk_apll_div_2", + "div_gdr", "div_gpr" }; +PNAME(clkout_top_p4210) = { "fout_epll", "fout_vpll", "sclk_hdmi24m", + "sclk_usbphy0", "sclk_usbphy1", "sclk_hdmiphy", + "cdclk0", "cdclk1", "cdclk2", "spdif_extclk", + "aclk160", "aclk133", "aclk200", "aclk100", + "sclk_mfc", "sclk_g3d", "sclk_g2d", + "cam_a_pclk", "cam_b_pclk", "s_rxbyteclkhs0_2l", + "s_rxbyteclkhs0_4l" }; +PNAME(clkout_dmc_p4210) = { "div_dmcd", "div_dmcp", "div_acp_pclk", "div_dmc", + "div_dphy", "none", "div_pwi" }; +PNAME(clkout_cpu_p4210) = { "fout_apll_div_2", "none", "fout_mpll_div_2", + "none", "arm_clk_div_2", "div_corem0", + "div_corem1", "div_corem0", "div_atb", + "div_periph", "div_pclk_dbg", "div_hpm" }; /* Exynos 4x12-specific parent groups */ PNAME(mout_mpll_user_p4x12) = { "fin_pll", "sclk_mpll", }; PNAME(mout_core_p4x12) = { "mout_apll", "mout_mpll_user_c", }; +PNAME(mout_gdl_p4x12) = { "mout_mpll_user_l", "sclk_apll", }; +PNAME(mout_gdr_p4x12) = { "mout_mpll_user_r", "sclk_apll", }; PNAME(sclk_ampll_p4x12) = { "mout_mpll_user_t", "sclk_apll", }; PNAME(group1_p4x12) = { "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0", "none", "sclk_hdmiphy", "mout_mpll_user_t", @@ -418,6 +469,32 @@ PNAME(aclk_p4412) = { "mout_mpll_user_t", "sclk_apll", }; PNAME(mout_user_aclk400_mcuisp_p4x12) = {"fin_pll", "div_aclk400_mcuisp", }; PNAME(mout_user_aclk200_p4x12) = {"fin_pll", "div_aclk200", }; PNAME(mout_user_aclk266_gps_p4x12) = {"fin_pll", "div_aclk266_gps", }; +PNAME(mout_pwi_p4x12) = { "xxti", "xusbxti", "sclk_hdmi24m", "sclk_usbphy0", + "none", "sclk_hdmiphy", "sclk_mpll", + "sclk_epll", "sclk_vpll" }; +PNAME(clkout_left_p4x12) = { "sclk_mpll_user_l_div_2", "sclk_apll_div_2", + "div_gdl", "div_gpl" }; +PNAME(clkout_right_p4x12) = { "sclk_mpll_user_r_div_2", "sclk_apll_div_2", + "div_gdr", "div_gpr" }; +PNAME(clkout_top_p4x12) = { "fout_epll", "fout_vpll", "sclk_hdmi24m", + "sclk_usbphy0", "none", "sclk_hdmiphy", + "cdclk0", "cdclk1", "cdclk2", "spdif_extclk", + "aclk160", "aclk133", "aclk200", "aclk100", + "sclk_mfc", "sclk_g3d", "aclk400_mcuisp", + "cam_a_pclk", "cam_b_pclk", "s_rxbyteclkhs0_2l", + "s_rxbyteclkhs0_4l", "rx_half_byte_clk_csis0", + "rx_half_byte_clk_csis1", "div_jpeg", + "sclk_pwm_isp", "sclk_spi0_isp", + "sclk_spi1_isp", "sclk_uart_isp", + "sclk_mipihsi", "sclk_hdmi", "sclk_fimd0", + "sclk_pcm0" }; +PNAME(clkout_dmc_p4x12) = { "div_dmcd", "div_dmcp", "aclk_acp", "div_acp_pclk", + "div_dmc", "div_dphy", "fout_mpll_div_2", + "div_pwi", "none", "div_c2c", "div_c2c_aclk" }; +PNAME(clkout_cpu_p4x12) = { "fout_apll_div_2", "none", "none", "none", + "arm_clk_div_2", "div_corem0", "div_corem1", + "div_cores", "div_atb", "div_periph", + "div_pclk_dbg", "div_hpm" }; /* fixed rate clocks generated outside the soc */ static struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata = { @@ -436,6 +513,24 @@ static struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = FRATE(0, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000), }; +static struct samsung_fixed_factor_clock exynos4_fixed_factor_clks[] __initdata = { + FFACTOR(0, "sclk_apll_div_2", "sclk_apll", 1, 2, 0), + FFACTOR(0, "fout_mpll_div_2", "fout_mpll", 1, 2, 0), + FFACTOR(0, "fout_apll_div_2", "fout_apll", 1, 2, 0), + FFACTOR(0, "arm_clk_div_2", "arm_clk", 1, 2, 0), +}; + +static struct samsung_fixed_factor_clock exynos4210_fixed_factor_clks[] __initdata = { + FFACTOR(0, "sclk_mpll_div_2", "sclk_mpll", 1, 2, 0), +}; + +static struct samsung_fixed_factor_clock exynos4x12_fixed_factor_clks[] __initdata = { + FFACTOR(0, "sclk_mpll_user_l_div_2", "mout_mpll_user_l", 1, 2, 0), + FFACTOR(0, "sclk_mpll_user_r_div_2", "mout_mpll_user_r", 1, 2, 0), + FFACTOR(0, "sclk_mpll_user_t_div_2", "mout_mpll_user_t", 1, 2, 0), + FFACTOR(0, "sclk_mpll_user_c_div_2", "mout_mpll_user_c", 1, 2, 0), +}; + /* list of mux clocks supported in all exynos4 soc's */ static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, @@ -451,6 +546,9 @@ static struct samsung_mux_clock exynos4_mux_clks[] __initdata = { MUX(0, "mout_onenand1", mout_onenand1_p, SRC_TOP0, 0, 1), MUX(CLK_SCLK_EPLL, "sclk_epll", mout_epll_p, SRC_TOP0, 4, 1), MUX(0, "mout_onenand", mout_onenand_p, SRC_TOP0, 28, 1), + + MUX(0, "mout_dmc_bus", sclk_ampll_p4210, SRC_DMC, 4, 1), + MUX(0, "mout_dphy", sclk_ampll_p4210, SRC_DMC, 8, 1), }; /* list of mux clocks supported in exynos4210 soc */ @@ -459,6 +557,14 @@ static struct samsung_mux_clock exynos4210_mux_early[] __initdata = { }; static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { + MUX(0, "mout_gdl", sclk_ampll_p4210, SRC_LEFTBUS, 0, 1), + MUX(0, "mout_clkout_leftbus", clkout_left_p4210, + CLKOUT_CMU_LEFTBUS, 0, 5), + + MUX(0, "mout_gdr", sclk_ampll_p4210, SRC_RIGHTBUS, 0, 1), + MUX(0, "mout_clkout_rightbus", clkout_right_p4210, + CLKOUT_CMU_RIGHTBUS, 0, 5), + MUX(0, "mout_aclk200", sclk_ampll_p4210, SRC_TOP0, 12, 1), MUX(0, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1), MUX(0, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1), @@ -472,6 +578,7 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { MUX(0, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4), MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1), MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4210, SRC_CPU, 16, 1), + MUX(0, "mout_hpm", mout_core_p4210, SRC_CPU, 20, 1), MUX(CLK_SCLK_VPLL, "sclk_vpll", sclk_vpll_p4210, SRC_TOP0, 8, 1), MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4), MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4), @@ -503,12 +610,30 @@ static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = { MUX(0, "mout_spi0", group1_p4210, SRC_PERIL1, 16, 4), MUX(0, "mout_spi1", group1_p4210, SRC_PERIL1, 20, 4), MUX(0, "mout_spi2", group1_p4210, SRC_PERIL1, 24, 4), + MUX(0, "mout_clkout_top", clkout_top_p4210, CLKOUT_CMU_TOP, 0, 5), + + MUX(0, "mout_pwi", mout_pwi_p4210, SRC_DMC, 16, 4), + MUX(0, "mout_clkout_dmc", clkout_dmc_p4210, CLKOUT_CMU_DMC, 0, 5), + + MUX(0, "mout_clkout_cpu", clkout_cpu_p4210, CLKOUT_CMU_CPU, 0, 5), }; /* list of mux clocks supported in exynos4x12 soc */ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = { + MUX(0, "mout_mpll_user_l", mout_mpll_p, SRC_LEFTBUS, 4, 1), + MUX(0, "mout_gdl", mout_gdl_p4x12, SRC_LEFTBUS, 0, 1), + MUX(0, "mout_clkout_leftbus", clkout_left_p4x12, + CLKOUT_CMU_LEFTBUS, 0, 5), + + MUX(0, "mout_mpll_user_r", mout_mpll_p, SRC_RIGHTBUS, 4, 1), + MUX(0, "mout_gdr", mout_gdr_p4x12, SRC_RIGHTBUS, 0, 1), + MUX(0, "mout_clkout_rightbus", clkout_right_p4x12, + CLKOUT_CMU_RIGHTBUS, 0, 5), + MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p4x12, SRC_CPU, 24, 1), + MUX(0, "mout_clkout_cpu", clkout_cpu_p4x12, CLKOUT_CMU_CPU, 0, 5), + MUX(0, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1), MUX(0, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1), MUX(CLK_MOUT_MPLL_USER_T, "mout_mpll_user_t", mout_mpll_user_p4x12, @@ -531,6 +656,7 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = { MUX(CLK_SCLK_MPLL, "sclk_mpll", mout_mpll_p, SRC_DMC, 12, 1), MUX(CLK_SCLK_VPLL, "sclk_vpll", mout_vpll_p, SRC_TOP0, 8, 1), MUX(CLK_MOUT_CORE, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1), + MUX(0, "mout_hpm", mout_core_p4x12, SRC_CPU, 20, 1), MUX(CLK_MOUT_FIMC0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4), MUX(CLK_MOUT_FIMC1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4), MUX(CLK_MOUT_FIMC2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4), @@ -565,15 +691,39 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = { MUX(0, "mout_spi0_isp", group1_p4x12, E4X12_SRC_ISP, 4, 4), MUX(0, "mout_spi1_isp", group1_p4x12, E4X12_SRC_ISP, 8, 4), MUX(0, "mout_uart_isp", group1_p4x12, E4X12_SRC_ISP, 12, 4), + MUX(0, "mout_clkout_top", clkout_top_p4x12, CLKOUT_CMU_TOP, 0, 5), + + MUX(0, "mout_c2c", sclk_ampll_p4210, SRC_DMC, 0, 1), + MUX(0, "mout_pwi", mout_pwi_p4x12, SRC_DMC, 16, 4), MUX(0, "mout_g2d0", sclk_ampll_p4210, SRC_DMC, 20, 1), MUX(0, "mout_g2d1", sclk_evpll_p, SRC_DMC, 24, 1), MUX(0, "mout_g2d", mout_g2d_p, SRC_DMC, 28, 1), + MUX(0, "mout_clkout_dmc", clkout_dmc_p4x12, CLKOUT_CMU_DMC, 0, 5), }; /* list of divider clocks supported in all exynos4 soc's */ static struct samsung_div_clock exynos4_div_clks[] __initdata = { + DIV(0, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3), + DIV(0, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3), + DIV(0, "div_clkout_leftbus", "mout_clkout_leftbus", + CLKOUT_CMU_LEFTBUS, 8, 6), + + DIV(0, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3), + DIV(0, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3), + DIV(0, "div_clkout_rightbus", "mout_clkout_rightbus", + CLKOUT_CMU_RIGHTBUS, 8, 6), + DIV(0, "div_core", "mout_core", DIV_CPU0, 0, 3), + DIV(0, "div_corem0", "div_core2", DIV_CPU0, 4, 3), + DIV(0, "div_corem1", "div_core2", DIV_CPU0, 8, 3), + DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), + DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), + DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3), + DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), + DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), + DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), + DIV(0, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4), DIV(0, "div_fimc1", "mout_fimc1", DIV_CAM, 4, 4), DIV(0, "div_fimc2", "mout_fimc2", DIV_CAM, 8, 4), @@ -631,6 +781,16 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = { CLK_SET_RATE_PARENT, 0), DIV_F(0, "div_mmc_pre3", "div_mmc3", DIV_FSYS2, 24, 8, CLK_SET_RATE_PARENT, 0), + DIV(0, "div_clkout_top", "mout_clkout_top", CLKOUT_CMU_TOP, 8, 6), + + DIV(0, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3), + DIV(0, "div_acp_pclk", "div_acp", DIV_DMC0, 4, 3), + DIV(0, "div_dphy", "mout_dphy", DIV_DMC0, 8, 3), + DIV(0, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3), + DIV(0, "div_dmcd", "div_dmc", DIV_DMC0, 16, 3), + DIV(0, "div_dmcp", "div_dmcd", DIV_DMC0, 20, 3), + DIV(0, "div_pwi", "mout_pwi", DIV_DMC1, 8, 4), + DIV(0, "div_clkout_dmc", "mout_clkout_dmc", CLKOUT_CMU_DMC, 8, 6), }; /* list of divider clocks supported in exynos4210 soc */ @@ -671,6 +831,8 @@ static struct samsung_div_clock exynos4x12_div_clks[] __initdata = { DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3, CLK_GET_RATE_NOCACHE, 0), DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4), + DIV(0, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3), + DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3), }; /* list of gate clocks supported in all exynos4 soc's */ @@ -680,6 +842,8 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { * the device name and clock alias names specified below for some * of the clocks can be removed. */ + GATE(CLK_PPMULEFT, "ppmuleft", "aclk200", GATE_IP_LEFTBUS, 1, 0, 0), + GATE(CLK_PPMURIGHT, "ppmuright", "aclk200", GATE_IP_RIGHTBUS, 1, 0, 0), GATE(CLK_SCLK_HDMI, "sclk_hdmi", "mout_hdmi", SRC_MASK_TV, 0, 0, 0), GATE(CLK_SCLK_SPDIF, "sclk_spdif", "mout_spdif", SRC_MASK_PERIL1, 8, 0, 0), @@ -695,11 +859,13 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { GATE(CLK_SROMC, "sromc", "aclk133", GATE_IP_FSYS, 11, 0, 0), GATE(CLK_SCLK_G3D, "sclk_g3d", "div_g3d", GATE_IP_G3D, 0, CLK_SET_RATE_PARENT, 0), + GATE(CLK_PPMUG3D, "ppmug3d", "aclk200", GATE_IP_G3D, 1, 0, 0), GATE(CLK_USB_DEVICE, "usb_device", "aclk133", GATE_IP_FSYS, 13, 0, 0), GATE(CLK_ONENAND, "onenand", "aclk133", GATE_IP_FSYS, 15, 0, 0), GATE(CLK_NFCON, "nfcon", "aclk133", GATE_IP_FSYS, 16, 0, 0), GATE(CLK_GPS, "gps", "aclk133", GATE_IP_GPS, 0, 0, 0), GATE(CLK_SMMU_GPS, "smmu_gps", "aclk133", GATE_IP_GPS, 1, 0, 0), + GATE(CLK_PPMUGPS, "ppmugps", "aclk200", GATE_IP_GPS, 2, 0, 0), GATE(CLK_SLIMBUS, "slimbus", "aclk100", GATE_IP_PERIL, 25, 0, 0), GATE(CLK_SCLK_CAM0, "sclk_cam0", "div_cam0", GATE_SCLK_CAM, 4, CLK_SET_RATE_PARENT, 0), @@ -781,19 +947,24 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { 0, 0), GATE(CLK_SMMU_JPEG, "smmu_jpeg", "aclk160", GATE_IP_CAM, 11, 0, 0), + GATE(CLK_PPMUCAMIF, "ppmucamif", "aclk160", GATE_IP_CAM, 16, 0, 0), GATE(CLK_PIXELASYNCM0, "pxl_async0", "aclk160", GATE_IP_CAM, 17, 0, 0), GATE(CLK_PIXELASYNCM1, "pxl_async1", "aclk160", GATE_IP_CAM, 18, 0, 0), GATE(CLK_SMMU_TV, "smmu_tv", "aclk160", GATE_IP_TV, 4, 0, 0), + GATE(CLK_PPMUTV, "ppmutv", "aclk160", GATE_IP_TV, 5, 0, 0), GATE(CLK_MFC, "mfc", "aclk100", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCL, "smmu_mfcl", "aclk100", GATE_IP_MFC, 1, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "aclk100", GATE_IP_MFC, 2, 0, 0), + GATE(CLK_PPMUMFC_L, "ppmumfc_l", "aclk100", GATE_IP_MFC, 3, 0, 0), + GATE(CLK_PPMUMFC_R, "ppmumfc_r", "aclk100", GATE_IP_MFC, 4, 0, 0), GATE(CLK_FIMD0, "fimd0", "aclk160", GATE_IP_LCD0, 0, 0, 0), GATE(CLK_SMMU_FIMD0, "smmu_fimd0", "aclk160", GATE_IP_LCD0, 4, 0, 0), + GATE(CLK_PPMULCD0, "ppmulcd0", "aclk160", GATE_IP_LCD0, 5, 0, 0), GATE(CLK_PDMA0, "pdma0", "aclk133", GATE_IP_FSYS, 0, 0, 0), GATE(CLK_PDMA1, "pdma1", "aclk133", GATE_IP_FSYS, 1, @@ -806,6 +977,7 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { 0, 0), GATE(CLK_SDMMC3, "sdmmc3", "aclk133", GATE_IP_FSYS, 8, 0, 0), + GATE(CLK_PPMUFILE, "ppmufile", "aclk133", GATE_IP_FSYS, 17, 0, 0), GATE(CLK_UART0, "uart0", "aclk100", GATE_IP_PERIL, 0, 0, 0), GATE(CLK_UART1, "uart1", "aclk100", GATE_IP_PERIL, 1, @@ -852,6 +1024,21 @@ static struct samsung_gate_clock exynos4_gate_clks[] __initdata = { 0, 0), GATE(CLK_AC97, "ac97", "aclk100", GATE_IP_PERIL, 27, 0, 0), + GATE(CLK_PPMUDMC0, "ppmudmc0", "aclk133", GATE_IP_DMC, 8, 0, 0), + GATE(CLK_PPMUDMC1, "ppmudmc1", "aclk133", GATE_IP_DMC, 9, 0, 0), + GATE(CLK_PPMUCPU, "ppmucpu", "aclk133", GATE_IP_DMC, 10, 0, 0), + GATE(CLK_PPMUACP, "ppmuacp", "aclk133", GATE_IP_DMC, 16, 0, 0), + + GATE(CLK_OUT_LEFTBUS, "clkout_leftbus", "div_clkout_leftbus", + CLKOUT_CMU_LEFTBUS, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_OUT_RIGHTBUS, "clkout_rightbus", "div_clkout_rightbus", + CLKOUT_CMU_RIGHTBUS, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_OUT_TOP, "clkout_top", "div_clkout_top", + CLKOUT_CMU_TOP, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_OUT_DMC, "clkout_dmc", "div_clkout_dmc", + CLKOUT_CMU_DMC, 16, CLK_SET_RATE_PARENT, 0), + GATE(CLK_OUT_CPU, "clkout_cpu", "div_clkout_cpu", + CLKOUT_CMU_CPU, 16, CLK_SET_RATE_PARENT, 0), }; /* list of gate clocks supported in exynos4210 soc */ @@ -863,6 +1050,9 @@ static struct samsung_gate_clock exynos4210_gate_clks[] __initdata = { GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", E4210_GATE_IP_IMAGE, 3, 0, 0), GATE(CLK_SMMU_MDMA, "smmu_mdma", "aclk200", E4210_GATE_IP_IMAGE, 5, 0, 0), + GATE(CLK_PPMUIMAGE, "ppmuimage", "aclk200", E4210_GATE_IP_IMAGE, 9, 0, + 0), + GATE(CLK_PPMULCD1, "ppmulcd1", "aclk160", E4210_GATE_IP_LCD1, 5, 0, 0), GATE(CLK_PCIE_PHY, "pcie_phy", "aclk133", GATE_IP_FSYS, 2, 0, 0), GATE(CLK_SATA_PHY, "sata_phy", "aclk133", GATE_IP_FSYS, 3, 0, 0), GATE(CLK_SATA, "sata", "aclk133", GATE_IP_FSYS, 10, 0, 0), @@ -906,6 +1096,8 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { GATE(CLK_MDMA, "mdma", "aclk200", E4X12_GATE_IP_IMAGE, 2, 0, 0), GATE(CLK_SMMU_MDMA, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0, 0), + GATE(CLK_PPMUIMAGE, "ppmuimage", "aclk200", E4X12_GATE_IP_IMAGE, 9, 0, + 0), GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0), GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0), GATE(CLK_SYSREG, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, @@ -1062,7 +1254,7 @@ static void __init exynos4_clk_register_finpll(struct samsung_clk_provider *ctx) } -static struct of_device_id ext_clk_match[] __initdata = { +static const struct of_device_id ext_clk_match[] __initconst = { { .compatible = "samsung,clock-xxti", .data = (void *)0, }, { .compatible = "samsung,clock-xusbxti", .data = (void *)1, }, {}, @@ -1164,6 +1356,32 @@ static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = { VPLL_LOCK, VPLL_CON0, NULL), }; +static void __init exynos4_core_down_clock(enum exynos4_soc soc) +{ + unsigned int tmp; + + /* + * Enable arm clock down (in idle) and set arm divider + * ratios in WFI/WFE state. + */ + tmp = (PWR_CTRL1_CORE2_DOWN_RATIO(7) | PWR_CTRL1_CORE1_DOWN_RATIO(7) | + 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); + /* On Exynos4412 enable it also on core 2 and 3 */ + if (num_possible_cpus() == 4) + tmp |= PWR_CTRL1_USE_CORE3_WFE | PWR_CTRL1_USE_CORE2_WFE | + PWR_CTRL1_USE_CORE3_WFI | PWR_CTRL1_USE_CORE2_WFI; + __raw_writel(tmp, reg_base + PWR_CTRL1); + + /* + * Disable the clock up feature on Exynos4x12, in case it was + * enabled by bootloader. + */ + if (exynos4_soc == EXYNOS4X12) + __raw_writel(0x0, reg_base + E4X12_PWR_CTRL2); +} + /* register exynos4 clocks */ static void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc soc) @@ -1224,6 +1442,8 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4_div_clks)); samsung_clk_register_gate(ctx, exynos4_gate_clks, ARRAY_SIZE(exynos4_gate_clks)); + samsung_clk_register_fixed_factor(ctx, exynos4_fixed_factor_clks, + ARRAY_SIZE(exynos4_fixed_factor_clks)); if (exynos4_soc == EXYNOS4210) { samsung_clk_register_fixed_rate(ctx, exynos4210_fixed_rate_clks, @@ -1236,6 +1456,9 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4210_gate_clks)); samsung_clk_register_alias(ctx, exynos4210_aliases, ARRAY_SIZE(exynos4210_aliases)); + samsung_clk_register_fixed_factor(ctx, + exynos4210_fixed_factor_clks, + ARRAY_SIZE(exynos4210_fixed_factor_clks)); } else { samsung_clk_register_mux(ctx, exynos4x12_mux_clks, ARRAY_SIZE(exynos4x12_mux_clks)); @@ -1245,13 +1468,19 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4x12_gate_clks)); samsung_clk_register_alias(ctx, exynos4x12_aliases, ARRAY_SIZE(exynos4x12_aliases)); + samsung_clk_register_fixed_factor(ctx, + exynos4x12_fixed_factor_clks, + ARRAY_SIZE(exynos4x12_fixed_factor_clks)); } samsung_clk_register_alias(ctx, exynos4_aliases, ARRAY_SIZE(exynos4_aliases)); + exynos4_core_down_clock(soc); exynos4_clk_sleep_init(); + samsung_clk_of_add_provider(np, ctx); + pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n" "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n", exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 184f64293b26..70ec3d2608a1 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -748,7 +748,7 @@ static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { VPLL_LOCK, VPLL_CON0, NULL), }; -static struct of_device_id ext_clk_match[] __initdata = { +static const struct of_device_id ext_clk_match[] __initconst = { { .compatible = "samsung,clock-xxti", .data = (void *)0, }, { }, }; @@ -820,6 +820,8 @@ static void __init exynos5250_clk_init(struct device_node *np) exynos5250_clk_sleep_init(); + samsung_clk_of_add_provider(np, ctx); + pr_info("Exynos5250: clock setup completed, armclk=%ld\n", _get_rate("div_arm2")); } diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 64596ba58df1..ce3de97e5f11 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -206,6 +206,8 @@ void __init exynos5260_cmu_register_one(struct device_node *np, if (cmu->clk_regs) exynos5260_clk_sleep_init(reg_base, cmu->clk_regs, cmu->nr_clk_regs); + + samsung_clk_of_add_provider(np, ctx); } diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index c9505ab9ee70..231475bc2b99 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -204,6 +204,8 @@ static void __init exynos5410_clk_init(struct device_node *np) samsung_clk_register_gate(ctx, exynos5410_gate_clks, ARRAY_SIZE(exynos5410_gate_clks)); + samsung_clk_of_add_provider(np, ctx); + pr_debug("Exynos5410: clock setup completed.\n"); } CLK_OF_DECLARE(exynos5410_clk, "samsung,exynos5410-clock", exynos5410_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 61eccf0dd72f..bc772f8585d6 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -28,6 +28,7 @@ #define GATE_BUS_CPU 0x700 #define GATE_SCLK_CPU 0x800 #define CLKOUT_CMU_CPU 0xa00 +#define SRC_MASK_CPERI 0x4300 #define GATE_IP_G2D 0x8800 #define CPLL_LOCK 0x10020 #define DPLL_LOCK 0x10030 @@ -70,6 +71,8 @@ #define SRC_TOP11 0x10284 #define SRC_TOP12 0x10288 #define SRC_TOP13 0x1028c /* 5800 specific */ +#define SRC_MASK_TOP0 0x10300 +#define SRC_MASK_TOP1 0x10304 #define SRC_MASK_TOP2 0x10308 #define SRC_MASK_TOP7 0x1031c #define SRC_MASK_DISP10 0x1032c @@ -77,6 +80,7 @@ #define SRC_MASK_FSYS 0x10340 #define SRC_MASK_PERIC0 0x10350 #define SRC_MASK_PERIC1 0x10354 +#define SRC_MASK_ISP 0x10370 #define DIV_TOP0 0x10500 #define DIV_TOP1 0x10504 #define DIV_TOP2 0x10508 @@ -98,6 +102,7 @@ #define DIV2_RATIO0 0x10590 #define DIV4_RATIO 0x105a0 #define GATE_BUS_TOP 0x10700 +#define GATE_BUS_DISP1 0x10728 #define GATE_BUS_GEN 0x1073c #define GATE_BUS_FSYS0 0x10740 #define GATE_BUS_FSYS2 0x10748 @@ -190,6 +195,10 @@ static unsigned long exynos5x_clk_regs[] __initdata = { SRC_MASK_FSYS, SRC_MASK_PERIC0, SRC_MASK_PERIC1, + SRC_MASK_TOP0, + SRC_MASK_TOP1, + SRC_MASK_MAU, + SRC_MASK_ISP, SRC_ISP, DIV_TOP0, DIV_TOP1, @@ -208,6 +217,7 @@ static unsigned long exynos5x_clk_regs[] __initdata = { SCLK_DIV_ISP1, DIV2_RATIO0, DIV4_RATIO, + GATE_BUS_DISP1, GATE_BUS_TOP, GATE_BUS_GEN, GATE_BUS_FSYS0, @@ -249,6 +259,22 @@ static unsigned long exynos5800_clk_regs[] __initdata = { GATE_IP_CAM, }; +static const struct samsung_clk_reg_dump exynos5420_set_clksrc[] = { + { .offset = SRC_MASK_CPERI, .value = 0xffffffff, }, + { .offset = SRC_MASK_TOP0, .value = 0x11111111, }, + { .offset = SRC_MASK_TOP1, .value = 0x11101111, }, + { .offset = SRC_MASK_TOP2, .value = 0x11111110, }, + { .offset = SRC_MASK_TOP7, .value = 0x00111100, }, + { .offset = SRC_MASK_DISP10, .value = 0x11111110, }, + { .offset = SRC_MASK_MAU, .value = 0x10000000, }, + { .offset = SRC_MASK_FSYS, .value = 0x11111110, }, + { .offset = SRC_MASK_PERIC0, .value = 0x11111110, }, + { .offset = SRC_MASK_PERIC1, .value = 0x11111100, }, + { .offset = SRC_MASK_ISP, .value = 0x11111000, }, + { .offset = GATE_BUS_DISP1, .value = 0xffffffff, }, + { .offset = GATE_IP_PERIC, .value = 0xffffffff, }, +}; + static int exynos5420_clk_suspend(void) { samsung_clk_save(reg_base, exynos5x_save, @@ -258,6 +284,9 @@ static int exynos5420_clk_suspend(void) samsung_clk_save(reg_base, exynos5800_save, ARRAY_SIZE(exynos5800_clk_regs)); + samsung_clk_restore(reg_base, exynos5420_set_clksrc, + ARRAY_SIZE(exynos5420_set_clksrc)); + return 0; } @@ -1167,6 +1196,28 @@ static struct samsung_gate_clock exynos5x_gate_clks[] __initdata = { GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), }; +static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] = { + PLL_35XX_RATE(2000000000, 250, 3, 0), + PLL_35XX_RATE(1900000000, 475, 6, 0), + PLL_35XX_RATE(1800000000, 225, 3, 0), + PLL_35XX_RATE(1700000000, 425, 6, 0), + PLL_35XX_RATE(1600000000, 200, 3, 0), + PLL_35XX_RATE(1500000000, 250, 4, 0), + PLL_35XX_RATE(1400000000, 175, 3, 0), + PLL_35XX_RATE(1300000000, 325, 6, 0), + PLL_35XX_RATE(1200000000, 200, 2, 1), + PLL_35XX_RATE(1100000000, 275, 3, 1), + PLL_35XX_RATE(1000000000, 250, 3, 1), + PLL_35XX_RATE(900000000, 150, 2, 1), + PLL_35XX_RATE(800000000, 200, 3, 1), + PLL_35XX_RATE(700000000, 175, 3, 1), + PLL_35XX_RATE(600000000, 200, 2, 2), + PLL_35XX_RATE(500000000, 250, 3, 2), + PLL_35XX_RATE(400000000, 200, 3, 2), + PLL_35XX_RATE(300000000, 200, 2, 3), + PLL_35XX_RATE(200000000, 200, 3, 3), +}; + static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { [apll] = PLL(pll_2550, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK, APLL_CON0, NULL), @@ -1192,7 +1243,7 @@ static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { KPLL_CON0, NULL), }; -static struct of_device_id ext_clk_match[] __initdata = { +static const struct of_device_id ext_clk_match[] __initconst = { { .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, }, { }, }; @@ -1220,6 +1271,12 @@ static void __init exynos5x_clk_init(struct device_node *np, samsung_clk_of_register_fixed_ext(ctx, exynos5x_fixed_rate_ext_clks, ARRAY_SIZE(exynos5x_fixed_rate_ext_clks), ext_clk_match); + + if (_get_rate("fin_pll") == 24 * MHZ) { + exynos5x_plls[apll].rate_table = exynos5420_pll2550x_24mhz_tbl; + exynos5x_plls[kpll].rate_table = exynos5420_pll2550x_24mhz_tbl; + } + samsung_clk_register_pll(ctx, exynos5x_plls, ARRAY_SIZE(exynos5x_plls), reg_base); samsung_clk_register_fixed_rate(ctx, exynos5x_fixed_rate_clks, @@ -1251,6 +1308,8 @@ static void __init exynos5x_clk_init(struct device_node *np, } exynos5420_clk_sleep_init(); + + samsung_clk_of_add_provider(np, ctx); } static void __init exynos5420_clk_init(struct device_node *np) diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index 647f1440aa6a..00d1d00a41de 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -84,7 +84,7 @@ static struct samsung_gate_clock exynos5440_gate_clks[] __initdata = { GATE(CLK_CS250_O, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0), }; -static struct of_device_id ext_clk_match[] __initdata = { +static const struct of_device_id ext_clk_match[] __initconst = { { .compatible = "samsung,clock-xtal", .data = (void *)0, }, {}, }; @@ -123,6 +123,8 @@ static void __init exynos5440_clk_init(struct device_node *np) samsung_clk_register_gate(ctx, exynos5440_gate_clks, ARRAY_SIZE(exynos5440_gate_clks)); + samsung_clk_of_add_provider(np, ctx); + pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk")); pr_info("exynos5440 clock initialization complete\n"); } diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index 140f4733c02e..5d2f03461bc5 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -466,6 +466,8 @@ void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, } s3c2410_clk_sleep_init(); + + samsung_clk_of_add_provider(np, ctx); } static void __init s3c2410_clk_init(struct device_node *np) diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index 23e4313f625e..34af09f6a155 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -265,6 +265,8 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, ARRAY_SIZE(s3c2412_aliases)); s3c2412_clk_sleep_init(); + + samsung_clk_of_add_provider(np, ctx); } static void __init s3c2412_clk_init(struct device_node *np) diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index c4bbdabebaa4..c92f853fca9f 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -445,6 +445,8 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, } s3c2443_clk_sleep_init(); + + samsung_clk_of_add_provider(np, ctx); } static void __init s3c2416_clk_init(struct device_node *np) diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 8889ff1c10fc..0f590e5550cb 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -518,6 +518,8 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, ARRAY_SIZE(s3c64xx_clock_aliases)); s3c64xx_clk_sleep_init(); + samsung_clk_of_add_provider(np, ctx); + pr_info("%s clocks: apll = %lu, mpll = %lu\n" "\tepll = %lu, arm_clk = %lu\n", is_s3c6400 ? "S3C6400" : "S3C6410", diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 49629c71c9e7..deab84d9f37d 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -53,7 +53,6 @@ struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np, { struct samsung_clk_provider *ctx; struct clk **clk_table; - int ret; int i; ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL); @@ -72,17 +71,19 @@ struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np, ctx->clk_data.clk_num = nr_clks; spin_lock_init(&ctx->lock); - if (!np) - return ctx; - - ret = of_clk_add_provider(np, of_clk_src_onecell_get, - &ctx->clk_data); - if (ret) - panic("could not register clock provide\n"); - return ctx; } +void __init samsung_clk_of_add_provider(struct device_node *np, + struct samsung_clk_provider *ctx) +{ + if (np) { + if (of_clk_add_provider(np, of_clk_src_onecell_get, + &ctx->clk_data)) + panic("could not register clk provider\n"); + } +} + /* add a clock instance to the clock lookup table used for dt based lookup */ void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk, unsigned int id) @@ -284,7 +285,7 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx, struct samsung_fixed_rate_clock *fixed_rate_clk, unsigned int nr_fixed_rate_clk, - struct of_device_id *clk_matches) + const struct of_device_id *clk_matches) { const struct of_device_id *match; struct device_node *clk_np; diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 9693b80d924f..66ab36b5cef1 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -327,11 +327,13 @@ struct samsung_pll_clock { extern struct samsung_clk_provider *__init samsung_clk_init( struct device_node *np, void __iomem *base, unsigned long nr_clks); +extern void __init samsung_clk_of_add_provider(struct device_node *np, + struct samsung_clk_provider *ctx); extern void __init samsung_clk_of_register_fixed_ext( struct samsung_clk_provider *ctx, struct samsung_fixed_rate_clock *fixed_rate_clk, unsigned int nr_fixed_rate_clk, - struct of_device_id *clk_matches); + const struct of_device_id *clk_matches); extern void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk, unsigned int id); |