xref: /openbmc/linux/drivers/clk/mvebu/mv98dx3236.c (revision 9b4eedf6)
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 
1759b4eedf6SYangtao Li 	if (cgnp) {
17633707260SChris Packham 		mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc);
1779b4eedf6SYangtao Li 		of_node_put(cgnp);
1789b4eedf6SYangtao Li 	}
17933707260SChris Packham }
18033707260SChris Packham CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init);
181