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