1c3828949SGregory CLEMENT // SPDX-License-Identifier: GPL-2.0
233707260SChris Packham /*
333707260SChris Packham * Marvell MV98DX3236 SoC clocks
433707260SChris Packham *
533707260SChris Packham * Copyright (C) 2012 Marvell
633707260SChris Packham *
733707260SChris Packham * Gregory CLEMENT <gregory.clement@free-electrons.com>
833707260SChris Packham * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
933707260SChris Packham * Andrew Lunn <andrew@lunn.ch>
1033707260SChris Packham *
1133707260SChris Packham */
1233707260SChris Packham
1333707260SChris Packham #include <linux/kernel.h>
1433707260SChris Packham #include <linux/clk-provider.h>
1533707260SChris Packham #include <linux/io.h>
1633707260SChris Packham #include <linux/of.h>
1733707260SChris Packham #include "common.h"
1833707260SChris Packham
1933707260SChris Packham
2033707260SChris Packham /*
2133707260SChris Packham * For 98DX4251 Sample At Reset the CPU, DDR and Main PLL clocks are all
2233707260SChris Packham * defined at the same time
2333707260SChris Packham *
2433707260SChris Packham * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency
2533707260SChris Packham * 0 = 400 MHz 400 MHz 800 MHz
2633707260SChris Packham * 2 = 667 MHz 667 MHz 2000 MHz
2733707260SChris Packham * 3 = 800 MHz 800 MHz 1600 MHz
2833707260SChris Packham * others reserved.
2933707260SChris Packham *
3033707260SChris Packham * For 98DX3236 Sample At Reset the CPU, DDR and Main PLL clocks are all
3133707260SChris Packham * defined at the same time
3233707260SChris Packham *
3333707260SChris Packham * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency
3433707260SChris Packham * 1 = 667 MHz 667 MHz 2000 MHz
3533707260SChris Packham * 2 = 400 MHz 400 MHz 400 MHz
3633707260SChris Packham * 3 = 800 MHz 800 MHz 800 MHz
3733707260SChris Packham * 5 = 800 MHz 400 MHz 800 MHz
3833707260SChris Packham * others reserved.
3933707260SChris Packham */
4033707260SChris Packham
4133707260SChris Packham #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT 18
4233707260SChris Packham #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK 0x7
4333707260SChris Packham
mv98dx3236_get_tclk_freq(void __iomem * sar)4433707260SChris Packham static u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar)
4533707260SChris Packham {
4633707260SChris Packham /* Tclk = 200MHz, no SaR dependency */
4733707260SChris Packham return 200000000;
4833707260SChris Packham }
4933707260SChris Packham
5033707260SChris Packham static const u32 mv98dx3236_cpu_frequencies[] __initconst = {
5133707260SChris Packham 0,
5233707260SChris Packham 667000000,
5333707260SChris Packham 400000000,
5433707260SChris Packham 800000000,
5533707260SChris Packham 0,
5633707260SChris Packham 800000000,
5733707260SChris Packham 0, 0,
5833707260SChris Packham };
5933707260SChris Packham
6033707260SChris Packham static const u32 mv98dx4251_cpu_frequencies[] __initconst = {
6133707260SChris Packham 400000000,
6233707260SChris Packham 0,
6333707260SChris Packham 667000000,
6433707260SChris Packham 800000000,
6533707260SChris Packham 0, 0, 0, 0,
6633707260SChris Packham };
6733707260SChris Packham
mv98dx3236_get_cpu_freq(void __iomem * sar)6833707260SChris Packham static u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar)
6933707260SChris Packham {
7033707260SChris Packham u32 cpu_freq = 0;
7133707260SChris Packham u8 cpu_freq_select = 0;
7233707260SChris Packham
7333707260SChris Packham cpu_freq_select = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
7433707260SChris Packham SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
7533707260SChris Packham
7633707260SChris Packham if (of_machine_is_compatible("marvell,armadaxp-98dx4251"))
7733707260SChris Packham cpu_freq = mv98dx4251_cpu_frequencies[cpu_freq_select];
7833707260SChris Packham else if (of_machine_is_compatible("marvell,armadaxp-98dx3236"))
7933707260SChris Packham cpu_freq = mv98dx3236_cpu_frequencies[cpu_freq_select];
8033707260SChris Packham
8133707260SChris Packham if (!cpu_freq)
8233707260SChris Packham pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
8333707260SChris Packham
8433707260SChris Packham return cpu_freq;
8533707260SChris Packham }
8633707260SChris Packham
8733707260SChris Packham enum {
8833707260SChris Packham MV98DX3236_CPU_TO_DDR,
8933707260SChris Packham MV98DX3236_CPU_TO_MPLL
9033707260SChris Packham };
9133707260SChris Packham
9233707260SChris Packham static const struct coreclk_ratio mv98dx3236_core_ratios[] __initconst = {
9333707260SChris Packham { .id = MV98DX3236_CPU_TO_DDR, .name = "ddrclk" },
9433707260SChris Packham { .id = MV98DX3236_CPU_TO_MPLL, .name = "mpll" },
9533707260SChris Packham };
9633707260SChris Packham
9733707260SChris Packham static const int __initconst mv98dx3236_cpu_mpll_ratios[8][2] = {
9833707260SChris Packham {0, 1}, {3, 1}, {1, 1}, {1, 1},
9933707260SChris Packham {0, 1}, {1, 1}, {0, 1}, {0, 1},
10033707260SChris Packham };
10133707260SChris Packham
10233707260SChris Packham static const int __initconst mv98dx3236_cpu_ddr_ratios[8][2] = {
10333707260SChris Packham {0, 1}, {1, 1}, {1, 1}, {1, 1},
10433707260SChris Packham {0, 1}, {1, 2}, {0, 1}, {0, 1},
10533707260SChris Packham };
10633707260SChris Packham
10733707260SChris Packham static const int __initconst mv98dx4251_cpu_mpll_ratios[8][2] = {
10833707260SChris Packham {2, 1}, {0, 1}, {3, 1}, {2, 1},
10933707260SChris Packham {0, 1}, {0, 1}, {0, 1}, {0, 1},
11033707260SChris Packham };
11133707260SChris Packham
11233707260SChris Packham static const int __initconst mv98dx4251_cpu_ddr_ratios[8][2] = {
11333707260SChris Packham {1, 1}, {0, 1}, {1, 1}, {1, 1},
11433707260SChris Packham {0, 1}, {0, 1}, {0, 1}, {0, 1},
11533707260SChris Packham };
11633707260SChris Packham
mv98dx3236_get_clk_ratio(void __iomem * sar,int id,int * mult,int * div)11733707260SChris Packham static void __init mv98dx3236_get_clk_ratio(
11833707260SChris Packham void __iomem *sar, int id, int *mult, int *div)
11933707260SChris Packham {
12033707260SChris Packham u32 opt = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
12133707260SChris Packham SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
12233707260SChris Packham
12333707260SChris Packham switch (id) {
12433707260SChris Packham case MV98DX3236_CPU_TO_DDR:
12533707260SChris Packham if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
12633707260SChris Packham *mult = mv98dx4251_cpu_ddr_ratios[opt][0];
12733707260SChris Packham *div = mv98dx4251_cpu_ddr_ratios[opt][1];
12833707260SChris Packham } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
12933707260SChris Packham *mult = mv98dx3236_cpu_ddr_ratios[opt][0];
13033707260SChris Packham *div = mv98dx3236_cpu_ddr_ratios[opt][1];
13133707260SChris Packham }
13233707260SChris Packham break;
13333707260SChris Packham case MV98DX3236_CPU_TO_MPLL:
13433707260SChris Packham if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
13533707260SChris Packham *mult = mv98dx4251_cpu_mpll_ratios[opt][0];
13633707260SChris Packham *div = mv98dx4251_cpu_mpll_ratios[opt][1];
13733707260SChris Packham } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
13833707260SChris Packham *mult = mv98dx3236_cpu_mpll_ratios[opt][0];
13933707260SChris Packham *div = mv98dx3236_cpu_mpll_ratios[opt][1];
14033707260SChris Packham }
14133707260SChris Packham break;
14233707260SChris Packham }
14333707260SChris Packham }
14433707260SChris Packham
14533707260SChris Packham static const struct coreclk_soc_desc mv98dx3236_core_clocks = {
14633707260SChris Packham .get_tclk_freq = mv98dx3236_get_tclk_freq,
14733707260SChris Packham .get_cpu_freq = mv98dx3236_get_cpu_freq,
14833707260SChris Packham .get_clk_ratio = mv98dx3236_get_clk_ratio,
14933707260SChris Packham .ratios = mv98dx3236_core_ratios,
15033707260SChris Packham .num_ratios = ARRAY_SIZE(mv98dx3236_core_ratios),
15133707260SChris Packham };
15233707260SChris Packham
15333707260SChris Packham
15433707260SChris Packham /*
15533707260SChris Packham * Clock Gating Control
15633707260SChris Packham */
15733707260SChris Packham
15833707260SChris Packham static const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = {
15933707260SChris Packham { "ge1", NULL, 3, 0 },
16033707260SChris Packham { "ge0", NULL, 4, 0 },
16133707260SChris Packham { "pex00", NULL, 5, 0 },
16233707260SChris Packham { "sdio", NULL, 17, 0 },
16333707260SChris Packham { "usb0", NULL, 18, 0 },
16433707260SChris Packham { "xor0", NULL, 22, 0 },
16533707260SChris Packham { }
16633707260SChris Packham };
16733707260SChris Packham
mv98dx3236_clk_init(struct device_node * np)16833707260SChris Packham static void __init mv98dx3236_clk_init(struct device_node *np)
16933707260SChris Packham {
17033707260SChris Packham struct device_node *cgnp =
17133707260SChris Packham of_find_compatible_node(NULL, NULL, "marvell,mv98dx3236-gating-clock");
17233707260SChris Packham
17333707260SChris Packham mvebu_coreclk_setup(np, &mv98dx3236_core_clocks);
17433707260SChris Packham
175*9b4eedf6SYangtao Li if (cgnp) {
17633707260SChris Packham mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc);
177*9b4eedf6SYangtao Li of_node_put(cgnp);
178*9b4eedf6SYangtao Li }
17933707260SChris Packham }
18033707260SChris Packham CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init);
181