Skip to content

Commit f962731

Browse files
rajanv-xilinxMichal Simek
authored andcommitted
firmware: xilinx: Add clock APIs
Add clock APIs to control clocks through firmware interface. Signed-off-by: Rajan Vaja <[email protected]> Signed-off-by: Jolly Shah <[email protected]> Signed-off-by: Michal Simek <[email protected]>
1 parent 59ecdd7 commit f962731

File tree

2 files changed

+214
-2
lines changed

2 files changed

+214
-2
lines changed

drivers/firmware/xilinx/zynqmp.c

Lines changed: 184 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,195 @@ static int get_set_conduit_method(struct device_node *np)
250250
*/
251251
static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
252252
{
253-
return zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
254-
qdata.arg2, qdata.arg3, out);
253+
int ret;
254+
255+
ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
256+
qdata.arg2, qdata.arg3, out);
257+
258+
/*
259+
* For clock name query, all bytes in SMC response are clock name
260+
* characters and return code is always success. For invalid clocks,
261+
* clock name bytes would be zeros.
262+
*/
263+
return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
264+
}
265+
266+
/**
267+
* zynqmp_pm_clock_enable() - Enable the clock for given id
268+
* @clock_id: ID of the clock to be enabled
269+
*
270+
* This function is used by master to enable the clock
271+
* including peripherals and PLL clocks.
272+
*
273+
* Return: Returns status, either success or error+reason
274+
*/
275+
static int zynqmp_pm_clock_enable(u32 clock_id)
276+
{
277+
return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
278+
}
279+
280+
/**
281+
* zynqmp_pm_clock_disable() - Disable the clock for given id
282+
* @clock_id: ID of the clock to be disable
283+
*
284+
* This function is used by master to disable the clock
285+
* including peripherals and PLL clocks.
286+
*
287+
* Return: Returns status, either success or error+reason
288+
*/
289+
static int zynqmp_pm_clock_disable(u32 clock_id)
290+
{
291+
return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
292+
}
293+
294+
/**
295+
* zynqmp_pm_clock_getstate() - Get the clock state for given id
296+
* @clock_id: ID of the clock to be queried
297+
* @state: 1/0 (Enabled/Disabled)
298+
*
299+
* This function is used by master to get the state of clock
300+
* including peripherals and PLL clocks.
301+
*
302+
* Return: Returns status, either success or error+reason
303+
*/
304+
static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
305+
{
306+
u32 ret_payload[PAYLOAD_ARG_CNT];
307+
int ret;
308+
309+
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
310+
0, 0, ret_payload);
311+
*state = ret_payload[1];
312+
313+
return ret;
314+
}
315+
316+
/**
317+
* zynqmp_pm_clock_setdivider() - Set the clock divider for given id
318+
* @clock_id: ID of the clock
319+
* @divider: divider value
320+
*
321+
* This function is used by master to set divider for any clock
322+
* to achieve desired rate.
323+
*
324+
* Return: Returns status, either success or error+reason
325+
*/
326+
static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
327+
{
328+
return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
329+
0, 0, NULL);
330+
}
331+
332+
/**
333+
* zynqmp_pm_clock_getdivider() - Get the clock divider for given id
334+
* @clock_id: ID of the clock
335+
* @divider: divider value
336+
*
337+
* This function is used by master to get divider values
338+
* for any clock.
339+
*
340+
* Return: Returns status, either success or error+reason
341+
*/
342+
static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
343+
{
344+
u32 ret_payload[PAYLOAD_ARG_CNT];
345+
int ret;
346+
347+
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
348+
0, 0, ret_payload);
349+
*divider = ret_payload[1];
350+
351+
return ret;
352+
}
353+
354+
/**
355+
* zynqmp_pm_clock_setrate() - Set the clock rate for given id
356+
* @clock_id: ID of the clock
357+
* @rate: rate value in hz
358+
*
359+
* This function is used by master to set rate for any clock.
360+
*
361+
* Return: Returns status, either success or error+reason
362+
*/
363+
static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
364+
{
365+
return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
366+
lower_32_bits(rate),
367+
upper_32_bits(rate),
368+
0, NULL);
369+
}
370+
371+
/**
372+
* zynqmp_pm_clock_getrate() - Get the clock rate for given id
373+
* @clock_id: ID of the clock
374+
* @rate: rate value in hz
375+
*
376+
* This function is used by master to get rate
377+
* for any clock.
378+
*
379+
* Return: Returns status, either success or error+reason
380+
*/
381+
static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
382+
{
383+
u32 ret_payload[PAYLOAD_ARG_CNT];
384+
int ret;
385+
386+
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
387+
0, 0, ret_payload);
388+
*rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
389+
390+
return ret;
391+
}
392+
393+
/**
394+
* zynqmp_pm_clock_setparent() - Set the clock parent for given id
395+
* @clock_id: ID of the clock
396+
* @parent_id: parent id
397+
*
398+
* This function is used by master to set parent for any clock.
399+
*
400+
* Return: Returns status, either success or error+reason
401+
*/
402+
static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
403+
{
404+
return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
405+
parent_id, 0, 0, NULL);
406+
}
407+
408+
/**
409+
* zynqmp_pm_clock_getparent() - Get the clock parent for given id
410+
* @clock_id: ID of the clock
411+
* @parent_id: parent id
412+
*
413+
* This function is used by master to get parent index
414+
* for any clock.
415+
*
416+
* Return: Returns status, either success or error+reason
417+
*/
418+
static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
419+
{
420+
u32 ret_payload[PAYLOAD_ARG_CNT];
421+
int ret;
422+
423+
ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
424+
0, 0, ret_payload);
425+
*parent_id = ret_payload[1];
426+
427+
return ret;
255428
}
256429

257430
static const struct zynqmp_eemi_ops eemi_ops = {
258431
.get_api_version = zynqmp_pm_get_api_version,
259432
.query_data = zynqmp_pm_query_data,
433+
.clock_enable = zynqmp_pm_clock_enable,
434+
.clock_disable = zynqmp_pm_clock_disable,
435+
.clock_getstate = zynqmp_pm_clock_getstate,
436+
.clock_setdivider = zynqmp_pm_clock_setdivider,
437+
.clock_getdivider = zynqmp_pm_clock_getdivider,
438+
.clock_setrate = zynqmp_pm_clock_setrate,
439+
.clock_getrate = zynqmp_pm_clock_getrate,
440+
.clock_setparent = zynqmp_pm_clock_setparent,
441+
.clock_getparent = zynqmp_pm_clock_getparent,
260442
};
261443

262444
/**

include/linux/firmware/xlnx-zynqmp.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
enum pm_api_id {
3636
PM_GET_API_VERSION = 1,
3737
PM_QUERY_DATA = 35,
38+
PM_CLOCK_ENABLE,
39+
PM_CLOCK_DISABLE,
40+
PM_CLOCK_GETSTATE,
41+
PM_CLOCK_SETDIVIDER,
42+
PM_CLOCK_GETDIVIDER,
43+
PM_CLOCK_SETRATE,
44+
PM_CLOCK_GETRATE,
45+
PM_CLOCK_SETPARENT,
46+
PM_CLOCK_GETPARENT,
3847
};
3948

4049
/* PMU-FW return status codes */
@@ -48,8 +57,20 @@ enum pm_ret_status {
4857
XST_PM_ABORT_SUSPEND,
4958
};
5059

60+
enum pm_ioctl_id {
61+
IOCTL_SET_PLL_FRAC_MODE = 8,
62+
IOCTL_GET_PLL_FRAC_MODE,
63+
IOCTL_SET_PLL_FRAC_DATA,
64+
IOCTL_GET_PLL_FRAC_DATA,
65+
};
66+
5167
enum pm_query_id {
5268
PM_QID_INVALID,
69+
PM_QID_CLOCK_GET_NAME,
70+
PM_QID_CLOCK_GET_TOPOLOGY,
71+
PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
72+
PM_QID_CLOCK_GET_PARENTS,
73+
PM_QID_CLOCK_GET_ATTRIBUTES,
5374
};
5475

5576
/**
@@ -69,6 +90,15 @@ struct zynqmp_pm_query_data {
6990
struct zynqmp_eemi_ops {
7091
int (*get_api_version)(u32 *version);
7192
int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
93+
int (*clock_enable)(u32 clock_id);
94+
int (*clock_disable)(u32 clock_id);
95+
int (*clock_getstate)(u32 clock_id, u32 *state);
96+
int (*clock_setdivider)(u32 clock_id, u32 divider);
97+
int (*clock_getdivider)(u32 clock_id, u32 *divider);
98+
int (*clock_setrate)(u32 clock_id, u64 rate);
99+
int (*clock_getrate)(u32 clock_id, u64 *rate);
100+
int (*clock_setparent)(u32 clock_id, u32 parent_id);
101+
int (*clock_getparent)(u32 clock_id, u32 *parent_id);
72102
};
73103

74104
#if IS_REACHABLE(CONFIG_ARCH_ZYNQMP)

0 commit comments

Comments
 (0)