diff options
Diffstat (limited to 'drivers/clk/mvebu')
| -rw-r--r-- | drivers/clk/mvebu/Kconfig | 17 | ||||
| -rw-r--r-- | drivers/clk/mvebu/Makefile | 4 | ||||
| -rw-r--r-- | drivers/clk/mvebu/armada-370.c | 39 | ||||
| -rw-r--r-- | drivers/clk/mvebu/armada-375.c | 184 | ||||
| -rw-r--r-- | drivers/clk/mvebu/armada-38x.c | 167 | ||||
| -rw-r--r-- | drivers/clk/mvebu/armada-xp.c | 32 | ||||
| -rw-r--r-- | drivers/clk/mvebu/clk-corediv.c | 315 | ||||
| -rw-r--r-- | drivers/clk/mvebu/clk-cpu.c | 6 | ||||
| -rw-r--r-- | drivers/clk/mvebu/common.c | 18 | ||||
| -rw-r--r-- | drivers/clk/mvebu/dove.c | 31 | ||||
| -rw-r--r-- | drivers/clk/mvebu/kirkwood.c | 48 | ||||
| -rw-r--r-- | drivers/clk/mvebu/orion.c | 210 |
12 files changed, 985 insertions, 86 deletions
diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 0b0f3e729cf..3b34dba9178 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -4,15 +4,28 @@ config MVEBU_CLK_COMMON config MVEBU_CLK_CPU bool +config MVEBU_CLK_COREDIV + bool + config ARMADA_370_CLK bool select MVEBU_CLK_COMMON select MVEBU_CLK_CPU + select MVEBU_CLK_COREDIV + +config ARMADA_375_CLK + bool + select MVEBU_CLK_COMMON + +config ARMADA_38X_CLK + bool + select MVEBU_CLK_COMMON config ARMADA_XP_CLK bool select MVEBU_CLK_COMMON select MVEBU_CLK_CPU + select MVEBU_CLK_COREDIV config DOVE_CLK bool @@ -21,3 +34,7 @@ config DOVE_CLK config KIRKWOOD_CLK bool select MVEBU_CLK_COMMON + +config ORION_CLK + bool + select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 1c7e70c63fb..a9a56fc0190 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -1,7 +1,11 @@ obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o +obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o +obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o +obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_DOVE_CLK) += dove.o obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o +obj-$(CONFIG_ORION_CLK) += orion.o diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 079960e7c30..bef198a8386 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -32,15 +32,15 @@ enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK }; -static const struct coreclk_ratio __initconst a370_coreclk_ratios[] = { +static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = { { .id = A370_CPU_TO_NBCLK, .name = "nbclk" }, { .id = A370_CPU_TO_HCLK, .name = "hclk" }, { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" }, }; -static const u32 __initconst a370_tclk_freqs[] = { - 16600000, - 20000000, +static const u32 a370_tclk_freqs[] __initconst = { + 166000000, + 200000000, }; static u32 __init a370_get_tclk_freq(void __iomem *sar) @@ -52,7 +52,7 @@ static u32 __init a370_get_tclk_freq(void __iomem *sar) return a370_tclk_freqs[tclk_freq_select]; } -static const u32 __initconst a370_cpu_freqs[] = { +static const u32 a370_cpu_freqs[] __initconst = { 400000000, 533000000, 667000000, @@ -78,7 +78,7 @@ static u32 __init a370_get_cpu_freq(void __iomem *sar) return cpu_freq; } -static const int __initconst a370_nbclk_ratios[32][2] = { +static const int a370_nbclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 1}, {2, 3}, {0, 1}, {1, 2}, {2, 4}, {0, 1}, @@ -89,7 +89,7 @@ static const int __initconst a370_nbclk_ratios[32][2] = { {0, 1}, {0, 1}, {0, 1}, {0, 1}, }; -static const int __initconst a370_hclk_ratios[32][2] = { +static const int a370_hclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 6}, {2, 3}, {1, 3}, {1, 4}, {1, 2}, {2, 6}, {0, 1}, {1, 6}, {2, 10}, {0, 1}, @@ -100,7 +100,7 @@ static const int __initconst a370_hclk_ratios[32][2] = { {0, 1}, {0, 1}, {0, 1}, {0, 1}, }; -static const int __initconst a370_dramclk_ratios[32][2] = { +static const int a370_dramclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 3}, {2, 3}, {1, 3}, {1, 2}, {1, 2}, {2, 6}, {0, 1}, {1, 3}, {2, 5}, {0, 1}, @@ -141,18 +141,11 @@ static const struct coreclk_soc_desc a370_coreclks = { .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), }; -static void __init a370_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &a370_coreclks); -} -CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock", - a370_coreclk_init); - /* * Clock Gating Control */ -static const struct clk_gating_soc_desc __initconst a370_gating_desc[] = { +static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = { { "audio", NULL, 0, 0 }, { "pex0_en", NULL, 1, 0 }, { "pex1_en", NULL, 2, 0 }, @@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc __initconst a370_gating_desc[] = { { } }; -static void __init a370_clk_gating_init(struct device_node *np) +static void __init a370_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, a370_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock"); + + mvebu_coreclk_setup(np, &a370_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, a370_gating_desc); } -CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock", - a370_clk_gating_init); +CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); + diff --git a/drivers/clk/mvebu/armada-375.c b/drivers/clk/mvebu/armada-375.c new file mode 100644 index 00000000000..c991a4d95e1 --- /dev/null +++ b/drivers/clk/mvebu/armada-375.c @@ -0,0 +1,184 @@ +/* + * Marvell Armada 375 SoC clocks + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * Andrew Lunn <andrew@lunn.ch> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * Core Clocks + */ + +/* + * For the Armada 375 SoCs, the CPU, DDR and L2 clocks frequencies are + * all modified at the same time, and not separately as for the Armada + * 370 or the Armada XP SoCs. + * + * SAR0[21:17] : CPU frequency DDR frequency L2 frequency + * 6 = 400 MHz 400 MHz 200 MHz + * 15 = 600 MHz 600 MHz 300 MHz + * 21 = 800 MHz 534 MHz 400 MHz + * 25 = 1000 MHz 500 MHz 500 MHz + * others reserved. + * + * SAR0[22] : TCLK frequency + * 0 = 166 MHz + * 1 = 200 MHz + */ + +#define SAR1_A375_TCLK_FREQ_OPT 22 +#define SAR1_A375_TCLK_FREQ_OPT_MASK 0x1 +#define SAR1_A375_CPU_DDR_L2_FREQ_OPT 17 +#define SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK 0x1F + +static const u32 armada_375_tclk_frequencies[] __initconst = { + 166000000, + 200000000, +}; + +static u32 __init armada_375_get_tclk_freq(void __iomem *sar) +{ + u8 tclk_freq_select; + + tclk_freq_select = ((readl(sar) >> SAR1_A375_TCLK_FREQ_OPT) & + SAR1_A375_TCLK_FREQ_OPT_MASK); + return armada_375_tclk_frequencies[tclk_freq_select]; +} + + +static const u32 armada_375_cpu_frequencies[] __initconst = { + 0, 0, 0, 0, 0, 0, + 400000000, + 0, 0, 0, 0, 0, 0, 0, 0, + 600000000, + 0, 0, 0, 0, 0, + 800000000, + 0, 0, 0, + 1000000000, +}; + +static u32 __init armada_375_get_cpu_freq(void __iomem *sar) +{ + u8 cpu_freq_select; + + cpu_freq_select = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) & + SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK); + if (cpu_freq_select >= ARRAY_SIZE(armada_375_cpu_frequencies)) { + pr_err("Selected CPU frequency (%d) unsupported\n", + cpu_freq_select); + return 0; + } else + return armada_375_cpu_frequencies[cpu_freq_select]; +} + +enum { A375_CPU_TO_DDR, A375_CPU_TO_L2 }; + +static const struct coreclk_ratio armada_375_coreclk_ratios[] __initconst = { + { .id = A375_CPU_TO_L2, .name = "l2clk" }, + { .id = A375_CPU_TO_DDR, .name = "ddrclk" }, +}; + +static const int armada_375_cpu_l2_ratios[32][2] __initconst = { + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {1, 2}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {1, 2}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {1, 2}, {0, 1}, {0, 1}, + {0, 1}, {1, 2}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int armada_375_cpu_ddr_ratios[32][2] __initconst = { + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {1, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {2, 3}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {2, 3}, {0, 1}, {0, 1}, + {0, 1}, {1, 2}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static void __init armada_375_get_clk_ratio( + void __iomem *sar, int id, int *mult, int *div) +{ + u32 opt = ((readl(sar) >> SAR1_A375_CPU_DDR_L2_FREQ_OPT) & + SAR1_A375_CPU_DDR_L2_FREQ_OPT_MASK); + + switch (id) { + case A375_CPU_TO_L2: + *mult = armada_375_cpu_l2_ratios[opt][0]; + *div = armada_375_cpu_l2_ratios[opt][1]; + break; + case A375_CPU_TO_DDR: + *mult = armada_375_cpu_ddr_ratios[opt][0]; + *div = armada_375_cpu_ddr_ratios[opt][1]; + break; + } +} + +static const struct coreclk_soc_desc armada_375_coreclks = { + .get_tclk_freq = armada_375_get_tclk_freq, + .get_cpu_freq = armada_375_get_cpu_freq, + .get_clk_ratio = armada_375_get_clk_ratio, + .ratios = armada_375_coreclk_ratios, + .num_ratios = ARRAY_SIZE(armada_375_coreclk_ratios), +}; + +static void __init armada_375_coreclk_init(struct device_node *np) +{ + mvebu_coreclk_setup(np, &armada_375_coreclks); +} +CLK_OF_DECLARE(armada_375_core_clk, "marvell,armada-375-core-clock", + armada_375_coreclk_init); + +/* + * Clock Gating Control + */ +static const struct clk_gating_soc_desc armada_375_gating_desc[] __initconst = { + { "mu", NULL, 2 }, + { "pp", NULL, 3 }, + { "ptp", NULL, 4 }, + { "pex0", NULL, 5 }, + { "pex1", NULL, 6 }, + { "audio", NULL, 8 }, + { "nd_clk", "nand", 11 }, + { "sata0_link", "sata0_core", 14 }, + { "sata0_core", NULL, 15 }, + { "usb3", NULL, 16 }, + { "sdio", NULL, 17 }, + { "usb", NULL, 18 }, + { "gop", NULL, 19 }, + { "sata1_link", "sata1_core", 20 }, + { "sata1_core", NULL, 21 }, + { "xor0", NULL, 22 }, + { "xor1", NULL, 23 }, + { "copro", NULL, 24 }, + { "tdm", NULL, 25 }, + { "crypto0_enc", NULL, 28 }, + { "crypto0_core", NULL, 29 }, + { "crypto1_enc", NULL, 30 }, + { "crypto1_core", NULL, 31 }, + { } +}; + +static void __init armada_375_clk_gating_init(struct device_node *np) +{ + mvebu_clk_gating_setup(np, armada_375_gating_desc); +} +CLK_OF_DECLARE(armada_375_clk_gating, "marvell,armada-375-gating-clock", + armada_375_clk_gating_init); diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c new file mode 100644 index 00000000000..8bccf4ecdab --- /dev/null +++ b/drivers/clk/mvebu/armada-38x.c @@ -0,0 +1,167 @@ +/* + * Marvell Armada 380/385 SoC clocks + * + * Copyright (C) 2014 Marvell + * + * Gregory CLEMENT <gregory.clement@free-electrons.com> + * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> + * Andrew Lunn <andrew@lunn.ch> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks + * + * SAR[15] : TCLK frequency + * 0 = 250 MHz + * 1 = 200 MHz + */ + +#define SAR_A380_TCLK_FREQ_OPT 15 +#define SAR_A380_TCLK_FREQ_OPT_MASK 0x1 +#define SAR_A380_CPU_DDR_L2_FREQ_OPT 10 +#define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F + +static const u32 armada_38x_tclk_frequencies[] __initconst = { + 250000000, + 200000000, +}; + +static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) +{ + u8 tclk_freq_select; + + tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) & + SAR_A380_TCLK_FREQ_OPT_MASK); + return armada_38x_tclk_frequencies[tclk_freq_select]; +} + +static const u32 armada_38x_cpu_frequencies[] __initconst = { + 0, 0, 0, 0, + 1066 * 1000 * 1000, 0, 0, 0, + 1332 * 1000 * 1000, 0, 0, 0, + 1600 * 1000 * 1000, +}; + +static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) +{ + u8 cpu_freq_select; + + cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) & + SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK); + if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) { + pr_err("Selected CPU frequency (%d) unsupported\n", + cpu_freq_select); + return 0; + } + + return armada_38x_cpu_frequencies[cpu_freq_select]; +} + +enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 }; + +static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { + { .id = A380_CPU_TO_L2, .name = "l2clk" }, + { .id = A380_CPU_TO_DDR, .name = "ddrclk" }, +}; + +static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static void __init armada_38x_get_clk_ratio( + void __iomem *sar, int id, int *mult, int *div) +{ + u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) & + SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK); + + switch (id) { + case A380_CPU_TO_L2: + *mult = armada_38x_cpu_l2_ratios[opt][0]; + *div = armada_38x_cpu_l2_ratios[opt][1]; + break; + case A380_CPU_TO_DDR: + *mult = armada_38x_cpu_ddr_ratios[opt][0]; + *div = armada_38x_cpu_ddr_ratios[opt][1]; + break; + } +} + +static const struct coreclk_soc_desc armada_38x_coreclks = { + .get_tclk_freq = armada_38x_get_tclk_freq, + .get_cpu_freq = armada_38x_get_cpu_freq, + .get_clk_ratio = armada_38x_get_clk_ratio, + .ratios = armada_38x_coreclk_ratios, + .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios), +}; + +static void __init armada_38x_coreclk_init(struct device_node *np) +{ + mvebu_coreclk_setup(np, &armada_38x_coreclks); +} +CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock", + armada_38x_coreclk_init); + +/* + * Clock Gating Control + */ +static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = { + { "audio", NULL, 0 }, + { "ge2", NULL, 2 }, + { "ge1", NULL, 3 }, + { "ge0", NULL, 4 }, + { "pex1", NULL, 5 }, + { "pex2", NULL, 6 }, + { "pex3", NULL, 7 }, + { "pex0", NULL, 8 }, + { "usb3h0", NULL, 9 }, + { "usb3h1", NULL, 10 }, + { "usb3d", NULL, 11 }, + { "bm", NULL, 13 }, + { "crypto0z", NULL, 14 }, + { "sata0", NULL, 15 }, + { "crypto1z", NULL, 16 }, + { "sdio", NULL, 17 }, + { "usb2", NULL, 18 }, + { "crypto1", NULL, 21 }, + { "xor0", NULL, 22 }, + { "crypto0", NULL, 23 }, + { "tdm", NULL, 25 }, + { "xor1", NULL, 28 }, + { "sata1", NULL, 30 }, + { } +}; + +static void __init armada_38x_clk_gating_init(struct device_node *np) +{ + mvebu_clk_gating_setup(np, armada_38x_gating_desc); +} +CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock", + armada_38x_clk_gating_init); diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index 13b62ceb340..b3094315a3c 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -40,7 +40,7 @@ enum { AXP_CPU_TO_NBCLK, AXP_CPU_TO_HCLK, AXP_CPU_TO_DRAMCLK }; -static const struct coreclk_ratio __initconst axp_coreclk_ratios[] = { +static const struct coreclk_ratio axp_coreclk_ratios[] __initconst = { { .id = AXP_CPU_TO_NBCLK, .name = "nbclk" }, { .id = AXP_CPU_TO_HCLK, .name = "hclk" }, { .id = AXP_CPU_TO_DRAMCLK, .name = "dramclk" }, @@ -52,7 +52,7 @@ static u32 __init axp_get_tclk_freq(void __iomem *sar) return 250000000; } -static const u32 __initconst axp_cpu_freqs[] = { +static const u32 axp_cpu_freqs[] __initconst = { 1000000000, 1066000000, 1200000000, @@ -89,7 +89,7 @@ static u32 __init axp_get_cpu_freq(void __iomem *sar) return cpu_freq; } -static const int __initconst axp_nbclk_ratios[32][2] = { +static const int axp_nbclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 1}, {2, 3}, {0, 1}, {1, 2}, {2, 4}, {0, 1}, @@ -100,7 +100,7 @@ static const int __initconst axp_nbclk_ratios[32][2] = { {0, 1}, {0, 1}, {0, 1}, {0, 1}, }; -static const int __initconst axp_hclk_ratios[32][2] = { +static const int axp_hclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 6}, {2, 3}, {1, 3}, {1, 4}, {1, 2}, {2, 6}, {0, 1}, {1, 6}, {2, 10}, {0, 1}, @@ -111,7 +111,7 @@ static const int __initconst axp_hclk_ratios[32][2] = { {0, 1}, {0, 1}, {0, 1}, {0, 1}, }; -static const int __initconst axp_dramclk_ratios[32][2] = { +static const int axp_dramclk_ratios[32][2] __initconst = { {0, 1}, {1, 2}, {2, 3}, {2, 3}, {1, 3}, {1, 2}, {1, 2}, {2, 6}, {0, 1}, {1, 3}, {2, 5}, {0, 1}, @@ -158,18 +158,11 @@ static const struct coreclk_soc_desc axp_coreclks = { .num_ratios = ARRAY_SIZE(axp_coreclk_ratios), }; -static void __init axp_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &axp_coreclks); -} -CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock", - axp_coreclk_init); - /* * Clock Gating Control */ -static const struct clk_gating_soc_desc __initconst axp_gating_desc[] = { +static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = { { "audio", NULL, 0, 0 }, { "ge3", NULL, 1, 0 }, { "ge2", NULL, 2, 0 }, @@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc __initconst axp_gating_desc[] = { { } }; -static void __init axp_clk_gating_init(struct device_node *np) +static void __init axp_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, axp_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock"); + + mvebu_coreclk_setup(np, &axp_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, axp_gating_desc); } -CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock", - axp_clk_gating_init); +CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c new file mode 100644 index 00000000000..d1e5863d337 --- /dev/null +++ b/drivers/clk/mvebu/clk-corediv.c @@ -0,0 +1,315 @@ +/* + * MVEBU Core divider clock + * + * Copyright (C) 2013 Marvell + * + * Ezequiel Garcia <ezequiel.garcia@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include "common.h" + +#define CORE_CLK_DIV_RATIO_MASK 0xff + +/* + * This structure describes the hardware details (bit offset and mask) + * to configure one particular core divider clock. Those hardware + * details may differ from one SoC to another. This structure is + * therefore typically instantiated statically to describe the + * hardware details. + */ +struct clk_corediv_desc { + unsigned int mask; + unsigned int offset; + unsigned int fieldbit; +}; + +/* + * This structure describes the hardware details to configure the core + * divider clocks on a given SoC. Amongst others, it points to the + * array of core divider clock descriptors for this SoC, as well as + * the corresponding operations to manipulate them. + */ +struct clk_corediv_soc_desc { + const struct clk_corediv_desc *descs; + unsigned int ndescs; + const struct clk_ops ops; + u32 ratio_reload; + u32 enable_bit_offset; + u32 ratio_offset; +}; + +/* + * This structure represents one core divider clock for the clock + * framework, and is dynamically allocated for each core divider clock + * existing in the current SoC. + */ +struct clk_corediv { + struct clk_hw hw; + void __iomem *reg; + const struct clk_corediv_desc *desc; + const struct clk_corediv_soc_desc *soc_desc; + spinlock_t lock; +}; + +static struct clk_onecell_data clk_data; + +/* + * Description of the core divider clocks available. For now, we + * support only NAND, and it is available at the same register + * locations regardless of the SoC. + */ +static const struct clk_corediv_desc mvebu_corediv_desc[] = { + { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ +}; + +#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) + +static int clk_corediv_is_enabled(struct clk_hw *hwclk) +{ + struct clk_corediv *corediv = to_corediv_clk(hwclk); + const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; + const struct clk_corediv_desc *desc = corediv->desc; + u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset; + + return !!(readl(corediv->reg) & enable_mask); +} + +static int clk_corediv_enable(struct clk_hw *hwclk) +{ + struct clk_corediv *corediv = to_corediv_clk(hwclk); + const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; + const struct clk_corediv_desc *desc = corediv->desc; + unsigned long flags = 0; + u32 reg; + + spin_lock_irqsave(&corediv->lock, flags); + + reg = readl(corediv->reg); + reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset); + writel(reg, corediv->reg); + + spin_unlock_irqrestore(&corediv->lock, flags); + + return 0; +} + +static void clk_corediv_disable(struct clk_hw *hwclk) +{ + struct clk_corediv *corediv = to_corediv_clk(hwclk); + const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; + const struct clk_corediv_desc *desc = corediv->desc; + unsigned long flags = 0; + u32 reg; + + spin_lock_irqsave(&corediv->lock, flags); + + reg = readl(corediv->reg); + reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset); + writel(reg, corediv->reg); + + spin_unlock_irqrestore(&corediv->lock, flags); +} + +static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk, + unsigned long parent_rate) +{ + struct clk_corediv *corediv = to_corediv_clk(hwclk); + const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; + const struct clk_corediv_desc *desc = corediv->desc; + u32 reg, div; + + reg = readl(corediv->reg + soc_desc->ratio_offset); + div = (reg >> desc->offset) & desc->mask; + return parent_rate / div; +} + +static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate, + unsigned long *parent_rate) +{ + /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ + u32 div; + + div = *parent_rate / rate; + if (div < 4) + div = 4; + else if (div > 6) + div = 8; + + return *parent_rate / div; +} + +static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_corediv *corediv = to_corediv_clk(hwclk); + const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc; + const struct clk_corediv_desc *desc = corediv->desc; + unsigned long flags = 0; + u32 reg, div; + + div = parent_rate / rate; + + spin_lock_irqsave(&corediv->lock, flags); + + /* Write new divider to the divider ratio register */ + reg = readl(corediv->reg + soc_desc->ratio_offset); + reg &= ~(desc->mask << desc->offset); + reg |= (div & desc->mask) << desc->offset; + writel(reg, corediv->reg + soc_desc->ratio_offset); + + /* Set reload-force for this clock */ + reg = readl(corediv->reg) | BIT(desc->fieldbit); + writel(reg, corediv->reg); + + /* Now trigger the clock update */ + reg = readl(corediv->reg) | soc_desc->ratio_reload; + writel(reg, corediv->reg); + + /* + * Wait for clocks to settle down, and then clear all the + * ratios request and the reload request. + */ + udelay(1000); + reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload); + writel(reg, corediv->reg); + udelay(1000); + + spin_unlock_irqrestore(&corediv->lock, flags); + + return 0; +} + +static const struct clk_corediv_soc_desc armada370_corediv_soc = { + .descs = mvebu_corediv_desc, + .ndescs = ARRAY_SIZE(mvebu_corediv_desc), + .ops = { + .enable = clk_corediv_enable, + .disable = clk_corediv_disable, + .is_enabled = clk_corediv_is_enabled, + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(8), + .enable_bit_offset = 24, + .ratio_offset = 0x8, +}; + +static const struct clk_corediv_soc_desc armada380_corediv_soc = { + .descs = mvebu_corediv_desc, + .ndescs = ARRAY_SIZE(mvebu_corediv_desc), + .ops = { + .enable = clk_corediv_enable, + .disable = clk_corediv_disable, + .is_enabled = clk_corediv_is_enabled, + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(8), + .enable_bit_offset = 16, + .ratio_offset = 0x4, +}; + +static const struct clk_corediv_soc_desc armada375_corediv_soc = { + .descs = mvebu_corediv_desc, + .ndescs = ARRAY_SIZE(mvebu_corediv_desc), + .ops = { + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(8), + .ratio_offset = 0x4, +}; + +static void __init +mvebu_corediv_clk_init(struct device_node *node, + const struct clk_corediv_soc_desc *soc_desc) +{ + struct clk_init_data init; + struct clk_corediv *corediv; + struct clk **clks; + void __iomem *base; + const char *parent_name; + const char *clk_name; + int i; + + base = of_iomap(node, 0); + if (WARN_ON(!base)) + return; + + parent_name = of_clk_get_parent_name(node, 0); + + clk_data.clk_num = soc_desc->ndescs; + + /* clks holds the clock array */ + clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), + GFP_KERNEL); + if (WARN_ON(!clks)) + goto err_unmap; + /* corediv holds the clock specific array */ + corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv), + GFP_KERNEL); + if (WARN_ON(!corediv)) + goto err_free_clks; + + spin_lock_init(&corediv->lock); + + for (i = 0; i < clk_data.clk_num; i++) { + of_property_read_string_index(node, "clock-output-names", + i, &clk_name); + init.num_parents = 1; + init.parent_names = &parent_name; + init.name = clk_name; + init.ops = &soc_desc->ops; + init.flags = 0; + + corediv[i].soc_desc = soc_desc; + corediv[i].desc = soc_desc->descs + i; + corediv[i].reg = base; + corediv[i].hw.init = &init; + + clks[i] = clk_register(NULL, &corediv[i].hw); + WARN_ON(IS_ERR(clks[i])); + } + + clk_data.clks = clks; + of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data); + return; + +err_free_clks: + kfree(clks); +err_unmap: + iounmap(base); +} + +static void __init armada370_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &armada370_corediv_soc); +} +CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock", + armada370_corediv_clk_init); + +static void __init armada375_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &armada375_corediv_soc); +} +CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock", + armada375_corediv_clk_init); + +static void __init armada380_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &armada380_corediv_soc); +} +CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", + armada380_corediv_clk_init); diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index b0fbc071549..8ebf757d29e 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -101,7 +101,7 @@ static const struct clk_ops cpu_ops = { .set_rate = clk_cpu_set_rate, }; -void __init of_cpu_clk_setup(struct device_node *node) +static void __init of_cpu_clk_setup(struct device_node *node) { struct cpu_clk *cpuclk; void __iomem *clock_complex_base = of_iomap(node, 0); @@ -119,7 +119,7 @@ void __init of_cpu_clk_setup(struct device_node *node) cpuclk = kzalloc(ncpus * sizeof(*cpuclk), GFP_KERNEL); if (WARN_ON(!cpuclk)) - return; + goto cpuclk_out; clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL); if (WARN_ON(!clks)) @@ -170,6 +170,8 @@ bail_out: kfree(cpuclk[ncpus].clk_name); clks_out: kfree(cpuclk); +cpuclk_out: + iounmap(clock_complex_base); } CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock", diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index adaa4a1821b..25ceccf939a 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -45,8 +45,10 @@ void __init mvebu_coreclk_setup(struct device_node *np, clk_data.clk_num = 2 + desc->num_ratios; clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *), GFP_KERNEL); - if (WARN_ON(!clk_data.clks)) + if (WARN_ON(!clk_data.clks)) { + iounmap(base); return; + } /* Register TCLK */ of_property_read_string_index(np, "clock-output-names", 0, @@ -134,7 +136,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np, ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); if (WARN_ON(!ctrl)) - return; + goto ctrl_out; spin_lock_init(&ctrl->lock); @@ -145,10 +147,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, ctrl->num_gates = n; ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *), GFP_KERNEL); - if (WARN_ON(!ctrl->gates)) { - kfree(ctrl); - return; - } + if (WARN_ON(!ctrl->gates)) + goto gates_out; for (n = 0; n < ctrl->num_gates; n++) { const char *parent = @@ -160,4 +160,10 @@ void __init mvebu_clk_gating_setup(struct device_node *np, } of_clk_add_provider(np, clk_gating_get_src, ctrl); + + return; +gates_out: + kfree(ctrl); +ctrl_out: + iounmap(base); } diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index 79d7aedf03f..b8c2424ac92 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -74,12 +74,12 @@ enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR }; -static const struct coreclk_ratio __initconst dove_coreclk_ratios[] = { +static const struct coreclk_ratio dove_coreclk_ratios[] __initconst = { { .id = DOVE_CPU_TO_L2, .name = "l2clk", }, { .id = DOVE_CPU_TO_DDR, .name = "ddrclk", } }; -static const u32 __initconst dove_tclk_freqs[] = { +static const u32 dove_tclk_freqs[] __initconst = { 166666667, 125000000, 0, 0 @@ -92,7 +92,7 @@ static u32 __init dove_get_tclk_freq(void __iomem *sar) return dove_tclk_freqs[opt]; } -static const u32 __initconst dove_cpu_freqs[] = { +static const u32 dove_cpu_freqs[] __initconst = { 0, 0, 0, 0, 0, 1000000000, 933333333, 933333333, @@ -111,12 +111,12 @@ static u32 __init dove_get_cpu_freq(void __iomem *sar) return dove_cpu_freqs[opt]; } -static const int __initconst dove_cpu_l2_ratios[8][2] = { +static const int dove_cpu_l2_ratios[8][2] __initconst = { { 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 } }; -static const int __initconst dove_cpu_ddr_ratios[16][2] = { +static const int dove_cpu_ddr_ratios[16][2] __initconst = { { 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 }, { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }, { 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 }, @@ -154,17 +154,11 @@ static const struct coreclk_soc_desc dove_coreclks = { .num_ratios = ARRAY_SIZE(dove_coreclk_ratios), }; -static void __init dove_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &dove_coreclks); -} -CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init); - /* * Clock Gating Control */ -static const struct clk_gating_soc_desc __initconst dove_gating_desc[] = { +static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = { { "usb0", NULL, 0, 0 }, { "usb1", NULL, 1, 0 }, { "ge", "gephy", 2, 0 }, @@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc __initconst dove_gating_desc[] = { { } }; -static void __init dove_clk_gating_init(struct device_node *np) +static void __init dove_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, dove_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock"); + + mvebu_coreclk_setup(np, &dove_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, dove_gating_desc); } -CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock", - dove_clk_gating_init); +CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index 71d24619ccd..ddb666a8650 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -78,7 +78,7 @@ enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR }; -static const struct coreclk_ratio __initconst kirkwood_coreclk_ratios[] = { +static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = { { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", }, { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", } }; @@ -90,7 +90,7 @@ static u32 __init kirkwood_get_tclk_freq(void __iomem *sar) return (opt) ? 166666667 : 200000000; } -static const u32 __initconst kirkwood_cpu_freqs[] = { +static const u32 kirkwood_cpu_freqs[] __initconst = { 0, 0, 0, 0, 600000000, 0, @@ -111,12 +111,12 @@ static u32 __init kirkwood_get_cpu_freq(void __iomem *sar) return kirkwood_cpu_freqs[opt]; } -static const int __initconst kirkwood_cpu_l2_ratios[8][2] = { +static const int kirkwood_cpu_l2_ratios[8][2] __initconst = { { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 } }; -static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = { +static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = { { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 }, { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 }, @@ -145,7 +145,7 @@ static void __init kirkwood_get_clk_ratio( } } -static const u32 __initconst mv88f6180_cpu_freqs[] = { +static const u32 mv88f6180_cpu_freqs[] __initconst = { 0, 0, 0, 0, 0, 600000000, 800000000, @@ -158,7 +158,7 @@ static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar) return mv88f6180_cpu_freqs[opt]; } -static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = { +static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = { { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 } }; @@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = { .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), }; -static void __init kirkwood_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &kirkwood_coreclks); -} -CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock", - kirkwood_coreclk_init); - static const struct coreclk_soc_desc mv88f6180_coreclks = { .get_tclk_freq = kirkwood_get_tclk_freq, .get_cpu_freq = mv88f6180_get_cpu_freq, @@ -208,18 +201,11 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = { .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), }; -static void __init mv88f6180_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &mv88f6180_coreclks); -} -CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock", - mv88f6180_coreclk_init); - /* * Clock Gating Control */ -static const struct clk_gating_soc_desc __initconst kirkwood_gating_desc[] = { +static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { { "ge0", NULL, 0, 0 }, { "pex0", NULL, 2, 0 }, { "usb0", NULL, 3, 0 }, @@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc __initconst kirkwood_gating_desc[] = { { } }; -static void __init kirkwood_clk_gating_init(struct device_node *np) +static void __init kirkwood_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, kirkwood_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock"); + + + if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock")) + mvebu_coreclk_setup(np, &mv88f6180_coreclks); + else + mvebu_coreclk_setup(np, &kirkwood_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); } -CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock", - kirkwood_clk_gating_init); +CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", + kirkwood_clk_init); +CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock", + kirkwood_clk_init); diff --git a/drivers/clk/mvebu/orion.c b/drivers/clk/mvebu/orion.c new file mode 100644 index 00000000000..fd129566c1c --- /dev/null +++ b/drivers/clk/mvebu/orion.c @@ -0,0 +1,210 @@ +/* + * Marvell Orion SoC clocks + * + * Copyright (C) 2014 Thomas Petazzoni + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = { + { .id = 0, .name = "ddrclk", } +}; + +/* + * Orion 5182 + */ + +#define SAR_MV88F5182_TCLK_FREQ 8 +#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3 + +static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) & + SAR_MV88F5182_TCLK_FREQ_MASK; + if (opt == 1) + return 150000000; + else if (opt == 2) + return 166666667; + else + return 0; +} + +#define SAR_MV88F5182_CPU_FREQ 4 +#define SAR_MV88F5182_CPU_FREQ_MASK 0xf + +static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & + SAR_MV88F5182_CPU_FREQ_MASK; + if (opt == 0) + return 333333333; + else if (opt == 1 || opt == 2) + return 400000000; + else if (opt == 3) + return 500000000; + else + return 0; +} + +static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) & + SAR_MV88F5182_CPU_FREQ_MASK; + if (opt == 0 || opt == 1) { + *mult = 1; + *div = 2; + } else if (opt == 2 || opt == 3) { + *mult = 1; + *div = 3; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f5182_coreclks = { + .get_tclk_freq = mv88f5182_get_tclk_freq, + .get_cpu_freq = mv88f5182_get_cpu_freq, + .get_clk_ratio = mv88f5182_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + +static void __init mv88f5182_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f5182_coreclks); +} + +CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init); + +/* + * Orion 5281 + */ + +static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar) +{ + /* On 5281, tclk is always 166 Mhz */ + return 166666667; +} + +#define SAR_MV88F5281_CPU_FREQ 4 +#define SAR_MV88F5281_CPU_FREQ_MASK 0xf + +static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & + SAR_MV88F5281_CPU_FREQ_MASK; + if (opt == 1 || opt == 2) + return 400000000; + else if (opt == 3) + return 500000000; + else + return 0; +} + +static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) & + SAR_MV88F5281_CPU_FREQ_MASK; + if (opt == 1) { + *mult = 1; + *div = 2; + } else if (opt == 2 || opt == 3) { + *mult = 1; + *div = 3; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f5281_coreclks = { + .get_tclk_freq = mv88f5281_get_tclk_freq, + .get_cpu_freq = mv88f5281_get_cpu_freq, + .get_clk_ratio = mv88f5281_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + +static void __init mv88f5281_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f5281_coreclks); +} + +CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init); + +/* + * Orion 6183 + */ + +#define SAR_MV88F6183_TCLK_FREQ 9 +#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1 + +static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) & + SAR_MV88F6183_TCLK_FREQ_MASK; + if (opt == 0) + return 133333333; + else if (opt == 1) + return 166666667; + else + return 0; +} + +#define SAR_MV88F6183_CPU_FREQ 1 +#define SAR_MV88F6183_CPU_FREQ_MASK 0x3f + +static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & + SAR_MV88F6183_CPU_FREQ_MASK; + if (opt == 9) + return 333333333; + else if (opt == 17) + return 400000000; + else + return 0; +} + +static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id, + int *mult, int *div) +{ + u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) & + SAR_MV88F6183_CPU_FREQ_MASK; + if (opt == 9 || opt == 17) { + *mult = 1; + *div = 2; + } else { + *mult = 0; + *div = 1; + } +} + +static const struct coreclk_soc_desc mv88f6183_coreclks = { + .get_tclk_freq = mv88f6183_get_tclk_freq, + .get_cpu_freq = mv88f6183_get_cpu_freq, + .get_clk_ratio = mv88f6183_get_clk_ratio, + .ratios = orion_coreclk_ratios, + .num_ratios = ARRAY_SIZE(orion_coreclk_ratios), +}; + + +static void __init mv88f6183_clk_init(struct device_node *np) +{ + return mvebu_coreclk_setup(np, &mv88f6183_coreclks); +} + +CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init); |
