1/*
2 * Marvell Orion SoC clocks
3 *
4 * Copyright (C) 2014 Thomas Petazzoni
5 *
6 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2.  This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/clk-provider.h>
15#include <linux/io.h>
16#include <linux/of.h>
17#include "common.h"
18
19static const struct coreclk_ratio orion_coreclk_ratios[] __initconst = {
20	{ .id = 0, .name = "ddrclk", }
21};
22
23/*
24 * Orion 5182
25 */
26
27#define SAR_MV88F5182_TCLK_FREQ      8
28#define SAR_MV88F5182_TCLK_FREQ_MASK 0x3
29
30static u32 __init mv88f5182_get_tclk_freq(void __iomem *sar)
31{
32	u32 opt = (readl(sar) >> SAR_MV88F5182_TCLK_FREQ) &
33		SAR_MV88F5182_TCLK_FREQ_MASK;
34	if (opt == 1)
35		return 150000000;
36	else if (opt == 2)
37		return 166666667;
38	else
39		return 0;
40}
41
42#define SAR_MV88F5182_CPU_FREQ       4
43#define SAR_MV88F5182_CPU_FREQ_MASK  0xf
44
45static u32 __init mv88f5182_get_cpu_freq(void __iomem *sar)
46{
47	u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
48		SAR_MV88F5182_CPU_FREQ_MASK;
49	if (opt == 0)
50		return 333333333;
51	else if (opt == 1 || opt == 2)
52		return 400000000;
53	else if (opt == 3)
54		return 500000000;
55	else
56		return 0;
57}
58
59static void __init mv88f5182_get_clk_ratio(void __iomem *sar, int id,
60					   int *mult, int *div)
61{
62	u32 opt = (readl(sar) >> SAR_MV88F5182_CPU_FREQ) &
63		SAR_MV88F5182_CPU_FREQ_MASK;
64	if (opt == 0 || opt == 1) {
65		*mult = 1;
66		*div  = 2;
67	} else if (opt == 2 || opt == 3) {
68		*mult = 1;
69		*div  = 3;
70	} else {
71		*mult = 0;
72		*div  = 1;
73	}
74}
75
76static const struct coreclk_soc_desc mv88f5182_coreclks = {
77	.get_tclk_freq = mv88f5182_get_tclk_freq,
78	.get_cpu_freq = mv88f5182_get_cpu_freq,
79	.get_clk_ratio = mv88f5182_get_clk_ratio,
80	.ratios = orion_coreclk_ratios,
81	.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
82};
83
84static void __init mv88f5182_clk_init(struct device_node *np)
85{
86	return mvebu_coreclk_setup(np, &mv88f5182_coreclks);
87}
88
89CLK_OF_DECLARE(mv88f5182_clk, "marvell,mv88f5182-core-clock", mv88f5182_clk_init);
90
91/*
92 * Orion 5281
93 */
94
95static u32 __init mv88f5281_get_tclk_freq(void __iomem *sar)
96{
97	/* On 5281, tclk is always 166 Mhz */
98	return 166666667;
99}
100
101#define SAR_MV88F5281_CPU_FREQ       4
102#define SAR_MV88F5281_CPU_FREQ_MASK  0xf
103
104static u32 __init mv88f5281_get_cpu_freq(void __iomem *sar)
105{
106	u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
107		SAR_MV88F5281_CPU_FREQ_MASK;
108	if (opt == 1 || opt == 2)
109		return 400000000;
110	else if (opt == 3)
111		return 500000000;
112	else
113		return 0;
114}
115
116static void __init mv88f5281_get_clk_ratio(void __iomem *sar, int id,
117					   int *mult, int *div)
118{
119	u32 opt = (readl(sar) >> SAR_MV88F5281_CPU_FREQ) &
120		SAR_MV88F5281_CPU_FREQ_MASK;
121	if (opt == 1) {
122		*mult = 1;
123		*div = 2;
124	} else if (opt == 2 || opt == 3) {
125		*mult = 1;
126		*div = 3;
127	} else {
128		*mult = 0;
129		*div = 1;
130	}
131}
132
133static const struct coreclk_soc_desc mv88f5281_coreclks = {
134	.get_tclk_freq = mv88f5281_get_tclk_freq,
135	.get_cpu_freq = mv88f5281_get_cpu_freq,
136	.get_clk_ratio = mv88f5281_get_clk_ratio,
137	.ratios = orion_coreclk_ratios,
138	.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
139};
140
141static void __init mv88f5281_clk_init(struct device_node *np)
142{
143	return mvebu_coreclk_setup(np, &mv88f5281_coreclks);
144}
145
146CLK_OF_DECLARE(mv88f5281_clk, "marvell,mv88f5281-core-clock", mv88f5281_clk_init);
147
148/*
149 * Orion 6183
150 */
151
152#define SAR_MV88F6183_TCLK_FREQ      9
153#define SAR_MV88F6183_TCLK_FREQ_MASK 0x1
154
155static u32 __init mv88f6183_get_tclk_freq(void __iomem *sar)
156{
157	u32 opt = (readl(sar) >> SAR_MV88F6183_TCLK_FREQ) &
158		SAR_MV88F6183_TCLK_FREQ_MASK;
159	if (opt == 0)
160		return 133333333;
161	else if (opt == 1)
162		return 166666667;
163	else
164		return 0;
165}
166
167#define SAR_MV88F6183_CPU_FREQ       1
168#define SAR_MV88F6183_CPU_FREQ_MASK  0x3f
169
170static u32 __init mv88f6183_get_cpu_freq(void __iomem *sar)
171{
172	u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
173		SAR_MV88F6183_CPU_FREQ_MASK;
174	if (opt == 9)
175		return 333333333;
176	else if (opt == 17)
177		return 400000000;
178	else
179		return 0;
180}
181
182static void __init mv88f6183_get_clk_ratio(void __iomem *sar, int id,
183					   int *mult, int *div)
184{
185	u32 opt = (readl(sar) >> SAR_MV88F6183_CPU_FREQ) &
186		SAR_MV88F6183_CPU_FREQ_MASK;
187	if (opt == 9 || opt == 17) {
188		*mult = 1;
189		*div  = 2;
190	} else {
191		*mult = 0;
192		*div  = 1;
193	}
194}
195
196static const struct coreclk_soc_desc mv88f6183_coreclks = {
197	.get_tclk_freq = mv88f6183_get_tclk_freq,
198	.get_cpu_freq = mv88f6183_get_cpu_freq,
199	.get_clk_ratio = mv88f6183_get_clk_ratio,
200	.ratios = orion_coreclk_ratios,
201	.num_ratios = ARRAY_SIZE(orion_coreclk_ratios),
202};
203
204
205static void __init mv88f6183_clk_init(struct device_node *np)
206{
207	return mvebu_coreclk_setup(np, &mv88f6183_coreclks);
208}
209
210CLK_OF_DECLARE(mv88f6183_clk, "marvell,mv88f6183-core-clock", mv88f6183_clk_init);
211