xref: /linux/drivers/clk/mvebu/mv98dx3236.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /*
2  * Marvell MV98DX3236 SoC clocks
3  *
4  * Copyright (C) 2012 Marvell
5  *
6  * Gregory CLEMENT <gregory.clement@free-electrons.com>
7  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
8  * Andrew Lunn <andrew@lunn.ch>
9  *
10  * This file is licensed under the terms of the GNU General Public
11  * License version 2.  This program is licensed "as is" without any
12  * warranty of any kind, whether express or implied.
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/clk-provider.h>
17 #include <linux/io.h>
18 #include <linux/of.h>
19 #include "common.h"
20 
21 
22 /*
23  * For 98DX4251 Sample At Reset the CPU, DDR and Main PLL clocks are all
24  * defined at the same time
25  *
26  * SAR1[20:18]   : CPU frequency    DDR frequency   MPLL frequency
27  *		 0  =  400 MHz	    400 MHz	    800 MHz
28  *		 2  =  667 MHz	    667 MHz	    2000 MHz
29  *		 3  =  800 MHz	    800 MHz	    1600 MHz
30  *		 others reserved.
31  *
32  * For 98DX3236 Sample At Reset the CPU, DDR and Main PLL clocks are all
33  * defined at the same time
34  *
35  * SAR1[20:18]   : CPU frequency    DDR frequency   MPLL frequency
36  *		 1  =  667 MHz	    667 MHz	    2000 MHz
37  *		 2  =  400 MHz	    400 MHz	    400 MHz
38  *		 3  =  800 MHz	    800 MHz	    800 MHz
39  *		 5  =  800 MHz	    400 MHz	    800 MHz
40  *		 others reserved.
41  */
42 
43 #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT		18
44 #define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK	0x7
45 
46 static u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar)
47 {
48 	/* Tclk = 200MHz, no SaR dependency */
49 	return 200000000;
50 }
51 
52 static const u32 mv98dx3236_cpu_frequencies[] __initconst = {
53 	0,
54 	667000000,
55 	400000000,
56 	800000000,
57 	0,
58 	800000000,
59 	0, 0,
60 };
61 
62 static const u32 mv98dx4251_cpu_frequencies[] __initconst = {
63 	400000000,
64 	0,
65 	667000000,
66 	800000000,
67 	0, 0, 0, 0,
68 };
69 
70 static u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar)
71 {
72 	u32 cpu_freq = 0;
73 	u8 cpu_freq_select = 0;
74 
75 	cpu_freq_select = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
76 			   SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
77 
78 	if (of_machine_is_compatible("marvell,armadaxp-98dx4251"))
79 		cpu_freq = mv98dx4251_cpu_frequencies[cpu_freq_select];
80 	else if (of_machine_is_compatible("marvell,armadaxp-98dx3236"))
81 		cpu_freq = mv98dx3236_cpu_frequencies[cpu_freq_select];
82 
83 	if (!cpu_freq)
84 		pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
85 
86 	return cpu_freq;
87 }
88 
89 enum {
90 	MV98DX3236_CPU_TO_DDR,
91 	MV98DX3236_CPU_TO_MPLL
92 };
93 
94 static const struct coreclk_ratio mv98dx3236_core_ratios[] __initconst = {
95 	{ .id = MV98DX3236_CPU_TO_DDR, .name = "ddrclk" },
96 	{ .id = MV98DX3236_CPU_TO_MPLL, .name = "mpll" },
97 };
98 
99 static const int __initconst mv98dx3236_cpu_mpll_ratios[8][2] = {
100 	{0, 1}, {3, 1}, {1, 1}, {1, 1},
101 	{0, 1}, {1, 1}, {0, 1}, {0, 1},
102 };
103 
104 static const int __initconst mv98dx3236_cpu_ddr_ratios[8][2] = {
105 	{0, 1}, {1, 1}, {1, 1}, {1, 1},
106 	{0, 1}, {1, 2}, {0, 1}, {0, 1},
107 };
108 
109 static const int __initconst mv98dx4251_cpu_mpll_ratios[8][2] = {
110 	{2, 1}, {0, 1}, {3, 1}, {2, 1},
111 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
112 };
113 
114 static const int __initconst mv98dx4251_cpu_ddr_ratios[8][2] = {
115 	{1, 1}, {0, 1}, {1, 1}, {1, 1},
116 	{0, 1}, {0, 1}, {0, 1}, {0, 1},
117 };
118 
119 static void __init mv98dx3236_get_clk_ratio(
120 	void __iomem *sar, int id, int *mult, int *div)
121 {
122 	u32 opt = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) &
123 		SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK);
124 
125 	switch (id) {
126 	case MV98DX3236_CPU_TO_DDR:
127 		if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
128 			*mult = mv98dx4251_cpu_ddr_ratios[opt][0];
129 			*div = mv98dx4251_cpu_ddr_ratios[opt][1];
130 		} else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
131 			*mult = mv98dx3236_cpu_ddr_ratios[opt][0];
132 			*div = mv98dx3236_cpu_ddr_ratios[opt][1];
133 		}
134 		break;
135 	case MV98DX3236_CPU_TO_MPLL:
136 		if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) {
137 			*mult = mv98dx4251_cpu_mpll_ratios[opt][0];
138 			*div = mv98dx4251_cpu_mpll_ratios[opt][1];
139 		} else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) {
140 			*mult = mv98dx3236_cpu_mpll_ratios[opt][0];
141 			*div = mv98dx3236_cpu_mpll_ratios[opt][1];
142 		}
143 		break;
144 	}
145 }
146 
147 static const struct coreclk_soc_desc mv98dx3236_core_clocks = {
148 	.get_tclk_freq = mv98dx3236_get_tclk_freq,
149 	.get_cpu_freq = mv98dx3236_get_cpu_freq,
150 	.get_clk_ratio = mv98dx3236_get_clk_ratio,
151 	.ratios = mv98dx3236_core_ratios,
152 	.num_ratios = ARRAY_SIZE(mv98dx3236_core_ratios),
153 };
154 
155 
156 /*
157  * Clock Gating Control
158  */
159 
160 static const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = {
161 	{ "ge1", NULL, 3, 0 },
162 	{ "ge0", NULL, 4, 0 },
163 	{ "pex00", NULL, 5, 0 },
164 	{ "sdio", NULL, 17, 0 },
165 	{ "usb0", NULL, 18, 0 },
166 	{ "xor0", NULL, 22, 0 },
167 	{ }
168 };
169 
170 static void __init mv98dx3236_clk_init(struct device_node *np)
171 {
172 	struct device_node *cgnp =
173 		of_find_compatible_node(NULL, NULL, "marvell,mv98dx3236-gating-clock");
174 
175 	mvebu_coreclk_setup(np, &mv98dx3236_core_clocks);
176 
177 	if (cgnp)
178 		mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc);
179 }
180 CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init);
181