• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Marvell MVEBU clock gating control.
3  *
4  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
5  * Andrew Lunn <andrew@lunn.ch>
6  *
7  * This file is licensed under the terms of the GNU General Public
8  * License version 2. This program is licensed "as is" without any
9  * warranty of any kind, whether express or implied.
10  */
11 #include <linux/kernel.h>
12 #include <linux/bitops.h>
13 #include <linux/io.h>
14 #include <linux/clk.h>
15 #include <linux/clkdev.h>
16 #include <linux/clk-provider.h>
17 #include <linux/clk/mvebu.h>
18 #include <linux/of.h>
19 #include <linux/of_address.h>
20 
21 struct mvebu_gating_ctrl {
22 	spinlock_t lock;
23 	struct clk **gates;
24 	int num_gates;
25 };
26 
27 struct mvebu_soc_descr {
28 	const char *name;
29 	const char *parent;
30 	int bit_idx;
31 };
32 
33 #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
34 
mvebu_clk_gating_get_src(struct of_phandle_args * clkspec,void * data)35 static struct clk *mvebu_clk_gating_get_src(
36 	struct of_phandle_args *clkspec, void *data)
37 {
38 	struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data;
39 	int n;
40 
41 	if (clkspec->args_count < 1)
42 		return ERR_PTR(-EINVAL);
43 
44 	for (n = 0; n < ctrl->num_gates; n++) {
45 		struct clk_gate *gate =
46 			to_clk_gate(__clk_get_hw(ctrl->gates[n]));
47 		if (clkspec->args[0] == gate->bit_idx)
48 			return ctrl->gates[n];
49 	}
50 	return ERR_PTR(-ENODEV);
51 }
52 
mvebu_clk_gating_setup(struct device_node * np,const struct mvebu_soc_descr * descr)53 static void __init mvebu_clk_gating_setup(
54 	struct device_node *np, const struct mvebu_soc_descr *descr)
55 {
56 	struct mvebu_gating_ctrl *ctrl;
57 	struct clk *clk;
58 	void __iomem *base;
59 	const char *default_parent = NULL;
60 	int n;
61 
62 	base = of_iomap(np, 0);
63 
64 	clk = of_clk_get(np, 0);
65 	if (!IS_ERR(clk)) {
66 		default_parent = __clk_get_name(clk);
67 		clk_put(clk);
68 	}
69 
70 	ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL);
71 	if (WARN_ON(!ctrl))
72 		return;
73 
74 	spin_lock_init(&ctrl->lock);
75 
76 	/*
77 	 * Count, allocate, and register clock gates
78 	 */
79 	for (n = 0; descr[n].name;)
80 		n++;
81 
82 	ctrl->num_gates = n;
83 	ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
84 			      GFP_KERNEL);
85 	if (WARN_ON(!ctrl->gates)) {
86 		kfree(ctrl);
87 		return;
88 	}
89 
90 	for (n = 0; n < ctrl->num_gates; n++) {
91 		u8 flags = 0;
92 		const char *parent =
93 			(descr[n].parent) ? descr[n].parent : default_parent;
94 
95 		/*
96 		 * On Armada 370, the DDR clock is a special case: it
97 		 * isn't taken by any driver, but should anyway be
98 		 * kept enabled, so we mark it as IGNORE_UNUSED for
99 		 * now.
100 		 */
101 		if (!strcmp(descr[n].name, "ddr"))
102 			flags |= CLK_IGNORE_UNUSED;
103 
104 		ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent,
105 				   flags, base, descr[n].bit_idx, 0, &ctrl->lock);
106 		WARN_ON(IS_ERR(ctrl->gates[n]));
107 	}
108 	of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl);
109 }
110 
111 /*
112  * SoC specific clock gating control
113  */
114 
115 #ifdef CONFIG_MACH_ARMADA_370
116 static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = {
117 	{ "audio", NULL, 0 },
118 	{ "pex0_en", NULL, 1 },
119 	{ "pex1_en", NULL,  2 },
120 	{ "ge1", NULL, 3 },
121 	{ "ge0", NULL, 4 },
122 	{ "pex0", NULL, 5 },
123 	{ "pex1", NULL, 9 },
124 	{ "sata0", NULL, 15 },
125 	{ "sdio", NULL, 17 },
126 	{ "tdm", NULL, 25 },
127 	{ "ddr", NULL, 28 },
128 	{ "sata1", NULL, 30 },
129 	{ }
130 };
131 #endif
132 
133 #ifdef CONFIG_MACH_ARMADA_XP
134 static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
135 	{ "audio", NULL, 0 },
136 	{ "ge3", NULL, 1 },
137 	{ "ge2", NULL,  2 },
138 	{ "ge1", NULL, 3 },
139 	{ "ge0", NULL, 4 },
140 	{ "pex0", NULL, 5 },
141 	{ "pex1", NULL, 6 },
142 	{ "pex2", NULL, 7 },
143 	{ "pex3", NULL, 8 },
144 	{ "bp", NULL, 13 },
145 	{ "sata0lnk", NULL, 14 },
146 	{ "sata0", "sata0lnk", 15 },
147 	{ "lcd", NULL, 16 },
148 	{ "sdio", NULL, 17 },
149 	{ "usb0", NULL, 18 },
150 	{ "usb1", NULL, 19 },
151 	{ "usb2", NULL, 20 },
152 	{ "xor0", NULL, 22 },
153 	{ "crypto", NULL, 23 },
154 	{ "tdm", NULL, 25 },
155 	{ "xor1", NULL, 28 },
156 	{ "sata1lnk", NULL, 29 },
157 	{ "sata1", "sata1lnk", 30 },
158 	{ }
159 };
160 #endif
161 
162 #ifdef CONFIG_ARCH_DOVE
163 static const struct mvebu_soc_descr __initconst dove_gating_descr[] = {
164 	{ "usb0", NULL, 0 },
165 	{ "usb1", NULL, 1 },
166 	{ "ge", "gephy", 2 },
167 	{ "sata", NULL, 3 },
168 	{ "pex0", NULL, 4 },
169 	{ "pex1", NULL, 5 },
170 	{ "sdio0", NULL, 8 },
171 	{ "sdio1", NULL, 9 },
172 	{ "nand", NULL, 10 },
173 	{ "camera", NULL, 11 },
174 	{ "i2s0", NULL, 12 },
175 	{ "i2s1", NULL, 13 },
176 	{ "crypto", NULL, 15 },
177 	{ "ac97", NULL, 21 },
178 	{ "pdma", NULL, 22 },
179 	{ "xor0", NULL, 23 },
180 	{ "xor1", NULL, 24 },
181 	{ "gephy", NULL, 30 },
182 	{ }
183 };
184 #endif
185 
186 #ifdef CONFIG_ARCH_KIRKWOOD
187 static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = {
188 	{ "ge0", NULL, 0 },
189 	{ "pex0", NULL, 2 },
190 	{ "usb0", NULL, 3 },
191 	{ "sdio", NULL, 4 },
192 	{ "tsu", NULL, 5 },
193 	{ "runit", NULL, 7 },
194 	{ "xor0", NULL, 8 },
195 	{ "audio", NULL, 9 },
196 	{ "powersave", "cpuclk", 11 },
197 	{ "sata0", NULL, 14 },
198 	{ "sata1", NULL, 15 },
199 	{ "xor1", NULL, 16 },
200 	{ "crypto", NULL, 17 },
201 	{ "pex1", NULL, 18 },
202 	{ "ge1", NULL, 19 },
203 	{ "tdm", NULL, 20 },
204 	{ }
205 };
206 #endif
207 
208 static const __initdata struct of_device_id clk_gating_match[] = {
209 #ifdef CONFIG_MACH_ARMADA_370
210 	{
211 		.compatible = "marvell,armada-370-gating-clock",
212 		.data = armada_370_gating_descr,
213 	},
214 #endif
215 
216 #ifdef CONFIG_MACH_ARMADA_XP
217 	{
218 		.compatible = "marvell,armada-xp-gating-clock",
219 		.data = armada_xp_gating_descr,
220 	},
221 #endif
222 
223 #ifdef CONFIG_ARCH_DOVE
224 	{
225 		.compatible = "marvell,dove-gating-clock",
226 		.data = dove_gating_descr,
227 	},
228 #endif
229 
230 #ifdef CONFIG_ARCH_KIRKWOOD
231 	{
232 		.compatible = "marvell,kirkwood-gating-clock",
233 		.data = kirkwood_gating_descr,
234 	},
235 #endif
236 
237 	{ }
238 };
239 
mvebu_gating_clk_init(void)240 void __init mvebu_gating_clk_init(void)
241 {
242 	struct device_node *np;
243 
244 	for_each_matching_node(np, clk_gating_match) {
245 		const struct of_device_id *match =
246 			of_match_node(clk_gating_match, np);
247 		mvebu_clk_gating_setup(np,
248 		       (const struct mvebu_soc_descr *)match->data);
249 	}
250 }
251