2 * Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED
3 * Copyright (C) 2015 Linaro Ltd.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/clkdev.h>
16 #include <linux/err.h>
19 #include <linux/cpu.h>
20 #include <linux/clk-provider.h>
21 #include <linux/spinlock.h>
22 #include <linux/module.h>
23 #include <linux/topology.h>
24 #include <linux/mailbox_client.h>
25 #include <linux/platform_device.h>
27 #include <soc/mb86s7x/scb_mhu.h>
29 #define to_crg_clk(p) container_of(p, struct crg_clk, hw)
30 #define to_clc_clk(p) container_of(p, struct cl_clk, hw)
32 struct mb86s7x_peri_clk
{
39 } __packed
__aligned(4);
49 u8 cntrlr
, domain
, port
;
52 static int crg_gate_control(struct clk_hw
*hw
, int en
)
54 struct crg_clk
*crgclk
= to_crg_clk(hw
);
55 struct mb86s7x_peri_clk cmd
;
58 cmd
.payload_size
= sizeof(cmd
);
59 cmd
.cntrlr
= crgclk
->cntrlr
;
60 cmd
.domain
= crgclk
->domain
;
61 cmd
.port
= crgclk
->port
;
64 /* Port is UngatedCLK */
66 return en
? 0 : -EINVAL
;
68 pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u En-%u}\n",
69 __func__
, __LINE__
, cmd
.cntrlr
,
70 cmd
.domain
, cmd
.port
, cmd
.en
);
72 ret
= mb86s7x_send_packet(CMD_PERI_CLOCK_GATE_SET_REQ
,
75 pr_err("%s:%d failed!\n", __func__
, __LINE__
);
79 pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u En-%u}\n",
80 __func__
, __LINE__
, cmd
.cntrlr
,
81 cmd
.domain
, cmd
.port
, cmd
.en
);
83 /* If the request was rejected */
92 static int crg_port_prepare(struct clk_hw
*hw
)
94 return crg_gate_control(hw
, 1);
97 static void crg_port_unprepare(struct clk_hw
*hw
)
99 crg_gate_control(hw
, 0);
103 crg_rate_control(struct clk_hw
*hw
, int set
, unsigned long *rate
)
105 struct crg_clk
*crgclk
= to_crg_clk(hw
);
106 struct mb86s7x_peri_clk cmd
;
109 cmd
.payload_size
= sizeof(cmd
);
110 cmd
.cntrlr
= crgclk
->cntrlr
;
111 cmd
.domain
= crgclk
->domain
;
112 cmd
.port
= crgclk
->port
;
113 cmd
.frequency
= *rate
;
116 code
= CMD_PERI_CLOCK_RATE_SET_REQ
;
117 pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
118 __func__
, __LINE__
, cmd
.cntrlr
,
119 cmd
.domain
, cmd
.port
, cmd
.frequency
);
121 code
= CMD_PERI_CLOCK_RATE_GET_REQ
;
122 pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-GET}\n",
123 __func__
, __LINE__
, cmd
.cntrlr
,
124 cmd
.domain
, cmd
.port
);
127 ret
= mb86s7x_send_packet(code
, &cmd
, sizeof(cmd
));
129 pr_err("%s:%d failed!\n", __func__
, __LINE__
);
134 pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
135 __func__
, __LINE__
, cmd
.cntrlr
,
136 cmd
.domain
, cmd
.port
, cmd
.frequency
);
138 pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-GOT %lluHz}\n",
139 __func__
, __LINE__
, cmd
.cntrlr
,
140 cmd
.domain
, cmd
.port
, cmd
.frequency
);
142 *rate
= cmd
.frequency
;
147 crg_port_recalc_rate(struct clk_hw
*hw
, unsigned long parent_rate
)
151 crg_rate_control(hw
, 0, &rate
);
157 crg_port_round_rate(struct clk_hw
*hw
,
158 unsigned long rate
, unsigned long *pr
)
164 crg_port_set_rate(struct clk_hw
*hw
,
165 unsigned long rate
, unsigned long parent_rate
)
167 return crg_rate_control(hw
, 1, &rate
);
170 const struct clk_ops crg_port_ops
= {
171 .prepare
= crg_port_prepare
,
172 .unprepare
= crg_port_unprepare
,
173 .recalc_rate
= crg_port_recalc_rate
,
174 .round_rate
= crg_port_round_rate
,
175 .set_rate
= crg_port_set_rate
,
178 struct mb86s70_crg11
{
179 struct mutex lock
; /* protects CLK populating and searching */
182 static struct clk
*crg11_get(struct of_phandle_args
*clkspec
, void *data
)
184 struct mb86s70_crg11
*crg11
= data
;
185 struct clk_init_data init
;
186 u32 cntrlr
, domain
, port
;
187 struct crg_clk
*crgclk
;
191 if (clkspec
->args_count
!= 3)
192 return ERR_PTR(-EINVAL
);
194 cntrlr
= clkspec
->args
[0];
195 domain
= clkspec
->args
[1];
196 port
= clkspec
->args
[2];
199 snprintf(clkp
, 20, "UngatedCLK%d_%X", cntrlr
, domain
);
201 snprintf(clkp
, 20, "CLK%d_%X_%d", cntrlr
, domain
, port
);
203 mutex_lock(&crg11
->lock
);
205 clk
= __clk_lookup(clkp
);
207 mutex_unlock(&crg11
->lock
);
211 crgclk
= kzalloc(sizeof(*crgclk
), GFP_KERNEL
);
213 mutex_unlock(&crg11
->lock
);
214 return ERR_PTR(-ENOMEM
);
218 init
.num_parents
= 0;
219 init
.ops
= &crg_port_ops
;
221 crgclk
->hw
.init
= &init
;
222 crgclk
->cntrlr
= cntrlr
;
223 crgclk
->domain
= domain
;
225 clk
= clk_register(NULL
, &crgclk
->hw
);
227 pr_err("%s:%d Error!\n", __func__
, __LINE__
);
229 pr_debug("Registered %s\n", clkp
);
231 clk_register_clkdev(clk
, clkp
, NULL
);
232 mutex_unlock(&crg11
->lock
);
236 static void __init
crg_port_init(struct device_node
*node
)
238 struct mb86s70_crg11
*crg11
;
240 crg11
= kzalloc(sizeof(*crg11
), GFP_KERNEL
);
244 mutex_init(&crg11
->lock
);
246 of_clk_add_provider(node
, crg11_get
, crg11
);
248 CLK_OF_DECLARE(crg11_gate
, "fujitsu,mb86s70-crg11", crg_port_init
);
255 struct mb86s7x_cpu_freq
{
263 static void mhu_cluster_rate(struct clk_hw
*hw
, unsigned long *rate
, int get
)
265 struct cl_clk
*clc
= to_clc_clk(hw
);
266 struct mb86s7x_cpu_freq cmd
;
269 cmd
.payload_size
= sizeof(cmd
);
270 cmd
.cluster_class
= 0;
271 cmd
.cluster_id
= clc
->cluster
;
273 cmd
.frequency
= *rate
;
276 code
= CMD_CPU_CLOCK_RATE_GET_REQ
;
278 code
= CMD_CPU_CLOCK_RATE_SET_REQ
;
280 pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
281 __func__
, __LINE__
, cmd
.cluster_class
,
282 cmd
.cluster_id
, cmd
.cpu_id
, cmd
.frequency
);
284 ret
= mb86s7x_send_packet(code
, &cmd
, sizeof(cmd
));
286 pr_err("%s:%d failed!\n", __func__
, __LINE__
);
290 pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
291 __func__
, __LINE__
, cmd
.cluster_class
,
292 cmd
.cluster_id
, cmd
.cpu_id
, cmd
.frequency
);
294 *rate
= cmd
.frequency
;
298 clc_recalc_rate(struct clk_hw
*hw
, unsigned long unused
)
302 mhu_cluster_rate(hw
, &rate
, 1);
307 clc_round_rate(struct clk_hw
*hw
, unsigned long rate
,
308 unsigned long *unused
)
314 clc_set_rate(struct clk_hw
*hw
, unsigned long rate
,
315 unsigned long unused
)
317 unsigned long res
= rate
;
319 mhu_cluster_rate(hw
, &res
, 0);
321 return (res
== rate
) ? 0 : -EINVAL
;
324 static struct clk_ops clk_clc_ops
= {
325 .recalc_rate
= clc_recalc_rate
,
326 .round_rate
= clc_round_rate
,
327 .set_rate
= clc_set_rate
,
330 static struct clk_hw
*mb86s7x_clclk_register(struct device
*cpu_dev
)
332 struct clk_init_data init
;
336 clc
= kzalloc(sizeof(*clc
), GFP_KERNEL
);
338 return ERR_PTR(-ENOMEM
);
340 clc
->hw
.init
= &init
;
341 clc
->cluster
= topology_physical_package_id(cpu_dev
->id
);
343 init
.name
= dev_name(cpu_dev
);
344 init
.ops
= &clk_clc_ops
;
345 init
.flags
= CLK_GET_RATE_NOCACHE
;
346 init
.num_parents
= 0;
348 ret
= devm_clk_hw_register(cpu_dev
, &clc
->hw
);
354 static int mb86s7x_clclk_of_init(void)
356 int cpu
, ret
= -ENODEV
;
357 struct device_node
*np
;
360 np
= of_find_compatible_node(NULL
, NULL
, "fujitsu,mb86s70-scb-1.0");
361 if (!np
|| !of_device_is_available(np
))
364 for_each_possible_cpu(cpu
) {
365 struct device
*cpu_dev
= get_cpu_device(cpu
);
368 pr_err("failed to get cpu%d device\n", cpu
);
372 hw
= mb86s7x_clclk_register(cpu_dev
);
374 pr_err("failed to register cpu%d clock\n", cpu
);
377 if (clk_hw_register_clkdev(hw
, NULL
, dev_name(cpu_dev
))) {
378 pr_err("failed to register cpu%d clock lookup\n", cpu
);
381 pr_debug("registered clk for %s\n", dev_name(cpu_dev
));
385 platform_device_register_simple("arm-bL-cpufreq-dt", -1, NULL
, 0);
390 module_init(mb86s7x_clclk_of_init
);