diff options
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/samsung/clk-exynos4.c | 172 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5250.c | 49 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5420.c | 49 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5440.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c64xx.c | 79 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.c | 71 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.h | 14 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-icst.c | 21 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-icst.h | 1 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-impd1.c | 12 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-integrator.c | 83 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-realview.c | 4 | ||||
-rw-r--r-- | drivers/clk/zynq/clkc.c | 89 |
13 files changed, 470 insertions, 176 deletions
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 010f071af883..b4f967210175 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -16,6 +16,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include "clk.h" @@ -130,6 +131,17 @@ enum exynos4_plls { nr_plls /* number of PLLs */ }; +static void __iomem *reg_base; +static enum exynos4_soc exynos4_soc; + +/* + * Support for CMU save/restore across system suspends + */ +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *exynos4_save_common; +static struct samsung_clk_reg_dump *exynos4_save_soc; +static struct samsung_clk_reg_dump *exynos4_save_pll; + /* * list of controller registers to be saved and restored during a * suspend/resume cycle. @@ -154,6 +166,17 @@ static unsigned long exynos4x12_clk_save[] __initdata = { E4X12_MPLL_CON0, }; +static unsigned long exynos4_clk_pll_regs[] __initdata = { + EPLL_LOCK, + VPLL_LOCK, + EPLL_CON0, + EPLL_CON1, + EPLL_CON2, + VPLL_CON0, + VPLL_CON1, + VPLL_CON2, +}; + static unsigned long exynos4_clk_regs[] __initdata = { SRC_LEFTBUS, DIV_LEFTBUS, @@ -161,12 +184,6 @@ static unsigned long exynos4_clk_regs[] __initdata = { SRC_RIGHTBUS, DIV_RIGHTBUS, GATE_IP_RIGHTBUS, - EPLL_CON0, - EPLL_CON1, - EPLL_CON2, - VPLL_CON0, - VPLL_CON1, - VPLL_CON2, SRC_TOP0, SRC_TOP1, SRC_CAM, @@ -227,6 +244,124 @@ static unsigned long exynos4_clk_regs[] __initdata = { GATE_IP_CPU, }; +static const struct samsung_clk_reg_dump src_mask_suspend[] = { + { .offset = SRC_MASK_TOP, .value = 0x00000001, }, + { .offset = SRC_MASK_CAM, .value = 0x11111111, }, + { .offset = SRC_MASK_TV, .value = 0x00000111, }, + { .offset = SRC_MASK_LCD0, .value = 0x00001111, }, + { .offset = SRC_MASK_MAUDIO, .value = 0x00000001, }, + { .offset = SRC_MASK_FSYS, .value = 0x01011111, }, + { .offset = SRC_MASK_PERIL0, .value = 0x01111111, }, + { .offset = SRC_MASK_PERIL1, .value = 0x01110111, }, + { .offset = SRC_MASK_DMC, .value = 0x00010000, }, +}; + +static const struct samsung_clk_reg_dump src_mask_suspend_e4210[] = { + { .offset = E4210_SRC_MASK_LCD1, .value = 0x00001111, }, +}; + +#define PLL_ENABLED (1 << 31) +#define PLL_LOCKED (1 << 29) + +static void exynos4_clk_wait_for_pll(u32 reg) +{ + u32 pll_con; + + pll_con = readl(reg_base + reg); + if (!(pll_con & PLL_ENABLED)) + return; + + while (!(pll_con & PLL_LOCKED)) { + cpu_relax(); + pll_con = readl(reg_base + reg); + } +} + +static int exynos4_clk_suspend(void) +{ + samsung_clk_save(reg_base, exynos4_save_common, + ARRAY_SIZE(exynos4_clk_regs)); + samsung_clk_save(reg_base, exynos4_save_pll, + ARRAY_SIZE(exynos4_clk_pll_regs)); + + if (exynos4_soc == EXYNOS4210) { + samsung_clk_save(reg_base, exynos4_save_soc, + ARRAY_SIZE(exynos4210_clk_save)); + samsung_clk_restore(reg_base, src_mask_suspend_e4210, + ARRAY_SIZE(src_mask_suspend_e4210)); + } else { + samsung_clk_save(reg_base, exynos4_save_soc, + ARRAY_SIZE(exynos4x12_clk_save)); + } + + samsung_clk_restore(reg_base, src_mask_suspend, + ARRAY_SIZE(src_mask_suspend)); + + return 0; +} + +static void exynos4_clk_resume(void) +{ + samsung_clk_restore(reg_base, exynos4_save_pll, + ARRAY_SIZE(exynos4_clk_pll_regs)); + + exynos4_clk_wait_for_pll(EPLL_CON0); + exynos4_clk_wait_for_pll(VPLL_CON0); + + samsung_clk_restore(reg_base, exynos4_save_common, + ARRAY_SIZE(exynos4_clk_regs)); + + if (exynos4_soc == EXYNOS4210) + samsung_clk_restore(reg_base, exynos4_save_soc, + ARRAY_SIZE(exynos4210_clk_save)); + else + samsung_clk_restore(reg_base, exynos4_save_soc, + ARRAY_SIZE(exynos4x12_clk_save)); +} + +static struct syscore_ops exynos4_clk_syscore_ops = { + .suspend = exynos4_clk_suspend, + .resume = exynos4_clk_resume, +}; + +static void exynos4_clk_sleep_init(void) +{ + exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs, + ARRAY_SIZE(exynos4_clk_regs)); + if (!exynos4_save_common) + goto err_warn; + + if (exynos4_soc == EXYNOS4210) + exynos4_save_soc = samsung_clk_alloc_reg_dump( + exynos4210_clk_save, + ARRAY_SIZE(exynos4210_clk_save)); + else + exynos4_save_soc = samsung_clk_alloc_reg_dump( + exynos4x12_clk_save, + ARRAY_SIZE(exynos4x12_clk_save)); + if (!exynos4_save_soc) + goto err_common; + + exynos4_save_pll = samsung_clk_alloc_reg_dump(exynos4_clk_pll_regs, + ARRAY_SIZE(exynos4_clk_pll_regs)); + if (!exynos4_save_pll) + goto err_soc; + + register_syscore_ops(&exynos4_clk_syscore_ops); + return; + +err_soc: + kfree(exynos4_save_soc); +err_common: + kfree(exynos4_save_common); +err_warn: + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); +} +#else +static void exynos4_clk_sleep_init(void) {} +#endif + /* list of all parent clock list */ PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", }; @@ -908,12 +1043,13 @@ static unsigned long exynos4_get_xom(void) return xom; } -static void __init exynos4_clk_register_finpll(unsigned long xom) +static void __init exynos4_clk_register_finpll(void) { struct samsung_fixed_rate_clock fclk; struct clk *clk; unsigned long finpll_f = 24000000; char *parent_name; + unsigned int xom = exynos4_get_xom(); parent_name = xom & 1 ? "xusbxti" : "xxti"; clk = clk_get(NULL, parent_name); @@ -1038,27 +1174,21 @@ static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = { /* register exynos4 clocks */ static void __init exynos4_clk_init(struct device_node *np, - enum exynos4_soc exynos4_soc, - void __iomem *reg_base, unsigned long xom) + enum exynos4_soc soc) { + exynos4_soc = soc; + reg_base = of_iomap(np, 0); if (!reg_base) panic("%s: failed to map registers\n", __func__); - if (exynos4_soc == EXYNOS4210) - samsung_clk_init(np, reg_base, CLK_NR_CLKS, - exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), - exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save)); - else - samsung_clk_init(np, reg_base, CLK_NR_CLKS, - exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), - exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save)); + samsung_clk_init(np, reg_base, CLK_NR_CLKS); samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks, ARRAY_SIZE(exynos4_fixed_rate_ext_clks), ext_clk_match); - exynos4_clk_register_finpll(xom); + exynos4_clk_register_finpll(); if (exynos4_soc == EXYNOS4210) { samsung_clk_register_mux(exynos4210_mux_early, @@ -1125,6 +1255,8 @@ static void __init exynos4_clk_init(struct device_node *np, samsung_clk_register_alias(exynos4_aliases, ARRAY_SIZE(exynos4_aliases)); + exynos4_clk_sleep_init(); + 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", @@ -1136,12 +1268,12 @@ static void __init exynos4_clk_init(struct device_node *np, static void __init exynos4210_clk_init(struct device_node *np) { - exynos4_clk_init(np, EXYNOS4210, NULL, exynos4_get_xom()); + exynos4_clk_init(np, EXYNOS4210); } CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4210_clk_init); static void __init exynos4412_clk_init(struct device_node *np) { - exynos4_clk_init(np, EXYNOS4X12, NULL, exynos4_get_xom()); + exynos4_clk_init(np, EXYNOS4X12); } CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4412_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index ff4beebe1f0b..e7ee4420da81 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -16,6 +16,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include "clk.h" @@ -85,6 +86,11 @@ enum exynos5250_plls { nr_plls /* number of PLLs */ }; +static void __iomem *reg_base; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *exynos5250_save; + /* * list of controller registers to be saved and restored during a * suspend/resume cycle. @@ -137,6 +143,41 @@ static unsigned long exynos5250_clk_regs[] __initdata = { GATE_IP_ACP, }; +static int exynos5250_clk_suspend(void) +{ + samsung_clk_save(reg_base, exynos5250_save, + ARRAY_SIZE(exynos5250_clk_regs)); + + return 0; +} + +static void exynos5250_clk_resume(void) +{ + samsung_clk_restore(reg_base, exynos5250_save, + ARRAY_SIZE(exynos5250_clk_regs)); +} + +static struct syscore_ops exynos5250_clk_syscore_ops = { + .suspend = exynos5250_clk_suspend, + .resume = exynos5250_clk_resume, +}; + +static void exynos5250_clk_sleep_init(void) +{ + exynos5250_save = samsung_clk_alloc_reg_dump(exynos5250_clk_regs, + ARRAY_SIZE(exynos5250_clk_regs)); + if (!exynos5250_save) { + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); + return; + } + + register_syscore_ops(&exynos5250_clk_syscore_ops); +} +#else +static void exynos5250_clk_sleep_init(void) {} +#endif + /* list of all parent clock list */ PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", }; @@ -645,8 +686,6 @@ static struct of_device_id ext_clk_match[] __initdata = { /* register exynox5250 clocks */ static void __init exynos5250_clk_init(struct device_node *np) { - void __iomem *reg_base; - if (np) { reg_base = of_iomap(np, 0); if (!reg_base) @@ -655,9 +694,7 @@ static void __init exynos5250_clk_init(struct device_node *np) panic("%s: unable to determine soc\n", __func__); } - samsung_clk_init(np, reg_base, CLK_NR_CLKS, - exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs), - NULL, 0); + samsung_clk_init(np, reg_base, CLK_NR_CLKS); samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), ext_clk_match); @@ -685,6 +722,8 @@ static void __init exynos5250_clk_init(struct device_node *np) samsung_clk_register_gate(exynos5250_gate_clks, ARRAY_SIZE(exynos5250_gate_clks)); + exynos5250_clk_sleep_init(); + pr_info("Exynos5250: clock setup completed, armclk=%ld\n", _get_rate("div_arm2")); } diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index ab4f2f7d88ef..60b26819bed5 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -16,6 +16,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include "clk.h" @@ -108,6 +109,11 @@ enum exynos5420_plls { nr_plls /* number of PLLs */ }; +static void __iomem *reg_base; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *exynos5420_save; + /* * list of controller registers to be saved and restored during a * suspend/resume cycle. @@ -174,6 +180,41 @@ static unsigned long exynos5420_clk_regs[] __initdata = { DIV_KFC0, }; +static int exynos5420_clk_suspend(void) +{ + samsung_clk_save(reg_base, exynos5420_save, + ARRAY_SIZE(exynos5420_clk_regs)); + + return 0; +} + +static void exynos5420_clk_resume(void) +{ + samsung_clk_restore(reg_base, exynos5420_save, + ARRAY_SIZE(exynos5420_clk_regs)); +} + +static struct syscore_ops exynos5420_clk_syscore_ops = { + .suspend = exynos5420_clk_suspend, + .resume = exynos5420_clk_resume, +}; + +static void exynos5420_clk_sleep_init(void) +{ + exynos5420_save = samsung_clk_alloc_reg_dump(exynos5420_clk_regs, + ARRAY_SIZE(exynos5420_clk_regs)); + if (!exynos5420_save) { + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); + return; + } + + register_syscore_ops(&exynos5420_clk_syscore_ops); +} +#else +static void exynos5420_clk_sleep_init(void) {} +#endif + /* list of all parent clocks */ PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll", "sclk_mpll", "sclk_spll" }; @@ -737,8 +778,6 @@ static struct of_device_id ext_clk_match[] __initdata = { /* register exynos5420 clocks */ static void __init exynos5420_clk_init(struct device_node *np) { - void __iomem *reg_base; - if (np) { reg_base = of_iomap(np, 0); if (!reg_base) @@ -747,9 +786,7 @@ static void __init exynos5420_clk_init(struct device_node *np) panic("%s: unable to determine soc\n", __func__); } - samsung_clk_init(np, reg_base, CLK_NR_CLKS, - exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs), - NULL, 0); + samsung_clk_init(np, reg_base, CLK_NR_CLKS); samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks, ARRAY_SIZE(exynos5420_fixed_rate_ext_clks), ext_clk_match); @@ -765,5 +802,7 @@ static void __init exynos5420_clk_init(struct device_node *np) ARRAY_SIZE(exynos5420_div_clks)); samsung_clk_register_gate(exynos5420_gate_clks, ARRAY_SIZE(exynos5420_gate_clks)); + + exynos5420_clk_sleep_init(); } CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index cbc15b56891d..2bfad5a993d0 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -101,7 +101,7 @@ static void __init exynos5440_clk_init(struct device_node *np) return; } - samsung_clk_init(np, reg_base, CLK_NR_CLKS, NULL, 0, NULL, 0); + samsung_clk_init(np, reg_base, CLK_NR_CLKS); samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks, ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 8e27aee6887e..8bda658137a8 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -13,6 +13,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include <dt-bindings/clock/samsung,s3c64xx-clock.h> @@ -61,6 +62,13 @@ enum s3c64xx_plls { apll, mpll, epll, }; +static void __iomem *reg_base; +static bool is_s3c6400; + +#ifdef CONFIG_PM_SLEEP +static struct samsung_clk_reg_dump *s3c64xx_save_common; +static struct samsung_clk_reg_dump *s3c64xx_save_soc; + /* * List of controller registers to be saved and restored during * a suspend/resume cycle. @@ -87,6 +95,60 @@ static unsigned long s3c6410_clk_regs[] __initdata = { MEM0_GATE, }; +static int s3c64xx_clk_suspend(void) +{ + samsung_clk_save(reg_base, s3c64xx_save_common, + ARRAY_SIZE(s3c64xx_clk_regs)); + + if (!is_s3c6400) + samsung_clk_save(reg_base, s3c64xx_save_soc, + ARRAY_SIZE(s3c6410_clk_regs)); + + return 0; +} + +static void s3c64xx_clk_resume(void) +{ + samsung_clk_restore(reg_base, s3c64xx_save_common, + ARRAY_SIZE(s3c64xx_clk_regs)); + + if (!is_s3c6400) + samsung_clk_restore(reg_base, s3c64xx_save_soc, + ARRAY_SIZE(s3c6410_clk_regs)); +} + +static struct syscore_ops s3c64xx_clk_syscore_ops = { + .suspend = s3c64xx_clk_suspend, + .resume = s3c64xx_clk_resume, +}; + +static void s3c64xx_clk_sleep_init(void) +{ + s3c64xx_save_common = samsung_clk_alloc_reg_dump(s3c64xx_clk_regs, + ARRAY_SIZE(s3c64xx_clk_regs)); + if (!s3c64xx_save_common) + goto err_warn; + + if (!is_s3c6400) { + s3c64xx_save_soc = samsung_clk_alloc_reg_dump(s3c6410_clk_regs, + ARRAY_SIZE(s3c6410_clk_regs)); + if (!s3c64xx_save_soc) + goto err_soc; + } + + register_syscore_ops(&s3c64xx_clk_syscore_ops); + return; + +err_soc: + kfree(s3c64xx_save_common); +err_warn: + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", + __func__); +} +#else +static void s3c64xx_clk_sleep_init(void) {} +#endif + /* List of parent clocks common for all S3C64xx SoCs. */ PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" }; PNAME(uart_p) = { "mout_epll", "dout_mpll" }; @@ -391,11 +453,11 @@ static void __init s3c64xx_clk_register_fixed_ext(unsigned long fin_pll_f, /* Register s3c64xx clocks. */ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, - unsigned long xusbxti_f, bool is_s3c6400, - void __iomem *reg_base) + unsigned long xusbxti_f, bool s3c6400, + void __iomem *base) { - unsigned long *soc_regs = NULL; - unsigned long nr_soc_regs = 0; + reg_base = base; + is_s3c6400 = s3c6400; if (np) { reg_base = of_iomap(np, 0); @@ -403,13 +465,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, panic("%s: failed to map registers\n", __func__); } - if (!is_s3c6400) { - soc_regs = s3c6410_clk_regs; - nr_soc_regs = ARRAY_SIZE(s3c6410_clk_regs); - } - - samsung_clk_init(np, reg_base, NR_CLKS, s3c64xx_clk_regs, - ARRAY_SIZE(s3c64xx_clk_regs), soc_regs, nr_soc_regs); + samsung_clk_init(np, reg_base, NR_CLKS); /* Register external clocks. */ if (!np) @@ -452,6 +508,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, samsung_clk_register_alias(s3c64xx_clock_aliases, ARRAY_SIZE(s3c64xx_clock_aliases)); + s3c64xx_clk_sleep_init(); pr_info("%s clocks: apll = %lu, mpll = %lu\n" "\tepll = %lu, arm_clk = %lu\n", diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index f503f32e2f80..91bec3ebdc8f 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -21,64 +21,45 @@ static void __iomem *reg_base; static struct clk_onecell_data clk_data; #endif -#ifdef CONFIG_PM_SLEEP -static struct samsung_clk_reg_dump *reg_dump; -static unsigned long nr_reg_dump; - -static int samsung_clk_suspend(void) +void samsung_clk_save(void __iomem *base, + struct samsung_clk_reg_dump *rd, + unsigned int num_regs) { - struct samsung_clk_reg_dump *rd = reg_dump; - unsigned long i; - - for (i = 0; i < nr_reg_dump; i++, rd++) - rd->value = __raw_readl(reg_base + rd->offset); + for (; num_regs > 0; --num_regs, ++rd) + rd->value = readl(base + rd->offset); +} - return 0; +void samsung_clk_restore(void __iomem *base, + const struct samsung_clk_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) + writel(rd->value, base + rd->offset); } -static void samsung_clk_resume(void) +struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( + const unsigned long *rdump, + unsigned long nr_rdump) { - struct samsung_clk_reg_dump *rd = reg_dump; - unsigned long i; + struct samsung_clk_reg_dump *rd; + unsigned int i; - for (i = 0; i < nr_reg_dump; i++, rd++) - __raw_writel(rd->value, reg_base + rd->offset); -} + rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL); + if (!rd) + return NULL; + + for (i = 0; i < nr_rdump; ++i) + rd[i].offset = rdump[i]; -static struct syscore_ops samsung_clk_syscore_ops = { - .suspend = samsung_clk_suspend, - .resume = samsung_clk_resume, -}; -#endif /* CONFIG_PM_SLEEP */ + return rd; +} /* setup the essentials required to support clock lookup using ccf */ void __init samsung_clk_init(struct device_node *np, void __iomem *base, - unsigned long nr_clks, unsigned long *rdump, - unsigned long nr_rdump, unsigned long *soc_rdump, - unsigned long nr_soc_rdump) + unsigned long nr_clks) { reg_base = base; -#ifdef CONFIG_PM_SLEEP - if (rdump && nr_rdump) { - unsigned int idx; - reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump) - * (nr_rdump + nr_soc_rdump), GFP_KERNEL); - if (!reg_dump) { - pr_err("%s: memory alloc for register dump failed\n", - __func__); - return; - } - - for (idx = 0; idx < nr_rdump; idx++) - reg_dump[idx].offset = rdump[idx]; - for (idx = 0; idx < nr_soc_rdump; idx++) - reg_dump[nr_rdump + idx].offset = soc_rdump[idx]; - nr_reg_dump = nr_rdump + nr_soc_rdump; - register_syscore_ops(&samsung_clk_syscore_ops); - } -#endif - clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); if (!clk_table) panic("could not allocate clock lookup table\n"); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 31b4174e7a5b..c7141ba826e0 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -313,9 +313,7 @@ struct samsung_pll_clock { _lock, _con, _rtable, _alias) extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, - unsigned long nr_clks, unsigned long *rdump, - unsigned long nr_rdump, unsigned long *soc_rdump, - unsigned long nr_soc_rdump); + unsigned long nr_clks); extern void __init samsung_clk_of_register_fixed_ext( struct samsung_fixed_rate_clock *fixed_rate_clk, unsigned int nr_fixed_rate_clk, @@ -340,4 +338,14 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list, extern unsigned long _get_rate(const char *clk_name); +extern void samsung_clk_save(void __iomem *base, + struct samsung_clk_reg_dump *rd, + unsigned int num_regs); +extern void samsung_clk_restore(void __iomem *base, + const struct samsung_clk_reg_dump *rd, + unsigned int num_regs); +extern struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( + const unsigned long *rdump, + unsigned long nr_rdump); + #endif /* __SAMSUNG_CLK_H */ diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 8cbfcf88fae3..a820b0cfcf57 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -33,7 +33,7 @@ struct clk_icst { struct clk_hw hw; void __iomem *vcoreg; void __iomem *lockreg; - const struct icst_params *params; + struct icst_params *params; unsigned long rate; }; @@ -84,6 +84,8 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (parent_rate) + icst->params->ref = parent_rate; vco = vco_get(icst->vcoreg); icst->rate = icst_hz(icst->params, vco); return icst->rate; @@ -105,6 +107,8 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (parent_rate) + icst->params->ref = parent_rate; vco = icst_hz_to_vco(icst->params, rate); icst->rate = icst_hz(icst->params, vco); vco_set(icst->lockreg, icst->vcoreg, vco); @@ -120,24 +124,33 @@ static const struct clk_ops icst_ops = { struct clk *icst_clk_register(struct device *dev, const struct clk_icst_desc *desc, const char *name, + const char *parent_name, void __iomem *base) { struct clk *clk; struct clk_icst *icst; struct clk_init_data init; + struct icst_params *pclone; icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); if (!icst) { pr_err("could not allocate ICST clock!\n"); return ERR_PTR(-ENOMEM); } + + pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); + if (!pclone) { + pr_err("could not clone ICST params\n"); + return ERR_PTR(-ENOMEM); + } + init.name = name; init.ops = &icst_ops; init.flags = CLK_IS_ROOT; - init.parent_names = NULL; - init.num_parents = 0; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); icst->hw.init = &init; - icst->params = desc->params; + icst->params = pclone; icst->vcoreg = base + desc->vco_offset; icst->lockreg = base + desc->lock_offset; diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index be99dd0da785..04e6f0aef588 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -16,4 +16,5 @@ struct clk_icst_desc { struct clk *icst_clk_register(struct device *dev, const struct clk_icst_desc *desc, const char *name, + const char *parent_name, void __iomem *base); diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 844f8d711a12..31b44f025f9e 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -13,10 +13,12 @@ #include <linux/io.h> #include <linux/platform_data/clk-integrator.h> -#include <mach/impd1.h> - #include "clk-icst.h" +#define IMPD1_OSC1 0x00 +#define IMPD1_OSC2 0x04 +#define IMPD1_LOCK 0x08 + struct impd1_clk { char *vco1name; struct clk *vco1clk; @@ -93,13 +95,15 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) imc = &impd1_clks[id]; imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); - clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, base); + clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL, + base); imc->vco1clk = clk; imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); /* VCO2 is also called "CLK2" */ imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); - clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, base); + clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL, + base); imc->vco2clk = clk; /* MMCI uses CLK2 right off */ diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c index bda8967e09c2..734c4b8fe6ab 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-integrator.c @@ -10,21 +10,17 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/err.h> -#include <linux/platform_data/clk-integrator.h> - -#include <mach/hardware.h> -#include <mach/platform.h> +#include <linux/of.h> +#include <linux/of_address.h> #include "clk-icst.h" -/* - * Implementation of the ARM Integrator/AP and Integrator/CP clock tree. - * Inspired by portions of: - * plat-versatile/clock.c and plat-versatile/include/plat/clock.h - */ +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 -static const struct icst_params cp_auxvco_params = { - .ref = 24000000, +/* Base offset for the core module */ +static void __iomem *cm_base; + +static const struct icst_params cp_auxosc_params = { .vco_max = ICST525_VCO_MAX_5V, .vco_min = ICST525_VCO_MIN, .vd_min = 8, @@ -35,50 +31,39 @@ static const struct icst_params cp_auxvco_params = { .idx2s = icst525_idx2s, }; -static const struct clk_icst_desc __initdata cp_icst_desc = { - .params = &cp_auxvco_params, +static const struct clk_icst_desc __initdata cm_auxosc_desc = { + .params = &cp_auxosc_params, .vco_offset = 0x1c, .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, }; -/* - * integrator_clk_init() - set up the integrator clock tree - * @is_cp: pass true if it's the Integrator/CP else AP is assumed - */ -void __init integrator_clk_init(bool is_cp) +static void __init of_integrator_cm_osc_setup(struct device_node *np) { - struct clk *clk; - - /* APB clock dummy */ - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - - /* UART reference clock */ - clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, - 14745600); - clk_register_clkdev(clk, NULL, "uart0"); - clk_register_clkdev(clk, NULL, "uart1"); - if (is_cp) - clk_register_clkdev(clk, NULL, "mmci"); - - /* 24 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, - 24000000); - clk_register_clkdev(clk, NULL, "kmi0"); - clk_register_clkdev(clk, NULL, "kmi1"); - if (!is_cp) - clk_register_clkdev(clk, NULL, "ap_timer"); + struct clk *clk = ERR_PTR(-EINVAL); + const char *clk_name = np->name; + const struct clk_icst_desc *desc = &cm_auxosc_desc; + const char *parent_name; - if (!is_cp) - return; + if (!cm_base) { + /* Remap the core module base if not done yet */ + struct device_node *parent; - /* 1 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, - 1000000); - clk_register_clkdev(clk, NULL, "sp804"); + parent = of_get_parent(np); + if (!np) { + pr_err("no parent on core module clock\n"); + return; + } + cm_base = of_iomap(parent, 0); + if (!cm_base) { + pr_err("could not remap core module base\n"); + return; + } + } - /* ICST VCO clock used on the Integrator/CP CLCD */ - clk = icst_clk_register(NULL, &cp_icst_desc, "icst", - __io_address(INTEGRATOR_HDR_BASE)); - clk_register_clkdev(clk, NULL, "clcd"); + parent_name = of_clk_get_parent_name(np, 0); + clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base); + if (!IS_ERR(clk)) + of_clk_add_provider(np, of_clk_src_simple_get, clk); } +CLK_OF_DECLARE(integrator_cm_auxosc_clk, + "arm,integrator-cm-auxosc", of_integrator_cm_osc_setup); diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c index 747e7b31117c..c8b523117fb7 100644 --- a/drivers/clk/versatile/clk-realview.c +++ b/drivers/clk/versatile/clk-realview.c @@ -85,10 +85,10 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) /* ICST VCO clock */ if (is_pb1176) clk = icst_clk_register(NULL, &realview_osc0_desc, - "osc0", sysbase); + "osc0", NULL, sysbase); else clk = icst_clk_register(NULL, &realview_osc4_desc, - "osc4", sysbase); + "osc4", NULL, sysbase); clk_register_clkdev(clk, NULL, "dev:clcd"); clk_register_clkdev(clk, NULL, "issp:clcd"); diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 09dd0173ea0a..c812b93a52b2 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -21,34 +21,35 @@ #include <linux/clk/zynq.h> #include <linux/clk-provider.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/io.h> -static void __iomem *zynq_slcr_base_priv; - -#define SLCR_ARMPLL_CTRL (zynq_slcr_base_priv + 0x100) -#define SLCR_DDRPLL_CTRL (zynq_slcr_base_priv + 0x104) -#define SLCR_IOPLL_CTRL (zynq_slcr_base_priv + 0x108) -#define SLCR_PLL_STATUS (zynq_slcr_base_priv + 0x10c) -#define SLCR_ARM_CLK_CTRL (zynq_slcr_base_priv + 0x120) -#define SLCR_DDR_CLK_CTRL (zynq_slcr_base_priv + 0x124) -#define SLCR_DCI_CLK_CTRL (zynq_slcr_base_priv + 0x128) -#define SLCR_APER_CLK_CTRL (zynq_slcr_base_priv + 0x12c) -#define SLCR_GEM0_CLK_CTRL (zynq_slcr_base_priv + 0x140) -#define SLCR_GEM1_CLK_CTRL (zynq_slcr_base_priv + 0x144) -#define SLCR_SMC_CLK_CTRL (zynq_slcr_base_priv + 0x148) -#define SLCR_LQSPI_CLK_CTRL (zynq_slcr_base_priv + 0x14c) -#define SLCR_SDIO_CLK_CTRL (zynq_slcr_base_priv + 0x150) -#define SLCR_UART_CLK_CTRL (zynq_slcr_base_priv + 0x154) -#define SLCR_SPI_CLK_CTRL (zynq_slcr_base_priv + 0x158) -#define SLCR_CAN_CLK_CTRL (zynq_slcr_base_priv + 0x15c) -#define SLCR_CAN_MIOCLK_CTRL (zynq_slcr_base_priv + 0x160) -#define SLCR_DBG_CLK_CTRL (zynq_slcr_base_priv + 0x164) -#define SLCR_PCAP_CLK_CTRL (zynq_slcr_base_priv + 0x168) -#define SLCR_FPGA0_CLK_CTRL (zynq_slcr_base_priv + 0x170) -#define SLCR_621_TRUE (zynq_slcr_base_priv + 0x1c4) -#define SLCR_SWDT_CLK_SEL (zynq_slcr_base_priv + 0x304) +static void __iomem *zynq_clkc_base; + +#define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00) +#define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04) +#define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08) +#define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c) +#define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20) +#define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24) +#define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28) +#define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c) +#define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40) +#define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44) +#define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48) +#define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c) +#define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50) +#define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54) +#define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58) +#define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c) +#define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60) +#define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64) +#define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68) +#define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70) +#define SLCR_621_TRUE (zynq_clkc_base + 0xc4) +#define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) #define NUM_MIO_PINS 54 @@ -569,8 +570,42 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_OF_DECLARE(zynq_clkc, "xlnx,ps7-clkc", zynq_clk_setup); -void __init zynq_clock_init(void __iomem *slcr_base) +void __init zynq_clock_init(void) { - zynq_slcr_base_priv = slcr_base; - of_clk_init(NULL); + struct device_node *np; + struct device_node *slcr; + struct resource res; + + np = of_find_compatible_node(NULL, NULL, "xlnx,ps7-clkc"); + if (!np) { + pr_err("%s: clkc node not found\n", __func__); + goto np_err; + } + + if (of_address_to_resource(np, 0, &res)) { + pr_err("%s: failed to get resource\n", np->name); + goto np_err; + } + + slcr = of_get_parent(np); + + if (slcr->data) { + zynq_clkc_base = (__force void __iomem *)slcr->data + res.start; + } else { + pr_err("%s: Unable to get I/O memory\n", np->name); + of_node_put(slcr); + goto np_err; + } + + pr_info("%s: clkc starts at %p\n", __func__, zynq_clkc_base); + + of_node_put(slcr); + of_node_put(np); + + return; + +np_err: + of_node_put(np); + BUG(); + return; } |